Warum funktioniert Shapelys Schnappschuss (GEO-Schnappschuss) nicht wie erwartet?

14

Ich versuche, mit Shapely / Geopandas zwei Linien miteinander zu verbinden, aber das Ergebnis des Schnappens ist sehr merkwürdig. Ich habe es versucht :

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

Und bekam dieses Ergebnis:

lines1 = rote Linien

lines2 = schwarze Linien

Vor dem Einrasten

Nach dem Fang (mit 14 als Toleranz): Die blauen Linien sind das Ergebnis des Fangens

In diesem Fall werden die Linien korrekt eingerastet Nach dem Knipsen

Ein weiteres Beispiel, wo es nicht wie erwartet funktioniert hat: (vor dem Einrasten) Vor dem Einrasten

Und hier ist das Ergebnis nach dem Einrasten. Nur ein Teil wird an der schwarzen Linie (der Südseite) gefangen. Obwohl die ursprünglichen Linien ziemlich nah und innerhalb der 14 Fuß sind Nach dem Knipsen

Wenn ich die Toleranz erhöhe, erhalte ich eine falsche Ausgabe (nach der Definition von 20 als Toleranz für das Einrasten ist die grüne Linie das Ergebnis):

Nach 20 als Toleranz

Irgendwelche Ideen, warum das Knipsen nicht richtig funktioniert? Irgendwelche Vorschläge zur Lösung dieses Problems?

GeoSal
quelle
@gene du solltest deinen Kommentar in eine Antwort umwandeln, denke ich.
Nmtoken
Können Sie die Daten oder Teile davon freigeben, um dieses Problem zu reproduzieren?
Bugmenot123
2
Mitgeliefertes Shapely 1.6-Benutzerhandbuch: "Die Funktion snap () in shapely.ops fängt die Scheitelpunkte in einer Geometrie mit einer bestimmten Toleranz an den Scheitelpunkten in einer zweiten Geometrie." Soweit ich weiß, werden keine nahe beieinander liegenden Geometrien gefangen, sondern ihre Scheitelpunkte werden nahe beieinander gefangen. Wenn sich also eine Geometrie in der Nähe einer anderen Geometrie befindet, werden ihre Scheitelpunkte innerhalb des Schwellenwerts gefangen.
Kadir Şahbaz

Antworten:

6

Die shapely.ops.snapFunktion rastet nur an den Scheitelpunkten von Geometrien ein.

Siehe die Abbildung unten. Auf der linken Seite befindet sich der rote Scheitelpunkt innerhalb der Fangtoleranz zum blauen Scheitelpunkt, sodass er schnappt. Rechts befindet sich der rote Scheitelpunkt außerhalb der Fangtoleranz (obwohl er näher am Rand liegt!).

Schnapptoleranz Visualisierung

Shapely bietet keinen Algorithmus zum Einrasten von Eckpunkten an Kanten. Es sollte jedoch nicht allzu schwierig sein, einen zu schreiben shapely.ops.nearest_points. So etwas (nicht getestet und nicht besonders effizient):

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
quelle
Sehr cool, aber ich denke if p1.distance(p2 <= threshold):sollte seinif p1.distance(p2) <= threshold:
Chrislarson