Solda segmentos de linha individuais em um LineString usando Shapely

13

Estou usando Shapely em python e recebi MultiLineStringum monte de Linestringobjetos. Posso garantir que todos os LineStringobjetos são linhas simples com apenas 2 vértices e que todos fazem parte de uma única linha (sem ramificações).

Eu quero "conectar os pontos" e criar um único LineString. Preciso escrever um método de soldagem recursiva para isso ou existe uma maneira mais rápida?

Raychaser
fonte

Respostas:

20

Você pode usar shapely's ops.linemergepara fazer isso:

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))
songololo
fonte
Como posso saber qual cadeia de linhas foi mesclada? Eu quero receber uma lista como: mesclado [[line_a, line_b], [line_c]]
james
Você pode percorrer uma lista de suas linhas individuais e verificar se a nova linha mesclada é a linha contains()individual. Os que não estavam contidos não teriam sido mesclados. por exemplo, merged_line.contains(line_a)que retornaria um booleano TrueouFalse
Songololo
Muito obrigado. Como você verifica se a linha está contida nas linhas mescladas?
james
1
ah, eu não entendi que ".contains (line_a)" era uma função pré-escrita. perfeito. Muito obrigado !
james
1
desculpe incomodá-lo novamente ... mas você sabe quem mesclar linhas que estão "próximas" (a uma certa distância máxima uma da outra)? Estou perguntando porque estou vendo muitas linhas que devem ser mescladas, mas devido a um pequeno gabarito entre elas, elas não são mescladas.
james
2

Eu acho que você poderia fazê-lo com Shapely usando o método shapely.ops.linemerge ().

Parece que pode pegar uma lista de linhas como entrada e mesclá-las. Eu usei o método 'polygonize' antes e ele leva uma lista de linhas.

Dê uma olhada no documento aqui: http://toblerity.org/shapely/manual.html#shapely.ops.linemerge

TurboGraphxBeige
fonte
1
Você sabe como mesclar linhas que estão "próximas" (a uma certa distância máxima uma da outra)?
James
polygonize_full funciona um pouco melhor, mas eu tenho algumas datastructures estranhos, como resultado
danuker
1

shapely.ops.linemerge()falhou em algumas das minhas linhas, então tive que fazê-lo manualmente. Parece falhar nas linhas que "retornaram" a si mesmas, ou seja, passando pelo mesmo ponto mais de uma vez. No meu caso, eu sei que as linhas estão na ordem correta, por isso foi fácil escrever uma pequena função para mesclá-las.

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 ajude alguém

oflyt
fonte
0

shapely.ops.linemergefunciona se as linhas são contíguas ("dicas" coincidem com as "caudas" das linhas constituintes), mas se não forem contíguas (se houver um espaço entre as pontas e as caudas), ele retornará outro MultiLineString. Se suas linhas constituintes estiverem bem ordenadas (com uma linha terminando perto do início da próxima linha), mas tiverem um espaço de ponta a ponta, você poderá extrair as coordenadas e usá-las para criar uma nova linha simples. Essa abordagem também funciona para linhas múltiplas compostas por sub-linhas mais complexas (ou seja, sub-linhas com mais de dois pontos).

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