我需要用户能够在地图上画一个复杂的多边形,然后让应用程序检查给定的经度/纬度是否位于该多边形内。
我只能找到使用简单的x/y笛卡尔坐标系算法,这些算法没有考虑到地球的曲率。
用户在PC上绘制多边形,然后将点通过无线电传输到嵌入式设备,然后需要检查给定多边形是否位于当前位置(从GPS获取)。
由于这是针对嵌入式设备的,我不能使用庞大的库,而是需要自己执行检查的算法或者一个非常小的库。但是我似乎找不到这样的算法。
我需要用户能够在地图上画一个复杂的多边形,然后让应用程序检查给定的经度/纬度是否位于该多边形内。
我只能找到使用简单的x/y笛卡尔坐标系算法,这些算法没有考虑到地球的曲率。
用户在PC上绘制多边形,然后将点通过无线电传输到嵌入式设备,然后需要检查给定多边形是否位于当前位置(从GPS获取)。
由于这是针对嵌入式设备的,我不能使用庞大的库,而是需要自己执行检查的算法或者一个非常小的库。但是我似乎找不到这样的算法。
这是我用C#编写的多边形类的实现,其中包含了一个顶点列表。它没有考虑地球的曲率。相反,在运行此程序之前,您需要对多边形进行预处理,将其分成较小的线段。
该算法的性能非常好。即使对于具有数千个边的多边形,在我的台式机上也可以在大约一到两毫秒内完成。
这段代码已经被优化过了,因此不像伪代码那么易读。
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”位置的多边形的所有边。然后找出有多少条线交叉垂直于穿过您的点上方的竖直线。如果偶数条线穿过该点,则在多边形外部。如果奇数条线穿过该点,则在内部。