主要是用在地图上判断
网上看到主要有两种方式
1.PNPoly 算法
def IsPtInPoly(aLon, aLat, pointList):
'''
:param aLon: double 经度
:param aLat: double 纬度
:param pointList: list [(lon, lat)...] 多边形点的顺序需根据顺时针或逆时针,不能乱
'''
iSum = 0
iCount = len(pointList)
if (iCount < 3):
return False
for i in range(iCount):
pLon1 = pointList[i][0]
pLat1 = pointList[i][1]
if (i == iCount - 1):
pLon2 = pointList[0][0]
pLat2 = pointList[0][1]
else:
pLon2 = pointList[i + 1][0]
pLat2 = pointList[i + 1][1]
if ((aLat >= pLat1) and (aLat < pLat2)) or ((aLat >= pLat2) and (aLat < pLat1)):
if (abs(pLat1 - pLat2) > 0):
pLon = pLon1 - ((pLon1 - pLon2) * (pLat1 - aLat)) / (pLat1 - pLat2)
if (pLon < aLon):
iSum += 1
if (iSum % 2 != 0):
return True
else:
return False
2.射线法
输入的是墨卡托坐标
# -*- coding: utf-8 -*-
"""
@Description: 几何计算工具类
@Author:
@Date: 2020-05-27 17:10
"""
from typing import Tuple
class Coord:
"""
坐标类
"""
x, y = 0, 0
def __init__(self, x: int, y: int):
self.x = x
self.y = y
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def __hash__(self):
return hash(self.x + self.y)
def __str__(self):
return str(self.x) + ',' + str(self.y)
def __lt__(self, other):
return (self.x + self.y) < (other.x + other.y)
class Section:
"""
线段
"""
def __init__(self, x1, y1, x2, y2):
self.x1 = x1
self.x2 = x2
self.y1 = y1
self.y2 = y2
def cross_point(section1: Section, section2: Section) -> Tuple[bool, int or None, int or None]:
"""
计算线段交点
Args:
section1: 线段1
section2: 线段2
Returns:
交点坐标
"""
# ab cd 两条线段求交点坐标
area_abc = (section1.x1 - section2.x1) * (section1.y2 - section2.y1) - \
(section1.y1 - section2.y1) * (section1.x2 - section2.x1)
area_abd = (section1.x1 - section2.x2) * (section1.y2 - section2.y2) - \
(section1.y1 - section2.y2) * (section1.x2 - section2.x2)
if (area_abc * area_abd) >= 0:
return False, None, None
area_cda = (section2.x1 - section1.x1) * (section2.y2 - section1.y1) - (section2.y1 - section1.y1) * (
section2.x2 - section1.x1)
area_cdb = area_cda + area_abc - area_abd
if (area_cda * area_cdb) >= 0:
return False, None, None
# 计算交点坐标
tmp = area_cda / (area_abd - area_abc)
dx = tmp * (section1.x2 - section1.x1)
dy = tmp * (section1.y2 - section1.y1)
return True, section1.x1 + dx, section1.y1 + dy
def is_in_polygon(pt: tuple, rings: list) -> bool:
"""
判断点在多边形内,向右射线法
Args:
pt: 点
rings: 多边形点集
Returns:
点是否在多边形内
"""
count = 0
for i in range(len(rings)):
prev = i + 1
if prev == len(rings):
prev = 0
r1 = rings[i]
r2 = rings[prev]
# 向右射线, 线段至少有一个点在判断点的右侧
if ((r1.y >= pt[1] >= r2.y) and (r1.x > pt[0] or r2.x > pt[0])) or (
(r2.y >= pt[1] >= r1.y) and (r1.x > pt[0] or r2.x > pt[0])):
# 向右射线共线
if cross_point(Section(r1.x, r1.y, r2.x, r2.y), Section(pt[0], pt[1], pt[0] + 10000, pt[1]))[0]:
count += 1
elif r1.y == pt[1]:
count += 1
return count % 2 == 1
为什么不用经纬度,是因为画图的时候,三维和二维直线有误差,所以在计算的时候用二维坐标