Shapelyは現在GEOS3.4.0しかサポートしていないので、 GEOS3.6.0にGEOSSTRtree_nearestのような他の関数を追加するのは素晴らしいことです。 そこで、自分でこの関数を追加して、いくつかの問題に対処しようとしていました。
GEOSのソースコードは次のようなものです。
const GEOSGeometry *
GEOSSTRtree_nearest (geos::index::strtree::STRtree *tree,
const geos::geom::Geometry *g)
{
return GEOSSTRtree_nearest_r( handle, tree, g);
}
const void* GEOSSTRtree_nearest_generic(GEOSSTRtree *tree,
const void* item,
const GEOSGeometry* itemEnvelope,
GEOSDistanceCallback distancefn,
void* userdata)
{
return GEOSSTRtree_nearest_generic_r( handle, tree, item, itemEnvelope, distancefn, userdata);
}
次に、strtree.py、ctypes_declarations.py、test.pyにコードを追加してテストを実行しようとしましたが、セグメンテーション違反エラーが発生しました:11
strtree.py
from shapely.geometry.base import geom_factory
class STRtree:
def nearest(self, geom):
if self._n_geoms == 0:
return None
return geom_factory(lgeos.GEOSSTRtree_nearest(self._tree_handle, geom._geom))
ctypes_declarations.py
def prototype(lgeos, geos_version):
if geos_version >= (3, 6, 0):
lgeos.GEOSSTRtree_nearest.argtypes = [c_void_p, c_void_p]
lgeos.GEOSSTRtree_nearest.restype = c_void_p
test.py
from shapely.geometry import Point, Polygon
from shapely.strtree import STRtree
a = []
a.append(Polygon([(1,0),(2,0),(2,1),(1,1)]))
a.append(Polygon([(0,2),(1,2),(1,3),(0,3)]))
a.append(Polygon([(-1.5,0),(-2.5,0),(-2.5,-1),(-1.5,-1)]))
tree = STRtree(a)
tree.nearest(Point(0,0))
私の問題はctypesとgeometry間のデータ処理にあると思ったので、 shared_path関数に再実装しようとしましたが、それでも問題が発生しました。
from shapely.geometry import LineString
from shapely.geometry.base import geom_factory
from ctypes import CDLL, c_void_p
dll = CDLL('/Users/*****/anaconda3/lib/python3.7/site-packages/shapely/.dylibs/libgeos_c.1.dylib')
shared_path = dll.GEOSSharedPaths
shared_path.restype = c_void_p
shared_path.argtypes = [c_void_p, c_void_p]
g1 = LineString([((0, 0), (1, 1)), ((-1, 0), (1, 0))])
g2 = LineString([((0, 0), (1, 1)), ((-2, 0), (1, 5))])
geom_factory(shared_path(g1._geom, g2._geom))
これを理解するのを手伝ってくれませんか、thx!
こんにちは@FuriousRococo 、私は最近傍検索機能の使用に慣れていませんが、あなたはほぼ正しい方向に進んでいるようです。 ただし、 https://github.com/libgeos/geos/blob/master/capi/geos_c.h.in#L1824で、ツリー内のアイテムがPythonオブジェクトであるため、ジェネリックメソッドを使用する必要があるという兆候が見られます。 。 https://github.com/libgeos/geos/blob/master/capi/geos_c.h.in#L1850を試してみる必要があると思います。
@sgilliesのアドバイスをありがとう、私はそれが今働いていると思います。
strtree.py
class STRtree:
def nearest(self, geom):
if self._n_geoms == 0:
return None
envelope = geom.envelope
def callback(item1, item2, distance, userdata):
try:
geom1 = ctypes.cast(item1, ctypes.py_object).value
geom2 = ctypes.cast(item2, ctypes.py_object).value
dist = ctypes.cast(distance, ctypes.POINTER(ctypes.c_double))
lgeos.GEOSDistance(geom1._geom, geom2._geom, dist)
return 1
except:
return 0
item = lgeos.GEOSSTRtree_nearest_generic(self._tree_handle, ctypes.py_object(geom), envelope._geom, \
lgeos.GEOSDistanceCallback(callback), None)
geom = ctypes.cast(item, ctypes.py_object).value
return geom
ctypes_declarations.py
def prototype(lgeos, geos_version):
if geos_version >= (3, 6, 0):
lgeos.GEOSDistanceCallback = CFUNCTYPE(c_int, c_void_p, c_void_p, c_void_p, c_void_p)
lgeos.GEOSSTRtree_nearest_generic.argtypes = [
c_void_p, py_object, c_void_p, lgeos.GEOSDistanceCallback, py_object]
lgeos.GEOSSTRtree_nearest_generic.restype = c_void_p
test.py
from shapely.geometry import Point, Polygon
from shapely.strtree import STRtree
a = []
a.append(Polygon([(1,0),(2,0),(2,1),(1,1)]))
a.append(Polygon([(0,2),(1,2),(1,3),(0,3)]))
a.append(Polygon([(-1.5,0),(-2.5,0),(-2.5,-1),(-1.5,-1)]))
a.append(Point(0,0.5))
tree = STRtree(a)
pt = tree.nearest(Point(0,0))
print(pt.wkt)
出力POINT (0 0.5)
@FuriousRococoこの新機能でプルリクエストを送信しますか?
機能@FuriousRococoを追加していただきありがとうございます。 この最も近い関数を理解しようとしているときの質問。 ポイントに最も近い道路を見つけようとしているとしましょう。 したがって、STRツリーはMultiLineString道路のツリーです。 したがって、この場合、ポイントからMultiLineStringsまでの投影距離を使用して、最も近い道路が指定されますか? それとも、道路を表すMultiLineStringsの重心までの最小距離に基づいていますか? ありがとう!
私はテストを作成しましたが、最も近い関数がMultiLineStringのすべての行をチェックして、最も近い行がMultiLineString内にあるかどうかを確認すると思います。 これが私のスクリプト@ asif-rehanです
test.py
from shapely.strtree import STRtree
from shapely.geometry import Point, LineString, MultiLineString
tree_list = [LineString([[0,1],[1,1]])]
tree_list.append(MultiLineString([LineString([[0,0],[1,0]]),LineString([[0,3],[1,3]])]))
tree = STRtree(tree_list)
tree.nearest(Point(0.5,0.25)).wkt
出力MULTILINESTRING ((0 0, 1 0), (0 3, 1 3))
最も参考になるコメント
@sgilliesのアドバイスをありがとう、私はそれが今働いていると思います。
strtree.py
ctypes_declarations.py
test.py
出力
POINT (0 0.5)