zoukankan      html  css  js  c++  java
  • 判断一个点是否在多边形区域内部 / 判断一个给定位置是否位于某个城市内部

    目前实验中有个需求,即给定一个经纬度,判断其是否处于某个城市内部。本来是想使用Google Earth的接口,然而谷歌一直不通过我的开发者账号申请,遂自己写了一个程序来实现该功能。

    首先一个城市的轮廓必然是多边形的,那么得先获取该多边形的每个点的坐标,即城市多边形边界的表示。
    怎么找城市边界的坐标呢?如下图所示,下图来自于:Getting polygon boundaries of City in JSON from Google Maps API?
    在这里插入图片描述
    打开图中链接:https://nominatim.openstreetmap.org/
    然后按照图中指示的操作即可获取所需地区的边界,有txt和json两种格式的数据。

    下面以纽约为例。
    获取到的简化版的地图边界信息如下图所示(当然里面也有原始的边界信息,只是转折点比较多而已):
    在这里插入图片描述
    数据的表示形式如下图所示:
    在这里插入图片描述
    这里我将无关信息去掉,只保留坐标信息,下图为另一个区域的一个简单的表示。可以看出第一个和最后一个节点是同一个,即这里的点是沿顺时针顺序进行的。
    在这里插入图片描述
    数据获取与预处理完成,该开始写核心算法了。

    下面的核心问题就是:判断一个点是否在多边形区域内部

    随便百度一下,就会知道有一个行之有效的方法叫“射线法”,但是关于射线法的使用详细情况却往往未做说明,这其中还是有很多坑的。这篇文章将射线法中所要遇到的问题进行了全面的分析与解释,也提出了解决办法,因此我不多赘述。判断一个坐标点是否在不规则多边形内部的算法
    但是该文章并未给出代码实现,因此本文在最后基于上述所说的应用场景给出一个python实现版本的例子。

    # region1是一个list,若以上图为例,则其格式为:[[-74.035, 40.695],[-74.036, 40.694]...]
    # 该函数就是判断一个给定点是否在region1这个list所围成的多边形内
    # 需要注意:region1中第一个元素代表经度,第二个代表纬度,而函数实际输入中第一个是纬度,第二个是经度
    def isInRegion_1(lat, lon):
        count = 0
        lat = float(lat)
        lon = float(lon)
        for i in range(len(region_1)):
            # 如果是最后一个元素,那么必然是和第一个一样的,就啥也不干
            if i+1 == len(region_1):
                break
            # 如果不是最后一个元素,那么需要和后一个元素一起判断给定点是否在区域内
            la_1, lo_1 = region_1[i]
            la_2, lo_2 = region_1[i+1]
    
            la_1, lo_1, la_2, lo_2 = float(la_1), float(lo_1), float(la_2), float(lo_2)
    
            # 以纬度确定位置,沿纬度向右作射线,看交点个数
            if lat < min(la_1, la_2):
                continue
            if lat > max(la_1, la_2):
                continue
            # 如果和某一个共点那么直接返回true
            if (lat, lon) == (la_1, lo_1) or (lat, lon) == (la_2, lo_2):
                return True
            # 如果和两点共线
            if lat == la_1 == la_2:
                if lon < min(lo_1, lo_2) or lon > max(lo_1, lo_2):
                    return False
                else:
                    return True
            # 接下来只需考虑射线穿越的情况,该情况下的特殊情况是射线穿越顶点
            # 求交点的精度
            cross_lon = (lat - la_1) * (lo_2 - lo_1) / (la_2 - la_1) + lo_1
            # 因为需要考虑特殊情况的射线穿越顶点,因此只判断是不是穿越左边这个顶点
            if cross_lon == la_1:
                count += 1
            # 其他情况
            elif cross_lon > lon:
                count += 1
        if count%2 == 0:
            return False
        return True
    
  • 相关阅读:
    容器跨主机网络通信学习笔记(以Flannel为例)
    Kubernetes控制器Job和CronJob
    记一次使用Flannel插件排错历程
    Kubernetes控制器Deployment
    Kubernetes如何通过StatefulSet支持有状态应用?
    react18 来了,我 get 到...
    gojs 实用高级用法
    vuecli3 vue2 保留 webpack 支持 vite 成功实践
    calibre 报错 This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem. 解决
    unable to recognize "*.yaml": no matches for kind "RoleBinding" in version "rbac.authorization.k8s.io/v1beta1"
  • 原文地址:https://www.cnblogs.com/yinyoupoet/p/13287362.html
Copyright © 2011-2022 走看看