Почему привязка 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")

И получил этот результат:

линии1 = красные линии

линии2 = черные линии

До щелчка

После привязки (с допуском 14): синие линии - результат привязки

В этом случае линии правильно отрезаны После привязки

Другой пример, где это не сработало, как ожидалось: (до щелчка) До щелчка

И вот результат после привязки. Только часть привязана к черной линии (южная сторона). Хотя оригинальные линии довольно близки и в пределах 14 футов После привязки

Если я увеличиваю допуск, я получаю неправильный вывод, что-то вроде этого (после определения 20 как допуск привязки, зеленая линия - результат):

После 20 как толерантность

Любые идеи о том, почему привязка не работает должным образом? Любые предложения о том, как решить эту проблему?

GeoSal
источник
@gene, вы должны преобразовать свой комментарий в ответ, я думаю.
nmtoken
Можете ли вы поделиться данными или их частями, чтобы воспроизвести эту проблему?
bugmenot123
2
Предоставлено Shapely 1.6. Руководство пользователя: «Функция snap () в shapely.ops привязывает вершины одной геометрии к вершинам второй геометрии с заданным допуском». Как я понимаю, он не привязывает геометрии, которые близки друг к другу, он привязывает их вершины близко друг к другу. Поэтому, если какая-либо геометрия близка к другой геометрии, она привязывает их вершины в пределах порога.
Кадир Шахбаз

Ответы:

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)
Snorfalorpagus
источник
Очень круто, но я думаю, что if p1.distance(p2 <= threshold):должно бытьif p1.distance(p2) <= threshold:
chrislarson