我需要用户能够在地图上绘制复杂的多边形,然后让应用程序检查给定的经度/纬度是否位于该多边形内。
我只能找到使用无法补偿地球曲率的简单x / y笛卡尔坐标系的算法。
用户在PC上绘制多边形,然后将这些点通过无线电传递到嵌入式设备,然后嵌入式设备需要检查给定的多边形是否位于其当前位置(从GPS获取)内。
因为这是针对嵌入式设备的,所以我无法使用庞大的库,而是需要算法来自己执行检查或执行很小的库。但是我似乎找不到任何这样的算法。
这是我在C#中为包含多边形列表的Polygon类编写的实现。它不考虑地球的曲率。相反,您需要在运行多边形之前将其预处理为较小的段。
该算法的性能非常好。即使对于具有数千条边的多边形,它在我的桌面上也需要大约一到两毫秒才能完成。
该代码已进行了相当多的优化,因此不像伪代码那样可读。
public bool Contains(GeoLocation location) { if (!Bounds.Contains(location)) return false; var lastPoint = _vertices[_vertices.Length - 1]; var isInside = false; var x = location.Longitude; foreach (var point in _vertices) { var x1 = lastPoint.Longitude; var x2 = point.Longitude; var dx = x2 - x1; if (Math.Abs(dx) > 180.0) { // we have, most likely, just jumped the dateline (could do further validation to this effect if needed). normalise the numbers. if (x > 0) { while (x1 < 0) x1 += 360; while (x2 < 0) x2 += 360; } else { while (x1 > 0) x1 -= 360; while (x2 > 0) x2 -= 360; } dx = x2 - x1; } if ((x1 <= x && x2 > x) || (x1 >= x && x2 < x)) { var grad = (point.Latitude - lastPoint.Latitude) / dx; var intersectAtLat = lastPoint.Latitude + ((x - x1) * grad); if (intersectAtLat > location.Latitude) isInside = !isInside; } lastPoint = point; } return isInside; }
基本思想是找到跨越测试点的“ x”位置的多边形的所有边缘。然后,您发现其中有多少与您的点上方延伸的垂直线相交。如果一个偶数横穿该点,那么您在多边形之外。如果上面有一个奇数,那么您就在里面。