Perché lo snap di Shapely (snap GEO) non funziona come previsto?


14

Sto cercando di collegare due linee l'una all'altra usando Shapely / Geopandas ma il risultato dello snap è molto strano. Provai :

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

E ottenuto questo risultato:

lines1 = linee rosse

lines2 = linee nere

Prima dello schiocco

Dopo lo snap (con 14 come tolleranza): le linee blu sono il risultato dello snap

In questo caso le linee sono correttamente spezzate Dopo lo schiocco

Un altro esempio in cui non ha funzionato come previsto: (prima dello snap) Prima dello schiocco

Ed ecco il risultato dopo lo schiocco. Solo una parte viene agganciata alla linea nera (il lato sud). Sebbene le linee originali siano piuttosto vicine e entro i 14 piedi Dopo lo schiocco

Se aumento la tolleranza ottengo un output errato, qualcosa del genere (dopo aver definito 20 come tolleranza dello snap, la linea verde è il risultato):

Dopo 20 come tolleranza

Qualche idea sul perché lo schiocco non funzioni correttamente? Qualche suggerimento su come risolvere questo problema?



@gene dovresti convertire il tuo commento in una risposta, credo.
nmtoken,

Puoi condividere i dati o parti di esso per riprodurre questo problema?
bugmenot123,

2
Fornito Shapely 1.6 Manuale dell'utente: "La funzione snap () in shapely.ops esegue lo snap dei vertici in una geometria ai vertici in una seconda geometria con una determinata tolleranza." A quanto ho capito, non scatta geometrie vicine tra loro, scatta i loro vertici vicini l'uno all'altro. Quindi, se una geometria è vicina ad altre geometrie, scatta i loro vertici entro la soglia.
Kadir Şahbaz,

Risposte:


6

La shapely.ops.snapfunzione si aggancia solo ai vertici delle geometrie.

Vedi l'illustrazione sotto. A sinistra, il vertice rosso rientra nella tolleranza di aggancio al vertice blu, quindi si spezzerà. A destra il vertice rosso è al di fuori della tolleranza a scatto (nonostante sia più vicino al bordo!).

visualizzazione della tolleranza a scatto

Shapely non fornisce un algoritmo per agganciare vertici ai bordi. Non dovrebbe essere troppo difficile scriverne uno usando shapely.ops.nearest_pointsperò. Qualcosa del genere (non testato e non particolarmente efficiente):

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)

Molto bello ma penso che if p1.distance(p2 <= threshold):dovrebbe essereif p1.distance(p2) <= threshold:
Chrislarson il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.