判断一个点是否在多边形区域内

主要是用在地图上判断

网上看到主要有两种方式

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

为什么不用经纬度,是因为画图的时候,三维和二维直线有误差,所以在计算的时候用二维坐标

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值