为什么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用户手册:“ shapely.ops中的snap()函数以给定的公差将一个几何图形中的顶点捕捉到第二个几何图形中的顶点。” 据我了解,它不会对齐彼此接近的几何,而是对齐其顶点彼此接近。因此,如果任何几何图形都与其他几何图形接近,它将在阈值内捕捉其顶点。
KadirŞahbaz18年

Answers:


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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.