问题描述
地图应用上,会经常判断用户是否在 xx 内(车站/商场/机场等),即判断一个点是否位于多边形区域内。
解决算法 - 射线法
思想: 从待判断的点向某一个方向引射线,计算和多边形交点的个数,如果个数是偶数或者0,则点在多边形外,如果是奇数,则在多边形内。
特殊情况:
- 射线经过顶点
- 点在边上
思路流程
1.首先获得数据集在横坐标和纵坐标的最大/小值,判断测试点是否在该四边形内。快速排除,提高效率。
1 2 3 4 5 6 7 8 9 10
| for i in range(1, pointLen): if points[i].lng > top.lng: top = points[i] elif points[i].lng < down.lng: down = points[i] if points[i].lat > right.lat: right = points[i] elif points[i].lat < left.lat: left = points[i]
|
2.接下来,取相邻的两个点与测试点,判断测试点是否为顶点
1 2 3
| # 点与多边形顶点重合 if (p.lng == p1.lng and p.lat == p1.lat) or \ (p.lng == p2.lng and p.lat == p2.lat):
|
3.判断测试点是否在两个相邻点的纵坐标范围之内,
1 2
| if (p2.lat < p.lat and p1.lat >= p.lat) or \ (p1.lat < p.lat and p2.lat >= p.lat)
|
4.判断测试点是否在相邻点的连线之间
5.判断测试点是否穿过线段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| if (p2.lat < p.lat and p1.lat >= p.lat) or \ (p1.lat < p.lat and p2.lat >= p.lat): print("on both sides") # 线段上与射线y坐标相同的点的x 的坐标 if p1.lat == p2.lat: x = (p1.lng + p2.lng)/2 else: x = p2.lng - (p2.lat - p.lat)*(p2.lng - p1.lng)/(p2.lat - p1.lat) # 点在多边形的边上 if x == p.lng: print("on the edge") inpolygonList.append(p) break # 射线穿过多边形的边界 if x > p.lng: print("throw") flag = not flag else: pass else: pass
|
完整代码
已上传至 github,欢迎下载。
https://github.com/pangrou/machine-learning/tree/master/python练习