Przecinające się linie, aby uzyskać skrzyżowania za pomocą Pythona z QGIS?


10

Mam zestaw linii reprezentujących linie autobusowe. Niektóre linie nachodzą na siebie i biegną tymi samymi drogami.

wprowadź opis zdjęcia tutaj

Jestem w stanie wyodrębnić węzły. wprowadź opis zdjęcia tutaj

Jednak interesuje mnie wyodrębnianie tylko takich przejść: wprowadź opis zdjęcia tutaj

W jaki sposób mogę to zrobić? Szukam sposobów na QGIS lub Python.

Próbowałem metody przecięcia z GDAL Python, ale to w zasadzie zwraca mi tylko wierzchołki.

Metoda przecięcia linii z QGIS zwraca mi skrzyżowania, jeśli przecinają się dwie linie. Jednak w przypadku, gdy dwie linie autobusowe idą daleko na części swojej trasy na tej samej drodze, nie daje mi to punktu, w którym się łączą.


Czy wypróbowałeś już narzędzie do przecinania linii w QGIS: Narzędzie analizy wektorowej> Przecięcia linii ... Nie da to końca i początkowych węzłów linii, ale wszystkie przecięcia.
Jakob,

Tak, napisałem o tym w pytaniu.
ustroetz

Nie jestem pewien, o co pytasz, po części dlatego, że wszystkie linie są symbolizowane w ten sam sposób na twoich obrazach - nie mogę odróżnić różnych tras, aby zrozumieć, na które węzły patrzysz i dlaczego jest ich tak wiele drugi obraz. Czy trasy są zbieżne na drogach? Czy to wszystkie dwupunktowe segmenty linii, czy ciągłe polilinie? Zwracam uwagę, że opisywane zachowanie jest takie samo, jak w narzędziu Przecięcie ArcGIS - linie / linie z wyjściem linii zapewniają nakładanie się, ale linie / linie z wyjściem punktu dają jedynie skrzyżowania.
Chris W

Na tej podstawie, aby uzyskać to, co myślę, że chcesz, być może będziesz musiał użyć obu metod. Uzyskaj skrzyżowania (linia / linia = punkt), a następnie uzyskaj nakładki (linia / linia = linia) i wyodrębnij węzły początkowe / końcowe dla tych nakładających się linii. To powinny być wszystkie punkty / węzły, których szukasz.
Chris W

Odpowiedzi:


21

Węzły:

Potrzebujesz dwóch rzeczy, punktów końcowych polilinii (bez węzłów pośrednich) i punktów przecięcia. Istnieje dodatkowy problem, niektóre punkty końcowe polilinii są również punktami przecięcia:

wprowadź opis zdjęcia tutaj

Rozwiązaniem jest użycie Pythona i modułów Shapely i Fiona

1) Przeczytaj plik kształtu:

from shapely.geometry import Point, shape
import fiona
lines = [shape(line['geometry']) for line in fiona.open("your_shapefile.shp")]

2) Znajdź punkty końcowe linii ( jak uzyskać punkty końcowe polilinii? ):

endpts = [(Point(list(line.coords)[0]), Point(list(line.coords)[-1])) for line  in lines]
# flatten the resulting list to a simple list of points
endpts= [pt for sublist in endpts  for pt in sublist] 

wprowadź opis zdjęcia tutaj

3) Oblicz przecięcia (iteracja przez pary geometrii w warstwie z modułem itertools ). Wynikiem niektórych skrzyżowań są MultiPoints i chcemy listę punktów:

import itertools
inters = []
for line1,line2 in  itertools.combinations(lines, 2):
  if  line1.intersects(line2):
    inter = line1.intersection(line2)
    if "Point" == inter.type:
        inters.append(inter)
    elif "MultiPoint" == inter.type:
        inters.extend([pt for pt in inter])
    elif "MultiLineString" == inter.type:
        multiLine = [line for line in inter]
        first_coords = multiLine[0].coords[0]
        last_coords = multiLine[len(multiLine)-1].coords[1]
        inters.append(Point(first_coords[0], first_coords[1]))
        inters.append(Point(last_coords[0], last_coords[1]))
    elif "GeometryCollection" == inter.type:
        for geom in inter:
            if "Point" == geom.type:
                inters.append(geom)
            elif "MultiPoint" == geom.type:
                inters.extend([pt for pt in geom])
            elif "MultiLineString" == geom.type:
                multiLine = [line for line in geom]
                first_coords = multiLine[0].coords[0]
                last_coords = multiLine[len(multiLine)-1].coords[1]
                inters.append(Point(first_coords[0], first_coords[1]))
                inters.append(Point(last_coords[0], last_coords[1]))

wprowadź opis zdjęcia tutaj

4) Wyeliminuj duplikaty między punktami końcowymi i punktami przecięcia (jak widać na rysunkach)

result = endpts.extend([pt for pt in inters  if pt not in endpts])

5) Zapisz wynikowy plik kształtu

from shapely.geometry import mapping
# schema of the shapefile
schema = {'geometry': 'Point','properties': {'test': 'int'}}
# creation of the shapefile
with fiona.open('result.shp','w','ESRI Shapefile', schema) as output:
    for i, pt in enumerate(result):
        output.write({'geometry':mapping(pt), 'properties':{'test':i}})

Ostateczny wynik:

wprowadź opis zdjęcia tutaj

Segmenty linii

Jeśli chcesz także segmentów między węzłami, musisz „planować” ( wykres planarny , żadne krawędzie nie krzyżują się) swój plik kształtu. Można tego dokonać za pomocą funkcji unary_union programu Shapely

from shapely.ops import unary_union
graph = unary_union(lines)

wprowadź opis zdjęcia tutaj


Dzięki @gene za szczegółową odpowiedź. Zredagowałem część, w której omawia różne typy geometrie. W moim przypadku przecięcie zwraca również linie, geometryczne zbiory itp. Ale to zależy od danych wejściowych. Moje pytanie nie było wystarczająco jasne.
ustroetz

Świetna odpowiedź. Mogę dodać, że nie trzeba wykonywać następujących czynności: result = endpts.extend([pt for pt in inters if pt not in endpts])ponieważ wydaje się, że .extendmetoda ulega modyfikacji endpt. W moim przypadku result = Nonepo tej operacji. To w endptskońcu zawiera wynik
set
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.