Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
支持大圆距离和多边形的快速python GIS库_Python_Performance_Gis_Polygon_Great Circle - Fatal编程技术网

支持大圆距离和多边形的快速python GIS库

支持大圆距离和多边形的快速python GIS库,python,performance,gis,polygon,great-circle,Python,Performance,Gis,Polygon,Great Circle,我正在寻找python的地理库。 我需要能够做到以下几点: 使用(非直线距离计算)获得两点之间的距离(以米为单位) 检查点是否位于多边形内 每秒执行1次和2次数千次 一开始,我看了这篇文章:并开始使用。 我遇到了两个问题: Geopy不支持多边形 geoPy的高CPU使用率(计算一个点和相对5000个点之间的距离需要大约140ms的CPU) 我一直在寻找,找到了。这看起来很有希望,因为geos使用的是符合要求的C代码,该代码应该更快,并且能够支持多边形。 问题在于geos/OGR执行的是线性距离

我正在寻找python的地理库。 我需要能够做到以下几点:

  • 使用(非直线距离计算)获得两点之间的距离(以米为单位)
  • 检查点是否位于多边形内
  • 每秒执行1次和2次数千次
  • 一开始,我看了这篇文章:并开始使用。 我遇到了两个问题:

  • Geopy不支持多边形
  • geoPy的高CPU使用率(计算一个点和相对5000个点之间的距离需要大约140ms的CPU)
  • 我一直在寻找,找到了。这看起来很有希望,因为geos使用的是符合要求的C代码,该代码应该更快,并且能够支持多边形。 问题在于geos/OGR执行的是线性距离计算,而不是球体。这消除了所有其他基于geos的模块(如GEODjango和shapely)。
    我是不是遗漏了什么?我不认为我是第一个使用python执行GIS计算并希望得到准确结果的人。

    更新

    现在继续完成该库中的其他576个函数,不包括已完成的两个多边形函数、已完成的三个球体距离算法和两个新算法,即angle_box_2d和angle_contains_ray_2d。另外,我切换到C版本,这样就不需要外部程序,简化了工作。把旧的C++版本放在目录OLDYC++中,所以它仍然存在。 经测试的性能与答案底部列出的相同


    更新2

    所以只是一个快速更新,我还没有完成整个库(我只完成了15%),但我已经添加了这些未经测试的函数,以备您需要,在github上,添加到多边形和球体距离算法中的旧点

    angle_box_2d
    angle_contains_ray_2d
    angle_deg_2d
    angle_half_2d # MLM: double *
    angle_rad_2d
    angle_rad_3d
    angle_rad_nd
    angle_turn_2d
    anglei_deg_2d
    anglei_rad_2d
    annulus_area_2d
    annulus_sector_area_2d
    annulus_sector_centroid_2d # MLM: double *
    ball_unit_sample_2d # MLM: double *
    ball_unit_sample_3d # MLM: double *
    ball_unit_sample_nd # MLM; double *
    basis_map_3d #double *
    box_01_contains_point_2d
    box_01_contains_point_nd
    box_contains_point_2d
    box_contains_point_nd
    box_ray_int_2d
    box_segment_clip_2d
    circle_arc_point_near_2d
    circle_area_2d
    circle_dia2imp_2d
    circle_exp_contains_point_2d
    circle_exp2imp_2d
    circle_imp_contains_point_2d
    circle_imp_line_par_int_2d
    circle_imp_point_dist_2d
    circle_imp_point_dist_signed_2d
    circle_imp_point_near_2d
    circle_imp_points_2d # MlM: double *
    circle_imp_points_3d # MLM: double *
    circle_imp_points_arc_2d
    circle_imp_print_2d
    circle_imp_print_3d
    circle_imp2exp_2d
    circle_llr2imp_2d # MLM: double *
    circle_lune_area_2d
    circle_lune_centroid_2d # MLM; double *
    circle_pppr2imp_3d
    
    我上面提到的那些可能不起作用,其他的可能起作用,但再一次——多边形和球体距离肯定起作用。你可以指定米,公里,英里,海里,这与球面距离无关,输出的单位和输入的单位是一样的,算法对单位是不可知的


    我今天早上把它放在一起,所以它目前只提供多边形中的点,凸多边形中的点,以及三种不同类型的球面距离算法,但至少您要求的那些算法现在已经在那里供您使用了。我不知道是否与任何其他python库存在名称冲突,这些天我只在外围参与python,所以如果有更好的名称,我愿意接受建议

    在github上:

    它只是此处描述和实现的函数的python桥:

    几何体库实际上相当不错,所以我认为它将有助于为python桥接所有这些函数,今晚我可能会这样做

    编辑:一些其他内容

  • 因为数学函数实际上是编译C++,所以当然需要确保共享库在路径中。您可以修改geometry.py,使其指向要放置该共享库的任何位置
  • 仅针对linux编译,.o和.so是在x86_64 fedora上编译的
  • 球面距离算法需要弧度,因此需要将十进制lat/lon度转换为弧度,如geometry.py所示
  • 如果您在Windows上确实需要此功能,请告诉我,在Visual Studio中只需几分钟即可完成。但除非有人问我,我可能现在就不谈了

    希望这有帮助

    Rgds…胡恩托/马特

    (新提交:SHA:4FA2DBBBE849C09252C7BD931EDFE8DB478DE28E6-修复了一些问题,如弧度转换和py函数的返回类型。还添加了一些基本性能测试,以确保库正确执行。)

    测试结果 在每次迭代中,一次调用sphere\u distance1,一次调用polygon\u包含\u point\u 2d,因此有2次调用库总计

    • ~0.062s:2000次迭代,4000次调用
    • ~0.603s:20000次迭代,40000次调用
    • ~0.905s:30000次迭代,60000次呼叫
    • ~1.198s:40000次迭代,80000次调用

    如果球面计算足够,我就用numpy表示距离,用matplotlib表示多边形检查(正如您在stackoverflow中找到的类似建议)

    从数学导入asin、cos、弧度、sin、sqrt
    将numpy作为np导入
    定义大圆距离(pnt1、pnt2、半径):
    “”“返回球体上点之间的距离(纬度、经度),单位为度。”“”
    lat1=弧度(pnt1[0])
    lat2=弧度(pnt2[0])
    dLat=lat2-lat1
    dLon=弧度(pnt2[1])-弧度(pnt1[1])
    a=sin(dLat/2.0)**2+cos(lat1)*cos(lat2)*sin(dLon/2.0)**2
    返回2*asin(最小(1,sqrt(a)))*半径
    定义大圆距离(pnt1、l、pnt2、半径):
    “”“类似于大圆距离(),但处理pnt2列表并返回最小值。”“”
    dLat=np.弧度(l_pnt2[:,0])-弧度(pnt1[0])#从(纬度,经度)点列表中切片纬度
    dLon=np.弧度(l_pnt2[:,1])-弧度(pnt1[1])
    a=np.square(np.sin(dLat/2.0))+np.cos(弧度(pnt1[0])*np.cos(np.radians(l_pnt2[:,0]))*np.square(np.sin(dLon/2.0))
    返回np.min(2*np.arcin(np.minimum)(np.sqrt(a),len(a)))*半径
    def aux_generatelalon():
    随机输入
    而1:
    收益率(90.0-180.0*random.random(),180.0-360.0*random.random())
    如果名称=“\uuuuu main\uuuuuuuu”:
    ## 1. 大圆距离
    地球半径=6371000.785同体积球体
    nPoints=1000
    nRep=100#仅用于测量时间
    #生成要检查的点和点列表
    pnt1=下一个(辅助生成)
    l_pnt2=np.数组([next(aux_generatelalon())表示范围(n)中的i
    
    from math import asin, cos, radians, sin, sqrt
    import numpy as np
    
    def great_circle_distance_py(pnt1, pnt2, radius):
        """ Returns distance on sphere between points given as (latitude, longitude) in degrees. """
        lat1 = radians(pnt1[0])
        lat2 = radians(pnt2[0])
        dLat = lat2 - lat1
        dLon = radians(pnt2[1]) - radians(pnt1[1])
        a = sin(dLat / 2.0) ** 2 + cos(lat1) * cos(lat2) * sin(dLon / 2.0) ** 2
        return 2 * asin(min(1, sqrt(a))) * radius
    
    def great_circle_distance_numpy(pnt1, l_pnt2, radius):
        """ Similar to great_circle_distance_py(), but working on list of pnt2 and returning minimum. """
        dLat = np.radians(l_pnt2[:, 0]) - radians(pnt1[0])   # slice latitude from list of (lat, lon) points
        dLon = np.radians(l_pnt2[:, 1]) - radians(pnt1[1])
        a = np.square(np.sin(dLat / 2.0)) + np.cos(radians(pnt1[0])) * np.cos(np.radians(l_pnt2[:, 0])) * np.square(np.sin(dLon / 2.0))
        return np.min(2 * np.arcsin(np.minimum(np.sqrt(a), len(a)))) * radius
    
    def aux_generateLatLon():
        import random
        while 1:
            yield (90.0 - 180.0 * random.random(), 180.0 - 360.0 * random.random())
    
    if __name__ == "__main__":
        ## 1. Great-circle distance
        earth_radius_m = 6371000.785   # sphere of same volume
        nPoints = 1000
        nRep    = 100   # just to measure time
    
        # generate a point and a list of to check against
        pnt1 = next(aux_generateLatLon())
        l_pnt2 = np.array([next(aux_generateLatLon()) for i in range(nPoints)])
    
        dMin1 = min([great_circle_distance_py(pnt1, pnt2, earth_radius_m) for pnt2 in l_pnt2])
        dMin2 = great_circle_distance_numpy(pnt1, l_pnt2, earth_radius_m)
    
        # check performance
        import timeit
        print "random points: %7i" % nPoints
        print "repetitions  : %7i" % nRep
        print "function 1   : %14.6f s" % (timeit.timeit('min([great_circle_distance_py(pnt1, pnt2, earth_radius_m) for pnt2 in l_pnt2])', 'from __main__ import great_circle_distance_py   , pnt1, l_pnt2, earth_radius_m', number=nRep))
        print "function 2   : %14.6f s" % (timeit.timeit('great_circle_distance_numpy(pnt1, l_pnt2, earth_radius_m)'                     , 'from __main__ import great_circle_distance_numpy, pnt1, l_pnt2, earth_radius_m', number=nRep))
    
        # tell distance
        assert(abs(dMin1 - dMin2) < 0.0001)
        print
        print "min. distance: %14.6f m" % dMin1
    
        ## 2. Inside polygon?
        # Note, not handled:
        #   - the "pathological case" mentioned on http://paulbourke.net/geometry/polygonmesh/
        #   - special situations on a sphere: polygons covering "180 degrees longitude edge" or the Poles
        from matplotlib.path import Path
        x = y = 1.0
        l_pnt2 = [(-x, -y), (x, -y), (x, y), (-x, y), (-x, -y)]
        path = Path(l_pnt2)
        print "isInside ?"
        for pnt in [(0.9, -1.9), (0.9, -0.9)]:
            print "   ", pnt, bool(path.contains_point(pnt))