Зваріть окремі сегменти лінії в одну LineString за допомогою Shapely


13

Я використовую Shapely в python, і мені дають MultiLineStringкучу Linestringоб’єктів. Я можу гарантувати, що всі LineStringоб'єкти є простими лініями, що мають лише 2 вершини, і що всі вони є частиною однієї єдиної лінії (без гілок).

Я хочу "підключити точки" і створити єдину LineString. Чи потрібно мені написати рекурсивний метод зварювання для цього чи існує більш швидкий спосіб?

Відповіді:


20

Ви можете використовувати shapely's ops.linemergeдля цього:

from shapely import geometry, ops

# create three lines
line_a = geometry.LineString([[0,0], [1,1]])
line_b = geometry.LineString([[1,1], [1,0]])
line_c = geometry.LineString([[1,0], [2,0]])

# combine them into a multi-linestring
multi_line = geometry.MultiLineString([line_a, line_b, line_c])
print(multi_line)  # prints MULTILINESTRING ((0 0, 1 1), (1 1, 2 2), (2 2, 3 3))

# you can now merge the lines
merged_line = ops.linemerge(multi_line)
print(merged_line)  # prints LINESTRING (0 0, 1 1, 2 2, 3 3)

# if your lines aren't contiguous
line_a = geometry.LineString([[0,0], [1,1]])
line_b = geometry.LineString([[1,1], [1,0]])
line_c = geometry.LineString([[2,0], [3,0]])

# combine them into a multi-linestring
multi_line = geometry.MultiLineString([line_a, line_b, line_c])
print(multi_line)  # prints MULTILINESTRING ((0 0, 1 1), (1 1, 1 0), (2 0, 3 0))

# note that it will now merge only the contiguous portions into a component of a new multi-linestring
merged_line = ops.linemerge(multi_line)
print(merged_line)  # prints MULTILINESTRING ((0 0, 1 1, 1 0), (2 0, 3 0))

Як я можу дізнатись, яка лінія рядків була об'єднана? Я хочу отримати такий список, як: merged = [[line_a, line_b], [line_c]]
Джеймс

Ви можете переглядати список окремих рядків і перевірити, чи є нова об'єднана лінія contains()окремими лініями. Ті, що не містяться, не були б об'єднані. наприклад, merged_line.contains(line_a)який би повернув булеву TrueабоFalse
songololo

дуже дякую. Як перевірити, чи міститься рядок у об'єднаних лініях?
Джеймс

1
ах, я не розумів, що ".contains (line_a)" була попередньо записаною функцією. досконалий. Дуже дякую !
Джеймс

1
Вибачте, що вас знову турбує ... але чи знаєте ви, хто об'єднує лінії, що знаходяться "близько" (на певній максимальній відстані одна від одної)? Я запитую, тому що я бачу багато ліній, які слід об'єднати, але через невелику щілину між ними вони не злиті.
Джеймс

2

Я думаю, ви могли б зробити це з Shapely, використовуючи метод shapely.ops.linemerge ().

Схоже, він міг би взяти список рядків як вхідний і об'єднати їх. Раніше я використовував метод "полігонізації", і він займає список рядків.

Подивіться на документ тут: http://toblerity.org/shapely/manual.html#shapely.ops.linemerge


1
Чи знаєте ви, як об’єднати лінії, що знаходяться "близько" (на певній максимальній відстані один від одного)?
Джеймс

polygonize_full працює дещо краще, але в результаті я отримав деякі дивні структури даних
danuker

1

shapely.ops.linemerge()не вдалося виконати деякі мої лінії, тому мені довелося це зробити вручну. Здається, це не вдається для рядків, які «повернулися» до себе, тобто пройшли через ту саму точку не один раз. У моєму випадку я знаю, що рядки в правильному порядку, тому було легко написати невелику функцію для їх об’єднання.

from shapely.geometry import LineString
from typing import List


def merge_lines(lines: List[LineString]) -> LineString:
    last = None
    points = []
    for line in merged_line:
        current = line.coords[0]

        if last is None:
            points.extend(line.coords)
        else:
            if last == current:
                points.extend(line.coords[1:])
            else:
                print('Skipping to merge {} {}'.format(last, current))
                return None
        last = line.coords[-1]
    return LineString(points)

Сподіваюся, це комусь допоможе


0

shapely.ops.linemergeпрацює, якщо рядки є суміжними ("підказки" збігаються з "хвостиками" складових ліній), але якщо вони не є суміжними (якщо між кінчиками та хвостами є розрив), він повертає інший MultiLineString. Якщо ваші складові лінії добре впорядковані (один рядок закінчується біля початку наступного рядка), але має розрив від кінця до хвоста, ви можете витягнути координати та використовувати їх для створення нової простої лінії. Цей підхід також працює для багаторядкових рядків, складених із більш складних підрядів (тобто підрядків з більш ніж двома точками).

import shapely

# Make a MultiLineString to use for the example
inlines = shapely.geometry.MultiLineString(
    [shapely.geometry.LineString([(0,0),(0,0.9)]), 
     shapely.geometry.LineString([(0,1),(1,1)])]
)

# Put the sub-line coordinates into a list of sublists
outcoords = [list(i.coords) for i in inlines]

# Flatten the list of sublists and use it to make a new line
outline = shapely.geometry.LineString([i for sublist in outcoords for i in sublist])
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.