python射线法判断点是否在多边形内

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值