class Point: lng = '' lat = '' def __init__(self, lng, lat): self.lng = lng self.lat = lat # 求外包矩形 def get_polygon_bounds(points): length = len(points) top = down = left = right = points[0] for i in range(1, length): if points[i].lng > top.lng: top = points[i] elif points[i].lng < down.lng: down = points[i] else: pass if points[i].lat > right.lat: right = points[i] elif points[i].lat < left.lat: left = points[i] else: pass top_left = Point(top.lng, left.lat) top_right = Point(top.lng, right.lat) down_right = Point(down.lng, right.lat) down_left = Point(down.lng, left.lat) return [top_left, top_right, down_right, down_left] # 判斷點是否在外包矩形外 def is_point_in_rect(point, polygon_bounds): top_left = polygon_bounds[0] top_right = polygon_bounds[1] down_right = polygon_bounds[2] down_left = polygon_bounds[3] return (down_left.lng <= point.lng <= top_right.lng and top_left.lat <= point.lat <= down_right.lat) def is_point_in_polygon(point, points): polygon_bounds = get_polygon_bounds(points) if not is_point_in_rect(point, polygon_bounds): return False length = len(points) point_start = points[0] flag = False for i in range(1, length): point_end = points[i] # 點與多邊形頂點重合 if (point.lng == point_start.lng and point.lat == point_start.lat) or ( point.lng == point_end.lng and point.lat == point_end.lat): return True # 判斷線段兩端點是否在射線兩側 if (point_end.lat < point.lat <= point_start.lat) or ( point_end.lat >= point.lat > point_start.lat): # 線段上與射線 Y 坐標相同的點的 X 坐標 if point_end.lat == point_start.lat: x = (point_start.lng + point_end.lng) / 2 else: x = point_end.lng - (point_end.lat - point.lat) * ( point_end.lng - point_start.lng) / ( point_end.lat - point_start.lat) # 點在多邊形的邊上 if x == point.lng: return True # 射線穿過多邊形的邊界 if x > point.lng: flag = not flag else: pass else: pass point_start = point_end return flag def test(input_lng=116.732617, input_lat=39.722676): # polyline 是多個坐標點,形如 # ['116.732617,39.722676', '116.732617,39.722676', '116.732617,39.722676', # '116.732617,39.722676', '116.732617,39.722676'] polyline = [] points = [] for line in polyline: if line: try: lng, lat = line.split(',') points.append(Point(float(lng), float(lat))) except ValueError: pass if points: is_point_in_polygon(Point(float(input_lng), float(input_lat)), points)
缺點:慢
替代方法,類似的坐標的需求可以集成 https://geoalchemy-2.readthedocs.io/en/latest/