GIS算法-两线段是否相交

算法1:快速排斥与矢量跨立

  • 快速排斥。以线段为对角线作正矩形,判断两矩形是否相交。如两矩形交进行矢量跨立,排除两线段共线且只有一个交点情况。
  • 矢量跨立。如两线段相交,必然互相跨立。

 

代码
 //线段相交 跨立法
        public static bool IsSegmentsIntersectWithCrossCheck(Segment segment1, Segment segment2)
        {
            Point P1 
= segment1.Vertex1.CenterPoint;
            Point P2 
= segment1.Vertex2.CenterPoint;

            Point Q1 
= segment2.Vertex1.CenterPoint;
            Point Q2 
= segment2.Vertex2.CenterPoint;


            
//快速排斥 

            
//Q1Q2对角线正矩形是否包含P1P2对角线正矩形
            if ((((P1.X >= Math.Min(Q1.X, Q2.X)) && (P1.X <= Math.Max(Q1.X, Q2.X))) && ((P1.Y >= Math.Min(Q1.Y, Q2.Y)) && (P1.Y <= Math.Max(Q1.Y, Q2.Y)))))
            {
                
return CrossCheck(segment1, segment2);
            }
            
//P1P2对角线正矩形是否包含Q1Q2对角线正矩形
            if ((((Q1.X >= Math.Min(P1.X, P2.X)) && (Q1.X <= Math.Max(P1.X, P2.X))) && ((Q1.Y >= Math.Min(P1.Y, P2.Y)) && (Q1.Y <= Math.Max(P1.Y, P2.Y)))))
            {
                
return CrossCheck(segment1, segment2);
            }

            
//两矩形重叠,内部形成一个新矩形情况
            if ((Math.Max(Q1.X, Q2.X) >= Math.Max(P1.X, P2.X))
                
&& (Math.Min(Q1.X, Q2.X) <= Math.Min(P1.X, P2.X))
                
&& (Math.Min(Q2.Y, Q1.Y) >= Math.Min(P1.Y, P2.Y))
                
&& (Math.Max(Q2.Y, Q1.Y) <= Math.Max(P1.Y, P2.Y)))
            {
                
return CrossCheck(segment1, segment2);
            }
            
if ((Math.Max(Q1.X, Q2.X) <= Math.Max(P1.X, P2.X))
                
&& (Math.Min(Q1.X, Q2.X) >= Math.Min(P1.X, P2.X))
                
&& (Math.Min(Q2.Y, Q1.Y) <= Math.Min(P1.Y, P2.Y))
                
&& (Math.Max(Q2.Y, Q1.Y) >= Math.Max(P1.Y, P2.Y)))
            {
                
return CrossCheck(segment1, segment2);
            }

            
//通过判断对角线端点是否落在对角线正矩形内,确定分别以两矢量为对角线的正矩形是否相交
            
//p1或p2落在Q1Q2矩形内
            if (((P1.X >= Math.Min(Q1.X, Q2.X)) && (P1.X <= Math.Max(Q1.X, Q2.X))) || ((P2.X >= Math.Min(Q1.X, Q2.X)) && (P2.X <= Math.Max(Q1.X, Q2.X))))
            {
                
if (((P1.Y >= Math.Min(Q1.Y, Q2.Y)) && (P1.Y <= Math.Max(Q1.Y, Q2.Y))) || ((P2.Y >= Math.Min(Q1.Y, Q2.Y)) && (P2.Y <= Math.Max(Q1.Y, Q2.Y))))
                {
                    
return CrossCheck(segment1, segment2);
                }
            }
            
//q1或q2落在p1p2矩形内
            if (((Q1.X >= Math.Min(P1.X, P2.X)) && (Q1.X <= Math.Max(P1.X, P2.X))) || ((Q2.X >= Math.Min(P1.X, P2.X)) && (Q2.X <= Math.Max(P1.X, P2.X))))
            {
                
if (((Q1.Y >= Math.Min(P1.Y, P2.Y)) && (Q1.Y <= Math.Max(P1.Y, P2.Y))) || ((Q2.Y >= Math.Min(P1.Y, P2.Y)) && (Q2.Y <= Math.Max(P1.Y, P2.Y))))
                {
                    
return CrossCheck(segment1, segment2);
                }
            }
            
//水平或垂直情况
            
//Q1Q2垂直
            if (Q1.X == Q2.X)
            {
                
if (((P1.Y >= Math.Min(Q1.Y, Q2.Y)) && (P1.Y <= Math.Max(Q1.Y, Q2.Y))) && ((P2.Y >= Math.Min(Q1.Y, Q2.Y)) && (P2.Y <= Math.Max(Q1.Y, Q2.Y)))
                    
&& ((Q1.X >= Math.Min(P1.X, P2.X)) && (Q1.X <= Math.Max(P1.X, P2.X))))
                {
                    
return CrossCheck(segment1, segment2);
                }
            }
            
//Q1Q2水平
            if (Q1.Y == Q2.Y)
            {
                
if (((P1.X >= Math.Min(Q1.X, Q2.X)) && (P1.X <= Math.Max(Q1.X, Q2.X))) && ((P2.X >= Math.Min(Q1.X, Q2.X)) && (P2.X <= Math.Max(Q1.X, Q2.X)))
                    
&& ((Q1.Y >= Math.Min(P1.Y, P2.Y)) && (Q1.Y <= Math.Max(P1.Y, P2.Y))))
                {
                    
return CrossCheck(segment1, segment2);
                }
            }

            
//Q1Q2垂直
            if (Q1.X == Q2.X)
            {
                
if (((P1.Y >= Math.Min(Q1.Y, Q2.Y)) && (P1.Y <= Math.Max(Q1.Y, Q2.Y))) && ((P2.Y >= Math.Min(Q1.Y, Q2.Y)) && (P2.Y <= Math.Max(Q1.Y, Q2.Y)))
                    
&& ((Q1.X >= Math.Min(P1.X, P2.X)) && (Q1.X <= Math.Max(P1.X, P2.X))))
                {
                    
return CrossCheck(segment1, segment2);
                }
            }
            
//P1P2水平
            if (P1.Y == P2.Y)
            {
                
if (((Q1.X >= Math.Min(P1.X, P2.X)) && (Q1.X <= Math.Max(P1.X, P2.X))) && ((Q2.X >= Math.Min(P1.X, P2.X)) && (Q2.X <= Math.Max(P1.X, P2.X)))
                    
&& ((P1.Y >= Math.Min(Q1.Y, Q2.Y)) && (P1.Y <= Math.Max(Q1.Y, Q2.Y))))
                {
                    
return CrossCheck(segment1, segment2);
                }
            }
            
//P1P2垂直
            if (P1.X == P2.X)
            {
                
if (((Q1.Y >= Math.Min(P1.Y, P2.Y)) && (Q1.Y <= Math.Max(P1.Y, P2.Y))) && ((Q2.Y >= Math.Min(P1.Y, P2.Y)) && (Q2.Y <= Math.Max(P1.Y, P2.Y)))
                    
&& ((P1.X >= Math.Min(Q1.X, Q2.X)) && (P1.X <= Math.Max(Q1.X, Q2.X))))
                {
                    
return CrossCheck(segment1, segment2);
                }
            }

            
return false;

        }
        
