9

Python 用の地理的ライブラリを探していました。次のことができる必要があります。

  1. 大圏距離を使用して 2 点間の距離 (メートル単位) を取得します(直線距離の計算ではありません) 。
  2. ポイントがポリゴン内にあるかどうかを確認する
  3. 1秒間に数千回と2回実行する

最初に、この投稿を見てきました: 地理座標を保存および照会するための Python モジュールとgeopyの使用を開始しました。私は2つの問題に遭遇しました:

  1. Geopy はポリゴンをサポートしていません
  2. geoPy の CPU 使用率が高い (ポイントと相対 5000 ポイント間の距離を計算するには、約 140 ミリ秒の CPU が必要です)

私は探し続けて、最高のPython GISライブラリを見つけましたか? およびhttps://gis.stackexchange.com/。geos はコンパイルされた C コードを使用しているため、より高速でポリゴンを適切にサポートする必要があるため、有望に見えました。問題は、geos/OGR が球ではなく直線距離の計算を実行することです。これにより、他のすべての geo ベースのモジュール (GEODjango や shapely など) が排除されます。ここで何か不足していますか?Python を使用して GIS 計算を実行し、正確な結果を得たいと考えているのは、私が初めてではないと思います。

4

2 に答える 2

1

アップデート

次に、完成した 2 つのポリゴン関数、完成した 3 つの球距離アルゴリズム、および 2 つの新しいもの、angle_box_2d と angle_contains_ray_2d を除く、そのライブラリ内の他の 576 個の関数の完成に移ります。また、externsが不要になるようにCバージョンに切り替え、作業を簡素化しました。古い C++ バージョンをディレクトリ old_c++ に入れて、まだそこにあるようにします。

テストされたパフォーマンスは、回答の下部に記載されているものと同じです。


更新 2

簡単な更新ですが、私はまだライブラリ全体を完成させていません (まだ約 15% しか進んでいません) が、これらのテストされていない関数を追加しました。多角形および球距離アルゴリズムの古いポイントに追加します。

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

上でコメントしたものはおそらく機能しませんが、他のものは機能する可能性がありますが、ポリゴンと球体の距離は間違いなく機能します。また、メートル、キロメートル、マイル、海里を指定できます。球面距離のものでは実際には問題ではありません。出力は入力と同じ単位です。アルゴリズムは単位に依存しません。


今朝これをまとめたので、現在のところ、ポリゴン内のポイント、凸ポリゴン内のポイント、および 3 つの異なるタイプの球面距離アルゴリズムしか提供されていませんが、少なくともあなたが要求したものは、すぐに使用できるようになっています。他の python ライブラリと名前が競合するかどうかはわかりません。最近は python に周辺的にしか関与していないので、より良い名前があれば、提案を受け付けています。

github: https://github.com/hoonto/pygeometry

これは、ここで説明および実装されている関数への Python ブリッジにすぎません。

http://people.sc.fsu.edu/~jburkardt/cpp_src/geometry/geometry.html

GEOMETRY ライブラリは実際にはかなり優れているので、これらの関数をすべて Python 用に橋渡しするのに役立つと思います。これはおそらく今夜行う予定です。

編集:他のいくつかのこと

  1. 数学関数は実際には C++ でコンパイルされているため、もちろん、共有ライブラリがパスにあることを確認する必要があります。ただし、その共有ライブラリを配置したい場所を指すように geometry.py を変更できます。
  2. Linux 用にのみコンパイルされ、.o および .so は x86_64 fedora でコンパイルされました。
  3. 球面距離アルゴリズムはラジアンを想定しているため、geometry.py に示されているように、たとえば 10 進数の緯度/経度をラジアンに変換する必要があります。

Windows でこれが必要な場合はお知らせください。Visual Studio で作業するのに数分しかかかりません。でも、誰かに聞かれない限り、とりあえず放っておくことにします。

お役に立てれば!

Rgds....フーント/マット

(新しいコミット: SHA: 4fa2dbbe849c09252c7bd931edfe8db478de28e6 - ラジアン変換や py 関数の戻り値の型など、いくつかを修正しました。また、ライブラリが適切に動作することを確認するために、いくつかの基本的なパフォーマンス テストを追加しました。)

テスト結果 各反復で、sphere_distance1 への 1 回の呼び出しと、polygon_contains_point_2d への 1 回の呼び出しにより、合計 2 回のライブラリへの呼び出しが行われます。

  • ~0.062s : 2000 回の繰り返し、4000 回の呼び出し
  • ~0.603s : 20000 回の反復、40000 回の呼び出し
  • ~0.905 秒: 30000 回の反復、60000 回の呼び出し
  • ~1.198s : 40000 回の繰り返し、80000 回の呼び出し
于 2013-06-18T17:53:15.580 に答える
0

球状の計算で十分な場合は、距離には numpy を使用し、多角形チェックには matplotlib を使用します (stackoverflow で同様の提案があるため)。

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))

もっとやりたい場合は、Quantum GIS ツールセットは一見の価値があります: PyQGIS Developer Cookbook (docs.qgis.org)

于 2013-06-19T10:57:06.157 に答える