Pourquoi l'alignement de Shapely (accrochages GEO) ne fonctionne-t-il pas comme prévu?

14

J'essaie d'aligner deux lignes l'une sur l'autre en utilisant Shapely / Geopandas mais le résultat de l'alignement est très étrange. J'ai essayé :

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

Et j'ai obtenu ce résultat:

lines1 = lignes rouges

lines2 = lignes noires

Avant le claquement

Après la capture (avec 14 comme tolérance): les lignes bleues sont le résultat de la capture

Dans ce cas, les lignes sont correctement prises Après le claquement

Un autre exemple où cela n'a pas fonctionné comme prévu: (avant la capture) Avant le claquement

Et voici le résultat après la capture. Seule une partie est accrochée à la ligne noire (le côté sud). Bien que les lignes d'origine soient assez proches et dans les 14 pieds Après le claquement

Si j'augmente la tolérance, j'obtiens une sortie erronée, quelque chose comme ça (après avoir défini 20 comme la tolérance de l'accrochage, la ligne verte est le résultat):

Après 20 comme tolérance

Des idées sur la raison pour laquelle le cliché ne fonctionne pas correctement? Des suggestions sur la façon de résoudre ce problème?

GeoSal
la source
@gene vous devriez convertir votre commentaire en une réponse je pense.
nmtoken
Pouvez-vous partager les données ou des parties de celles-ci pour reproduire ce problème?
bugmenot123
2
Manuel utilisateur Shapely 1.6 fourni: "La fonction snap () dans shapely.ops capture les sommets d'une géométrie sur les sommets d'une seconde géométrie avec une tolérance donnée." Si je comprends bien, il ne capture pas les géométries proches les unes des autres, il capture leurs sommets les uns à côté des autres. Donc, si une géométrie est proche d'une autre géométrie, elle accroche ses sommets dans le seuil.
Kadir Şahbaz

Réponses:

6

La shapely.ops.snapfonction s'aligne uniquement sur les sommets des géométries.

Voir l'illustration ci-dessous. Sur la gauche, le sommet rouge se trouve dans la tolérance d'accrochage au sommet bleu, il s'accroche donc. Sur la droite, le sommet rouge est en dehors de la tolérance d'accrochage (bien qu'il soit plus proche du bord!).

visualisation de la tolérance d'accrochage

Shapely ne fournit pas d'algorithme pour accrocher les sommets aux arêtes. Il ne devrait cependant pas être trop difficile d'en écrire un en utilisant shapely.ops.nearest_points. Quelque chose comme ça (non testé et pas particulièrement efficace):

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
la source
Très cool mais je pense que ça if p1.distance(p2 <= threshold):devrait êtreif p1.distance(p2) <= threshold:
chrislarson