Shapely: Запрос функции: добавьте функцию STRtree.nearest

Созданный на 7 янв. 2019  ·  5Комментарии  ·  Источник: Toblerity/Shapely

Примечание

Поскольку сейчас Shapely поддерживает только GEOS 3.4.0, было бы здорово добавить другие функции, такие как GEOSSTRtree_nearest, в GEOS 3.6.0. Поэтому я пытался добавить эту функцию самостоятельно и столкнулся с некоторыми проблемами.

Проблемы

Исходный код 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 и попытался запустить тест, но получил ошибку Segmentation fault: 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 и геометрией, поэтому я попытался переопределить функцию 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))

Не могли бы вы помочь мне понять это, спасибо!

Самый полезный комментарий

Спасибо за совет @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)

Все 5 Комментарий

Привет @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))

Была ли эта страница полезной?
0 / 5 - 0 рейтинги