Por que o snap do Shapely (snap GEO) não está funcionando como o esperado?

14

Estou tentando encaixar duas linhas entre si usando Shapely / Geopandas, mas o resultado do encaixe é muito estranho. Eu tentei :

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 conseguiu este resultado:

lines1 = linhas vermelhas

lines2 = linhas pretas

Antes do encaixe

Após o encaixe (com 14 como tolerância): as linhas azuis são o resultado do encaixe

Nesse caso, as linhas estão corretamente ajustadas Após o encaixe

Outro exemplo em que não funcionou conforme o esperado: (antes do snap) Antes do encaixe

E aqui está o resultado após o encaixe. Apenas uma parte é encaixada na linha preta (lado sul). Embora as linhas originais estejam bem próximas e dentro dos 14 pés Após o encaixe

Se eu aumentar a tolerância, obtenho uma saída errada, algo assim (depois de definir 20 como a tolerância do snap, a linha verde é o resultado):

Após 20 anos como tolerância

Alguma idéia de por que o snap não está funcionando corretamente? Alguma sugestão sobre como resolver este problema?

GeoSal
fonte
@ gene você deve converter seu comentário em uma resposta, eu acho.
NmToken
Você pode compartilhar os dados ou partes deles para reproduzir esse problema?
precisa
2
Fornecido Shapely 1.6 Manual do Usuário: "A função snap () em shapely.ops ajusta os vértices em uma geometria aos vértices em uma segunda geometria com uma determinada tolerância." Pelo que entendi, ele não encaixa geometrias próximas umas das outras, encaixa seus vértices próximos um do outro. Portanto, se alguma geometria estiver próxima de outra, ela encaixará seus vértices dentro do limite.
Kadir Şahbaz 22/0318

Respostas:

6

A shapely.ops.snapfunção é ajustada apenas aos vértices das geometrias.

Veja a ilustração abaixo. À esquerda, o vértice vermelho está dentro da tolerância de snap ao vértice azul; À direita, o vértice vermelho está fora da tolerância de encaixe (apesar de estar mais próximo da borda!).

visualização de tolerância de encaixe

Shapely não fornece um algoritmo para ajustar vértices às arestas. shapely.ops.nearest_pointsPorém, não deve ser muito difícil escrever um usando . Algo assim (não testado e não especialmente eficiente):

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
fonte
Muito legal, mas acho que if p1.distance(p2 <= threshold):deveria serif p1.distance(p2) <= threshold:
chrislarson