python3射线法判断点是否在多边形内
射线法
首先我们要先理解什么是射线法。射线法的意思是:在随机点上做一条平行于x轴的射线,方向是x轴正方向,看这条射线与多边形区域的交点个数,如果是偶数,那么这个随机点不在该区域内,如果是奇数,则这个点在该区域内。
核心算法
该方法的核心算法是:求得射线与边界的交点横坐标,如果横坐标大于随机点的横坐标,则将计数器+1,表示有一个交点。
如何求这个横坐标呢?
其实就是使用了三角形的一条定理,如下图所示:
(A,E)之间的距离L1,(A,B)之间的距离L2,(B,C)之间的距离L3均是已知的,我们需要求得的是(E,D)之间的距离Lx,即:Lx = L1*(L3/L2)
代码实现
废话不多说,直接上代码:
"""
判断点是否在多边形区域内
"""
polygon_dict = {"A": ((0.5, 1), (3, 1), (3, 0.5), (3.5, 0.5), (4, 3), (1, 3)), "B": ((5, 0), (8, 0), (8, 3), (6, 3)), "C": ((6, 3), (8, 3), (8, 7)),
"D": ((2.5, 5.5), (3.5, 5.5), (3.5, 6.5), (2.5, 6.5)), "E": ((2, 5), (4, 5), (4, 7), (2, 7))}
def isPointinPolygon(point):
result = [] # 多个区域
for key, polygon in polygon_dict.items():
# 判断是否在外包矩形内
lnglist = []
latlist = []
for i in range(len(polygon)):
lnglist.append(polygon[i][0])
latlist.append(polygon[i][1])
maxlng = max(lnglist)
minlng = min(lnglist)
maxlat = max(latlist)
minlat = min(latlist)
if (point[0] > maxlng or point[0] < minlng or point[1] > maxlat or point[1] < minlat):
# 不在外包矩形内的直接跳过
continue
count = 0
point1 = polygon[0]
for i in range(1, len(polygon) + 1):
if i == len(polygon):
i = 0
point2 = polygon[i]
# 点与多边形顶点重合
if (point[0] == point1[0] and point[1] == point1[1]) or (point[0] == point2[0] and point[1] == point2[1]):
print("在顶点上")
result.append(key)
point1 = point2
continue
# 判断线段两端点是否在射线两侧 不在肯定不相交 射线(-∞,lat)(lng,lat)
if (point1[1] < point[1] and point2[1] >= point[1]) or (point1[1] >= point[1] and point2[1] < point[1]):
point12lng = point2[0] - (point2[1] - point[1]) * ((point2[0] - point1[0]) / (point2[1] - point1[1]))
# 点在多边形边上
if (point12lng == point[0]):
print("点在多边形边上")
result.append(key)
point1 = point2
continue
if (point12lng > point[0]):
count += 1
elif point[1] <= min(point1[1], point2[1]):
# 点在线段的延长线上,或在下方
if point1[1] == point2[1]:
# 如果是一条平行于X轴的线
if point[1] == point1[1] and min(point1[0], point2[0]) <= point[0] <= max(point1[0], point2[0]):
# 点在线段上
result.append(key)
point1 = point2
continue
elif point[0] <= min(point1[0], point2[0]):
# 点在线段左侧
if point[1] < min(point1[1], point2[1]) or point[1] > max(point1[1], point2[1]):
# 点在线段下方或上方,不相交跳过
point1 = point2
continue
point12lng = point2[0] - (point2[1] - point[1]) * ((point2[0] - point1[0]) / (point2[1] - point1[1]))
elif point[0] >= min(point1[0], point2[0]):
# 点在线段的右侧,不相交跳过
point1 = point2
continue
else:
point12lng = point2[1] - (point2[1] - point[1]) * ((point2[1] - point[1]) / (point2[1] - point1[1]))
if (point12lng == point[1]):
print("点在多边形边上")
result.append(key)
point1 = point2
continue
if (point12lng > point[0]):
count += 1
point1 = point2
if count % 2 == 0:
continue
else:
result.append(key)
return list(set(result))
if __name__ == '__main__':
A, a, B, b, C, c, D, d, E = (2, 2), (1, 0.5), (6, 1), (5, 1), (7, 4), (6, 4), (3, 6), (3, 8), (3, 5.25)
# 特殊点:(3.25, 0.5) (1, 0.5) (2, 1) (7, 3) (8, 3)
res = isPointinPolygon((8, 3))
print(res)
if len(res) == 1:
print(f"目标点在{res[0]}区")
elif len(res) > 1:
print(f"目标点可能在{res[0]}区或{res[1]}区的交点上")
else:
print("目标点不在任何区域内")
希望对你有所帮助
参考文档:
http://www.cppcns.com/jiaoben/python/263893.html
https://blog.csdn.net/u011722133/article/details/52813374