Suelde segmentos de línea individuales en un LineString usando Shapely


13

Estoy usando Shapely en python y me dan un MultiLineStringcon un montón de Linestringobjetos. Puedo garantizar que todos los LineStringobjetos son líneas simples con solo 2 vértices y que todos forman parte de una sola línea (sin ramas).

Quiero "conectar los puntos" y crear uno solo LineString. ¿Necesito escribir un método de soldadura recursiva para esto o hay una forma más rápida?

Respuestas:


20

Puede usar shapely's ops.linemergepara lograr esto:

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

¿Cómo puedo saber qué cadena lineal se fusionó? Quiero recibir una lista como: fusionada = [[line_a, line_b], [line_c]]
james

Puede recorrer una lista de sus líneas individuales y verificar si la nueva línea combinada contains()las líneas individuales. Los que no están contenidos no se habrían fusionado. por ejemplo, merged_line.contains(line_a)que devolvería un booleano TrueoFalse
songololo

muchas gracias. ¿Cómo verifica si la línea está contenida en merged_lines?
james

1
ah, no entendí que ".contains (line_a)" era una función preescrita. Perfecto. Muchas gracias !
James

1
lo siento, para molestarlo nuevamente ... pero ¿sabe a quién fusionar las líneas que están "cerca" (dentro de una cierta distancia máxima entre sí)? Pregunto porque veo muchas líneas que deberían fusionarse, pero debido a una pequeña separación entre ellas, no se fusionan.
James

2

Creo que podrías hacerlo con Shapely usando el método shapely.ops.linemerge ().

Parece que podría tomar una lista de líneas como entrada y fusionarlas. Utilicé el método 'polygonize' antes y toma una lista de líneas.

Eche un vistazo al documento aquí: http://toblerity.org/shapely/manual.html#shapely.ops.linemerge


1
¿Sabes cómo combinar líneas que están "cerca" (dentro de una cierta distancia máxima entre sí)?
James

polygonize_full funciona algo mejor, pero como resultado obtuve algunas estructuras de datos extrañas
danuker

1

shapely.ops.linemerge()falló en algunas de mis líneas, así que tuve que hacerlo manualmente. Parece fallar para las líneas que "regresaron" a sí mismas, es decir, pasando por el mismo punto más de una vez. Para mi caso, sé que las líneas están en el orden correcto, por lo que fue fácil escribir una pequeña función para fusionarlas.

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)

Espero que ayude a alguien


0

shapely.ops.linemergefunciona si las líneas son contiguas (las "puntas" coinciden con las "colas" de las líneas constituyentes), pero si no son contiguas (si hay un espacio entre las puntas y las colas), devuelve otra MultiLineString. Si sus líneas constituyentes están bien ordenadas (con una línea que termina cerca del comienzo de la línea siguiente) pero tienen un espacio de punta a cola, puede extraer las coordenadas y usarlas para hacer una nueva línea simple. Este enfoque también funciona para líneas múltiples hechas de sublíneas más complejas (es decir, sublíneas con más de dos puntos).

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])
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.