¿Intersección de líneas para obtener cruces usando Python con QGIS?

10

Tengo un conjunto de líneas que representan líneas de autobús. Algunas de las líneas se superponen y toman los mismos caminos.

ingrese la descripción de la imagen aquí

Soy capaz de extraer los nodos. ingrese la descripción de la imagen aquí

Sin embargo, estoy interesado en extraer solo cruces como este: ingrese la descripción de la imagen aquí

¿Cómo puedo hacer esto? Estoy buscando formas con QGIS o Python.

Probé el método de intersección de GDAL Python, pero esto básicamente me devuelve solo los vértices.

El método de intersecciones de línea de QGIS me devuelve los cruces si se cruzan dos líneas. Sin embargo, en el caso de que dos líneas de autobús recorran gran parte de su ruta en el mismo camino, no me da que señalen dónde se fusionan.

ustroetz
fuente
¿Has probado la herramienta de intersección de línea en QGIS: Herramienta de análisis vectorial> Intersecciones de línea ... No te dará el final y los nodos iniciales de una línea, sino todas las intersecciones.
Jakob
Sí, escribí sobre esto en la pregunta.
ustroetz
No estoy claro sobre lo que está preguntando, en parte porque todas las líneas están simbolizadas de la misma manera en sus imágenes: no puedo distinguir las diferentes rutas para comprender qué nodos está viendo o por qué hay tantos en el segunda imagen ¿Las rutas coinciden en las carreteras? ¿Son todos segmentos de línea de dos puntos o polilíneas continuas? Observo que el comportamiento que describe es el mismo que el de la herramienta Intersecar de ArcGIS : las líneas / líneas con salida de líneas le dan superposición, pero las líneas / líneas con salida de punto solo dan cruces.
Chris W
En base a eso, para obtener lo que creo que quieres, es posible que tengas que usar ambos métodos. Obtenga los cruces (línea / línea = punto) y luego obtenga las superposiciones (línea / línea = línea) y extraiga los nodos de inicio / final para esas líneas superpuestas. Esos deberían ser todos los puntos / nodos que estás buscando.
Chris W

Respuestas:

20

Los nodos:

Desea dos cosas, los puntos finales de las polilíneas (sin nodos intermedios) y los puntos de intersección. Hay un problema adicional, algunos puntos finales de polilíneas también son puntos de intersección:

ingrese la descripción de la imagen aquí

Una solución es utilizar Python y los módulos Shapely y Fiona.

1) Lea el archivo de forma:

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

2) Encuentre los puntos finales de las líneas ( ¿cómo se obtendrían los puntos finales de una polilínea? ):

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] 

ingrese la descripción de la imagen aquí

3) Calcule las intersecciones (iterando a través de pares de geometrías en la capa con el módulo itertools ). El resultado de algunas intersecciones son MultiPoints y queremos una lista de puntos:

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

ingrese la descripción de la imagen aquí

4) Elimine los duplicados entre los puntos finales y los puntos de intersección (como puede ver en las figuras)

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

5) Guarde el archivo de forma resultante

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

Resultado final:

ingrese la descripción de la imagen aquí

Los segmentos de línea

Si desea también los segmentos entre los nodos, debe "planarizar" ( Gráfico plano , sin bordes cruzados) su archivo de forma. Esto se puede hacer por el unary_union función del bien proporcionado

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

ingrese la descripción de la imagen aquí

gene
fuente
Gracias @gene por la respuesta detallada. Edité la parte donde va sobre los diferentes tipos de geometría. En mi caso, la intersección también devuelve líneas, colecciones de geometría, etc. Pero esto depende de los datos de entrada. No fui lo suficientemente claro en mi pregunta.
ustroetz
Gran respuesta. Podría agregar que no es necesario hacer lo siguiente: result = endpts.extend([pt for pt in inters if pt not in endpts])ya que parece que el .extendmétodo se modifica endpt. En mi caso result = Nonedespués de esa operación. Es lo endptsque termina conteniendo el conjunto de resultados
user32882