支持大圆距离和多边形的快速python GIS库
我正在寻找python的地理库。 我需要能够做到以下几点:支持大圆距离和多边形的快速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执行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桥接所有这些函数,今晚我可能会这样做 编辑:一些其他内容
- ~0.062s:2000次迭代,4000次调用
- ~0.603s:20000次迭代,40000次调用
- ~0.905s:30000次迭代,60000次呼叫
- ~1.198s:40000次迭代,80000次调用
从数学导入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))