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
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
Un autre exemple où cela n'a pas fonctionné comme prévu: (avant la capture)
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
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):
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?
Réponses:
La
shapely.ops.snap
fonction 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!).
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):la source
if p1.distance(p2 <= threshold):
devrait êtreif p1.distance(p2) <= threshold: