GIS算法-两线段是否相交
算法1:快速排斥与矢量跨立
- 快速排斥。以线段为对角线作正矩形,判断两矩形是否相交。如两矩形交进行矢量跨立,排除两线段共线且只有一个交点情况。
- 矢量跨立。如两线段相交,必然互相跨立。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//线段相交 跨立法
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;
}
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:参数方程法
建立线段参数方程,通过判断参数情况得到线段是否相交,可以得到交点。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//线段相交 参数方程法
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;
}
}
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;
}
}
效果图: