Shapelyのスナップ(GEOスナップ)が期待どおりに機能しないのはなぜですか?


14

Shapely / Geopandasを使用して2本の線を互いにスナップしようとしていますが、スナップの結果は非常に奇妙です。私は試した :

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 16

2
Shapely 1.6ユーザーマニュアルを提供:「shapely.opsのsnap()関数は、1つのジオメトリの頂点を、指定された許容値で2番目のジオメトリの頂点にスナップします。」私が理解しているように、お互いに近いジオメトリをスナップするのではなく、頂点をお互いにスナップします。そのため、ジオメトリが他のジオメトリに近い場合、頂点をしきい値内にスナップします。
カディールŞahbaz18年

回答:


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:
クリスラーソン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.