最近项目开发一个地图的服务端程序,需要 计算点,线,面与矩形是否有相交,
起初遇到这个问题脑袋里很混乱不知如何下手,静下心来仔细考虑,其实问题也不复杂.分三个步骤可以解决此问题
1.判断组成点,线,面的点元素是否在矩形内
假设矩形的近点:P1 远点:P2,要判断一个新的坐标点Px是否在矩形内,只要判断Px的坐标和P1,P2的大小就可以了代码如下
点是否在矩形内
/// <summary> /// 点是否与矩形有相交 /// </summary> /// <param name="cPoint">当前点</param> /// <param name="p1">矩形近点</param> /// <param name="p3">矩形远点</param> /// <returns></returns> public static bool PointCheck(MapPoint cPoint, MapPoint p1, MapPoint p3) { bool blResult = (cPoint.X >= p1.X && cPoint.X <= p3.X) && (cPoint.Y >= p1.Y && cPoint.Y <= p3.Y); return blResult; }
2.如果是线段还需要在判断线段与矩形的四条边是否有相交
需要判断做成多段线,多边形 的线段 与组成矩形的四条线段是否相交(几何原理:如果两条线段相交,那么一条线段的两个端点必定在另一条线段的两侧)
线段与矩形的四条边是否有相交
/// <summary> /// 检查线段与矩形的四条边是否有相交 /// </summary> /// <param name="points"></param> /// <param name="p1"></param> /// <param name="p2"></param> /// <param name="p3"></param> /// <param name="p4"></param> /// <returns></returns> protected bool Check4Line(List<MapPoint> points, MapPoint p1, MapPoint p2, MapPoint p3, MapPoint p4) { bool blResult = false; if (points == null | (points != null && points.Count < 2)) { return false; } for (int i = 0; i < points.Count - 1; i++) { var ptCurr = points[i]; var ptNext = points[i + 1]; blResult = CommMeth.Intersect(ptCurr, ptNext, p1, p2);//与矩形的第1条线段相比较 if (blResult) break; blResult = CommMeth.Intersect(ptCurr, ptNext, p2, p3);//与矩形的第2条线段相比较 if (blResult) break; blResult = CommMeth.Intersect(ptCurr, ptNext, p3, p4);//与矩形的第3条线段相比较 if (blResult) break; blResult = CommMeth.Intersect(ptCurr, ptNext, p4, p1);//与矩形的第3条线段相比较 if (blResult) break; } return blResult; }
两条线段是否相交
/// <summary> /// 两条线段是否相交 /// </summary> /// <param name="p1">第1条线段起点</param> /// <param name="p2">第1条线段终点</param> /// <param name="p3">第2条线段起点</param> /// <param name="p4">第2条线段终点点</param> /// <returns></returns> public static bool Intersect(MapPoint p1, MapPoint p2, MapPoint p3, MapPoint p4) { double x1 = p1.X; double y1 = p1.Y; double x2 = p2.X; double y2 = p2.Y; double x3 = p3.X; double y3 = p3.Y; double x4 = p4.X; double y4 = p4.Y; //依据:两条线段不相交,必定是存在其中一条线段的两端点在在另一条线段所在直线的同側.所以要分别考虑两种情况. if (DirectionV3(x1, y1, x2, y2, x3, y3) * DirectionV3(x1, y1, x2, y2, x4, y4) > 0)//一条线段的两点全在另一条线段的同一側 return false; if (DirectionV3(x3, y3, x4, y4, x1, y1) * DirectionV3(x3, y3, x4, y4, x2, y2) > 0)// return false; return true; } private static double DirectionV3(double x1, double y1, double x2, double y2, double x3, double y3) { //判断点在直线的上或下及左或右側.具体是采用点斜式求出一条线段所在直线的方程,然后将点代如求值进行判断 参照网站:计算几何算法概览 return x1 * y3 + x2 * y1 + x3 * y2 - x1 * y2 - x2 * y3 - x3 * y1; }
3.最后如果是面(多边形)还需要判断多边形是否全包括了矩形(即矩形的四个点,需要在多边形内)
在经过1,2两个步骤后,其实只需要判断矩形的其中一个点是否在多边形内即可(不用判断矩形的四个点)
点是否在多边形内
public static bool PointInPolygon(MapPoint point, MapPoint[] _vertices) { var j = _vertices.Length - 1; var oddNodes = false; for (var i = 0; i < _vertices.Length; i++) { if (_vertices[i].Y < point.Y && _vertices[j].Y >= point.Y || _vertices[j].Y < point.Y && _vertices[i].Y >= point.Y) { if (_vertices[i].X + (point.Y - _vertices[i].Y) / (_vertices[j].Y - _vertices[i].Y) * (_vertices[j].X - _vertices[i].X) < point.X) { oddNodes = !oddNodes; } } j = i; } return oddNodes; }