我最近正在开发一个项目,该项目有一个算法来判断一个点是否在一个区域内。
该区域如下:
{"state": "Washington", "border": [[-122.402015, 48.225216], [-117.032049, 48.999931], [-116.919132, 45.995175], [-124.079107, 46.267259], [-124.717175, 48.377557], [-122.92315, 47.047963], [-122.402015, 48.225216]]}
如果区域是矩形,则很容易。但是,该地区是不规则的。我的想法之一是检查一个点是否在该区域的每一行的“内部”侧。但是,表现并不好。有什么想法吗?
答案 0 :(得分:8)
首先,非常有趣的问题!!虽然这可能是一个重复的问题,但我仍然会发布另一个与该帖子不同的可行答案来鼓励这个新人。
这个想法是使用角度之和来决定目标是在内部还是外部。如果目标位于区域内,则目标和每两个边界点形成的角度之和将为360.如果目标位于外部,则总和将不是360.角度具有方向。如果角度向后,角度是负角度。这就像计算winding number。
一样提供的输入数据[[-122.402015, 48.225216], [-117.032049, 48.999931], [-116.919132, 45.995175], [-124.079107, 46.267259], [-124.717175, 48.377557], [-122.92315, 47.047963], [-122.402015, 48.225216]]
是顺时针(您可以查看谷歌地图)。因此,我的代码假设正角度是顺时针角度。
以下是实现它的python代码。
def isInside(self, border, target):
degree = 0
for i in range(len(border) - 1):
a = border[i]
b = border[i + 1]
# calculate distance of vector
A = getDistance(a[0], a[1], b[0], b[1]);
B = getDistance(target[0], target[1], a[0], a[1])
C = getDistance(target[0], target[1], b[0], b[1])
# calculate direction of vector
ta_x = a[0] - target[0]
ta_y = a[1] - target[1]
tb_x = b[0] - target[0]
tb_y = b[1] - target[1]
cross = tb_y * ta_x - tb_x * ta_y
clockwise = cross < 0
# calculate sum of angles
if(clockwise):
degree = degree + math.degrees(math.acos((B * B + C * C - A * A) / (2.0 * B * C)))
else:
degree = degree - math.degrees(math.acos((B * B + C * C - A * A) / (2.0 * B * C)))
if(abs(round(degree) - 360) <= 3):
return True
return False
答案 1 :(得分:0)
这是一个伪代码:
var point = [x,y] // Point to evaluate
int i, j, c = 0
int size = border.count
for (i = 0, j = size-1; i < size; j = i++) {
var ii = border[i]
var jj = border[j]
if ( ((ii.[1] > point.[1]) != (jj.[1] > point.[1])) &&
(point.[0] < (jj.[0]-ii.[0]) * (point.[1]-ii.[1]) / (jj.[1]-ii.[1]) + ii.[0])) {
c = !c
}
}
return c
答案 2 :(得分:0)
听起来像修改后的convex hull算法的一个很好的用例。
O(nlog(n))
),如果该点被选为凸包的一部分,则它不再位于“区域”内 - (即构成凸包的点不是最终答案的一部分。)