Spawaj pojedyncze segmenty linii w jeden LineString za pomocą Shapely


13

Używam Shapely w pythonie i dostaję MultiLineStringmnóstwo Linestringobiektów. Mogę zagwarantować, że wszystkie LineStringobiekty są prostymi liniami z tylko 2 wierzchołkami i że wszystkie są częścią jednej pojedynczej linii (bez gałęzi).

Chcę „połączyć kropki” i stworzyć singiel LineString. Czy muszę do tego napisać metodę spawania rekurencyjnego, czy jest szybszy sposób?

Odpowiedzi:


20

Można użyć shapely„s ops.linemergedo osiągnięcia tego celu:

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

Skąd mam wiedzieć, który łącznik został scalony? Chcę otrzymać listę w rodzaju: scalony = [[linia_a, linia_b], [linia_c]]
James

Możesz przeglądać listę poszczególnych linii i sprawdzać, czy nowa linia scalona contains()łączy poszczególne linie. Te niezawarte nie zostałyby połączone. np. merged_line.contains(line_a)który zwróciłby wartość logiczną TruelubFalse
songololo

wielkie dzięki. Jak sprawdzisz, czy linia jest zawarta w połączonych liniach?
James

1
ah, nie zrozumiałem, że „.contains (line_a)” to wcześniej napisana funkcja. doskonały. Wielkie dzięki !
James

1
przepraszam, że przeszkadzam jeszcze raz ... ale czy wiesz, kto połączyć linie, które są „blisko” (w pewnej maksymalnej odległości od siebie)? Pytam, ponieważ widzę wiele linii, które powinny zostać scalone, ale ze względu na małą przerwę między nimi, nie są one scalone.
James

2

Myślę, że można to zrobić za pomocą Shapely przy użyciu metody shapely.ops.linemerge ().

Wygląda na to, że może pobierać listę linii jako dane wejściowe i scalać je. Wcześniej użyłem metody „poligonizacji” i zajmuje ona listę linii.

Spójrz na dokument tutaj: http://toblerity.org/shapely/manual.html#shapely.ops.linemerge


1
Czy wiesz, jak scalać linie, które są „blisko” (w pewnej maksymalnej odległości od siebie)?
James

polygonize_full działa nieco lepiej, ale mam jakieś dziwne datastructures W efekcie
danuker

1

shapely.ops.linemerge()nie powiodło się dla niektórych moich linii, więc musiałem to zrobić ręcznie. Wydaje się, że zawodzi w przypadku linii, które „wróciły” do siebie, tzn. Przechodzą przez ten sam punkt więcej niż raz. W moim przypadku wiem, że wiersze są we właściwej kolejności, więc łatwo było napisać małą funkcję do ich scalenia.

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)

Mam nadzieję, że to komuś pomoże


0

shapely.ops.linemergedziała, jeśli linie są ciągłe („końcówki” pokrywają się z „ogonami” linii składowych), ale jeśli nie są one ciągłe (jeśli istnieje przerwa między końcami i ogonami), zwraca kolejną MultiLineString. Jeśli twoje linie składowe są dobrze uporządkowane (z jedną linią kończącą się w pobliżu początku następnej linii), ale mają odstęp od czubka do końca, możesz wyodrębnić współrzędne i użyć ich, aby utworzyć nową prostą linię. To podejście działa również w przypadku wielu linii wykonanych z bardziej złożonych podlinii (tj. Podlini z więcej niż dwoma punktami).

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])
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.