Soudez des segments de ligne individuels en un seul LineString en utilisant Shapely

13

J'utilise Shapely en python et je reçois un MultiLineStringavec un tas d' Linestringobjets. Je peux garantir que tous les LineStringobjets sont des lignes simples avec seulement 2 sommets et qu'ils font tous partie d'une seule ligne (pas de branches).

Je veux "relier les points" et créer un single LineString. Dois-je écrire une méthode de soudage récursif pour cela ou existe-t-il un moyen plus rapide?

Raychaser
la source

Réponses:

20

Vous pouvez utiliser shapely's ops.linemergepour accomplir ceci:

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
la source
Comment savoir quelle chaîne de caractères a été fusionnée? Je souhaite recevoir une liste comme: merged = [[line_a, line_b], [line_c]]
james
Vous pouvez parcourir une liste de vos lignes individuelles et vérifier si la nouvelle ligne fusionnée contains()les lignes individuelles. Ceux qui n'étaient pas contenus n'auraient pas été fusionnés. par exemple, merged_line.contains(line_a)qui retournerait un booléen TrueouFalse
songololo
Merci beaucoup. Comment vérifiez-vous si la ligne est contenue dans les lignes fusionnées?
James
1
ah, je n'ai pas compris que ".contains (line_a)" était une fonction pré-écrite. parfait. Merci beaucoup !
James
1
désolé, pour vous déranger encore ... mais savez-vous qui fusionner les lignes qui sont "proches" (à une certaine distance maximale les unes des autres)? Je demande parce que je vois de nombreuses lignes qui devraient être fusionnées, mais en raison d'un petit gabarit entre elles, elles ne sont pas fusionnées.
James
2

Je pense que vous pouvez le faire avec Shapely en utilisant la méthode shapely.ops.linemerge ().

Il semble qu'il puisse prendre une liste de lignes en entrée et les fusionner. J'ai utilisé la méthode «polygonize» auparavant et elle prend une liste de lignes.

Jetez un œil au document ici: http://toblerity.org/shapely/manual.html#shapely.ops.linemerge

TurboGraphxBeige
la source
1
Savez-vous comment fusionner des lignes qui sont "proches" (à une certaine distance maximale les unes des autres)?
James
polygonize_full fonctionne un peu mieux, mais j'ai obtenu des structures de données étranges en conséquence
danuker
1

shapely.ops.linemerge()a échoué pour certaines de mes lignes, j'ai donc dû le faire manuellement. Il semble échouer pour les lignes qui sont "revenues" à lui-même, c'est-à-dire passant par le même point plus d'une fois. Pour mon cas, je sais que les lignes sont dans le bon ordre, il était donc facile d'écrire une petite fonction pour les fusionner.

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)

J'espère que cela aide quelqu'un

oflyt
la source
0

shapely.ops.linemergefonctionne si les lignes sont contiguës (les "pointes" coïncident avec les "queues" des lignes constituantes), mais si elles ne sont pas contiguës (s'il y a un espace entre les pointes et les queues), elle renvoie une autre MultiLineString. Si vos lignes constituantes sont bien ordonnées (avec une ligne se terminant près du début de la ligne suivante) mais ont un écart de bout en bout, vous pouvez extraire les coordonnées et les utiliser pour créer une nouvelle ligne simple. Cette approche fonctionne également pour les lignes multiples constituées de sous-lignes plus complexes (c'est-à-dire les sous-lignes avec plus de deux points).

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
la source