Shapely의 스냅 (GEO 스냅)이 예상대로 작동하지 않는 이유는 무엇입니까?


14

Shapely / Geopandas를 사용하여 두 줄을 서로 맞추려고하지만 스냅 결과가 매우 이상합니다. 나는 시도했다 :

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

그리고이 결과를 얻었습니다 :

lines1 = 빨간

lines2 = 검은

스냅하기 전에

스냅 후 (공차로 14 포함) : 파란색 선은 스냅 결과입니다.

이 경우 선이 올바르게 스냅됩니다 스냅 후

예상대로 작동하지 않는 또 다른 예 : (스냅하기 전에) 스냅하기 전에

그리고 스냅 후 결과는 다음과 같습니다. 검은 색 선 (남쪽)에는 부품 만 스냅됩니다. 원래 선은 꽤 가깝고 14 피트 이내이지만 스냅 후

공차를 늘리면 다음과 같은 잘못된 출력이 발생합니다 (스냅 핑 공차로 20을 정의한 후 녹색 선이 결과 임).

공차로 20 이후

스냅이 제대로 작동하지 않는 이유에 대한 아이디어가 있습니까? 이 문제를 해결하는 방법에 대한 제안 사항이 있습니까?



@gene 당신은 내가 생각하는 답변으로 의견을 변환해야합니다.
nmtoken

이 문제를 재현하기 위해 데이터 또는 데이터의 일부를 공유 할 수 있습니까?
bugmenot123

2
Shapely 1.6 사용 설명서 제공 : "shape.ops의 snap () 함수는 주어진 공차를 사용하여 한 형상의 정점을 두 번째 형상의 정점에 스냅합니다." 내가 이해하는 것처럼, 서로 가깝게 지오메트리를 스냅하지 않고 정점을 서로 가깝게 스냅합니다. 따라서 어떤 지오메트리가 다른 지오메트리에 가까우면 임계점 내에 정점이 스냅됩니다.
Kadir Şahbaz

답변:


6

shapely.ops.snap함수는 형상의 정점에만 스냅합니다.

아래 그림을 참조하십시오. 왼쪽에서 빨간색 정점은 파란색 정점에 대한 스냅 공차 내에 있으므로 스냅됩니다. 오른쪽에서 빨간색 정점은 스냅 공차 외부에 있습니다 (가장자리에 더 가깝지만!).

스냅 공차 시각화

Shapely는 정점을 모서리에 스냅하는 알고리즘을 제공하지 않습니다. shapely.ops.nearest_points그래도 사용하여 작성하는 것이 어렵지 않아야합니다 . 이와 같은 것 (테스트되지 않았으며 특히 효율적이지 않음) :

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)

매우 시원하지만 생각 if p1.distance(p2 <= threshold):합니다if p1.distance(p2) <= threshold:
chrislarson
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.