private static bool CrossCheck(Segment segment1, Segment segment2)
        {
            
bool pResult = false;


            Point P1 
= segment1.Vertex1.CenterPoint;
            Point P2 
= segment1.Vertex2.CenterPoint;

            Point Q1 
= segment2.Vertex1.CenterPoint;
            Point Q2 
= segment2.Vertex2.CenterPoint;

            
//跨立实验

            Vector P1P2 
= VectorUtility.GetVetcorPQ(P1, P2);
            Vector P1Q1 
= VectorUtility.GetVetcorPQ(P1, Q1);
            Vector P1Q2 
= VectorUtility.GetVetcorPQ(P1, Q2);

            
//Q1Q2是否跨立P1P2
            if (VectorUtility.GetVetcorsX(P1Q1, P1P2) * VectorUtility.GetVetcorsX(P1P2, P1Q2) >= 0)
            {

                Vector Q1Q2 
= VectorUtility.GetVetcorPQ(Q1, Q2);
                Vector Q1P1 
= VectorUtility.GetVetcorPQ(Q1, P1);
                Vector Q1P2 
= VectorUtility.GetVetcorPQ(Q1, P2);

                
//P1P2是否跨立Q1Q2
                if (VectorUtility.GetVetcorsX(Q1P1, Q1Q2) * VectorUtility.GetVetcorsX(Q1Q2, Q1P2) >= 0)
                {
                    pResult 
= true;
                }

            }
            
return pResult;
        }

算法2:参数方程法

       建立线段参数方程,通过判断参数情况得到线段是否相交,可以得到交点。

 

代码
//线段相交 参数方程法
        public static Vertex IsSegmentsIntersectWithPolynomial(Segment segment1, Segment segment2)
        {
            Point A 
= segment1.Vertex1.CenterPoint;
            Point B 
= segment1.Vertex2.CenterPoint;

            Point C 
= segment2.Vertex1.CenterPoint;
            Point D 
= segment2.Vertex2.CenterPoint;

            
double R = (double)((A.Y - C.Y) * (D.X - C.X) - (A.X - C.X) * (D.Y - C.Y)) / (double)((B.X - A.X) * (D.Y - C.Y) - (B.Y - A.Y) * (D.X - C.X));
            
double S = (double)((A.Y - C.Y) * (B.X - A.X) - (A.X - C.X) * (B.Y - A.Y)) / (double)((B.X - A.X) * (D.Y - C.Y) - (B.Y - A.Y) * (D.X - C.X));

            
if ((R >= 0 && R <= 1&& (S >= 0 && S <= 1))
            {
                Vertex pIntersectPoint 
= new Vertex();
                
int pIntersectPointX = (int)(A.X + R * (B.X - A.X));
                
int pIntersectPointY = (int)(A.Y + R * (B.Y - A.Y));
                pIntersectPoint.CenterPoint 
= new Point(pIntersectPointX, pIntersectPointY);

                
return pIntersectPoint;
            }
            
else
            {
                
return null;
            }

        }

效果图:

 

posted on 2010-05-30 21:52  LuGang  阅读(1141)  评论(0编辑  收藏  举报

导航