Dlaczego przyciąganie Shapely (przyciągania GEO) nie działa zgodnie z oczekiwaniami?

14

Próbuję przyciągnąć do siebie dwie linie za pomocą Shapely / Geopandas, ale rezultat przyciągania jest bardzo dziwny. Próbowałem :

import geopandas as gpd
from shapely.geometry import *
from shapely.ops import snap

lines1 = gpd.GeoDataFrame.from_file('lines1.shp')
lines1 = lines1.to_crs({'init': 'epsg:2227'})
lines2 = gpd.GeoDataFrame.from_file('lines2.shp')
lines2 = lines2.to_crs({'init': 'epsg:2227'})
res = lines1
lines2_union = lines2.geometry.unary_union
res.geometry = res.geometry.apply(lambda x: snap(x, lines2_union, 14))
res.to_file('result.shp', driver="ESRI Shapefile")

I uzyskałem ten wynik:

lines1 = czerwone linie

linie2 = czarne linie

Przed snapowaniem

Po przyciąganiu (z tolerancją 14): niebieskie linie są wynikiem przyciągania

W takim przypadku linie są poprawnie przyciągane Po przyciągnięciu

Kolejny przykład, w którym nie działał zgodnie z oczekiwaniami: (przed snapowaniem) Przed snapowaniem

A oto wynik po przyciągnięciu. Tylko część jest przyciągana do czarnej linii (strona południowa). Chociaż oryginalne linie są dość blisko i w obrębie 14 stóp Po przyciągnięciu

Jeśli zwiększę tolerancję, otrzymam błędny wynik, coś takiego (po zdefiniowaniu 20 jako tolerancji przyciągania, wynikiem jest zielona linia):

Po 20 jako tolerancja

Wszelkie pomysły na to, dlaczego przyciąganie nie działa poprawnie? Wszelkie sugestie dotyczące rozwiązania tego problemu?

GeoSal
źródło
@gene powinieneś przekonwertować swój komentarz na odpowiedź.
nmtoken
Czy możesz udostępnić dane lub ich części, aby odtworzyć ten problem?
bugmenot123
2
Zapewniono instrukcję obsługi Shapely 1.6: „Funkcja snap () w shapely.ops przyciąga wierzchołki jednej geometrii do wierzchołków drugiej geometrii z określoną tolerancją”. Jak rozumiem, nie przyciąga geometrii, które są blisko siebie, przyciąga ich wierzchołki blisko siebie. Więc jeśli jakakolwiek geometria jest zbliżona do innej geometrii, przyciąga ich wierzchołki w granicach progu.
Kadir Şahbaz

Odpowiedzi:

6

shapely.ops.snapFunkcja jest przyciągany do wierzchołków tylko geometrii.

Zobacz ilustrację poniżej. Po lewej czerwony wierzchołek mieści się w tolerancji przyciągania do niebieskiego wierzchołka, więc zostanie przyciągnięty. Po prawej czerwony wierzchołek jest poza tolerancją przyciągania (mimo że jest bliżej krawędzi!).

przyciąganie wizualizacji tolerancji

Shapely nie zapewnia algorytmu przyciągania wierzchołków do krawędzi. shapely.ops.nearest_pointsJednak napisanie takiego przy użyciu nie powinno być trudne . Coś takiego (nie testowane i niezbyt wydajne):

from shapely.ops import nearest_points

def snap(g1, g2, threshold):
    coordinates = []
    for x, y in g1.coords:  # for each vertex in the first line
        point = Point(x, y)
        p1, p2 = nearest_points(point, g2)  # find the nearest point on the second line
        if p1.distance(p2 <= threshold):
            # it's within the snapping tolerance, use the snapped vertex
            coordinates.append(p2.coords[0])
        else:
            # it's too far, use the original vertex
            coordinates.append((x, y))
    # convert coordinates back to a LineString and return
    return LineString(coordinates)
Snorfalorpagus
źródło
Bardzo fajnie, ale myślę, że if p1.distance(p2 <= threshold):powinno byćif p1.distance(p2) <= threshold:
chrislarson