เชื่อมส่วนของแต่ละบรรทัดเป็นหนึ่งใน LineString โดยใช้หุ่นดี


13

ฉันใช้ Shapely ในงูหลามและฉันได้รับMultiLineStringของLinestringมากมาย ฉันรับประกันได้ว่าLineStringวัตถุทั้งหมดนั้นเป็นเส้นตรงที่มีจุดยอดเพียง 2 จุดและพวกมันทั้งหมดเป็นส่วนหนึ่งของเส้นเดียว (ไม่มีกิ่งก้านสาขา)

ฉันต้องการ "การเชื่อมต่อที่จุด" LineStringและสร้างเดียว ฉันต้องเขียนวิธีการเชื่อมแบบเรียกซ้ำเพื่อทำสิ่งนี้หรือมีวิธีที่เร็วกว่านี้หรือไม่?

คำตอบ:


20

คุณสามารถใช้shapely's ops.linemergeเพื่อบรรลุนี้:

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

ฉันจะรู้ได้อย่างไรว่ามีการรวมแถบใด ฉันต้องการรับรายการที่ชอบ: ผสาน = [[line_a, line_b], [line_c]]
james

คุณสามารถวนรอบรายการของแต่ละบรรทัดของคุณและตรวจสอบว่าบรรทัดที่ผสานใหม่contains()ของแต่ละบรรทัด สิ่งที่ไม่ได้มีอยู่จะไม่ถูกรวมเข้าด้วยกัน เช่นmerged_line.contains(line_a)ซึ่งจะส่งคืนบูลีนTrueหรือFalse
songololo

ขอบคุณมาก. คุณจะตรวจสอบว่ามีบรรทัดอยู่ในการผสาน _lines ได้อย่างไร?
James

1
อาฉันไม่เข้าใจว่า ".contain (line_a)" เป็นฟังก์ชันที่เขียนไว้ล่วงหน้า สมบูรณ์ ขอบคุณมาก !
James

1
ขอโทษที่รบกวนคุณอีกครั้ง ... แต่คุณรู้หรือไม่ว่าใครที่จะรวมบรรทัดที่ "ปิด" (ภายในระยะทางสูงสุดจากกัน) ฉันถามเพราะฉันเห็นหลายบรรทัดที่ควรจะผสาน แต่เนื่องจากช่องว่างเล็ก ๆ ระหว่างพวกเขาพวกเขาจะไม่รวม
James

2

ฉันคิดว่าคุณสามารถทำได้ด้วย Shapely โดยใช้วิธี shapely.ops.linemerge ()

ดูเหมือนว่าจะใช้รายการของบรรทัดเป็นอินพุตและรวมเข้าด้วยกัน ฉันใช้วิธี 'รูปหลายเหลี่ยม' มาก่อนและใช้รายการของเส้น

ดูเอกสารที่นี่: http://toblerity.org/shapely/manual.html#shapely.ops.linemerge


1
คุณรู้วิธีรวมเส้นที่เป็น "ปิด" (ภายในระยะทางสูงสุดจากกันและกัน) หรือไม่?
James

polygonize_full ทำงานได้ดีกว่า แต่ฉันได้รับโครงสร้างข้อมูลที่แปลกประหลาดบางอย่าง
danuker

1

shapely.ops.linemerge()ล้มเหลวสำหรับบางบรรทัดของฉันดังนั้นฉันต้องทำด้วยตนเอง ดูเหมือนว่าจะล้มเหลวสำหรับบรรทัดที่ "คืน" ให้กับตัวเองกล่าวคือจะผ่านจุดเดียวกันมากกว่าหนึ่งครั้ง สำหรับกรณีของฉันฉันรู้ว่าบรรทัดอยู่ในลำดับที่ถูกต้องดังนั้นจึงเป็นเรื่องง่ายที่จะเขียนฟังก์ชั่นขนาดเล็กเพื่อรวมพวกเขา

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)

หวังว่าจะช่วยใครซักคน


0

shapely.ops.linemergeใช้งานได้หากบรรทัดต่อเนื่องกัน ("เคล็ดลับ" ตรงกับ "ก้อย" ของเส้นที่เป็นส่วนประกอบ) แต่ถ้ามันไม่ต่อเนื่องกัน (หากมีช่องว่างระหว่างเคล็ดลับและก้อย) มันจะส่งกลับ MultiLineString อีกอันหนึ่ง หากบรรทัดที่เป็นส่วนประกอบของคุณมีการเรียงลำดับอย่างดี (โดยมีหนึ่งบรรทัดที่ลงท้ายด้วยใกล้กับจุดเริ่มต้นของบรรทัดถัดไป) แต่มีช่องว่างแบบปลายถึงหางคุณสามารถแยกพิกัดและใช้เส้นเหล่านั้นสร้างบรรทัดใหม่แบบง่าย วิธีการนี้ใช้ได้กับหลายสายที่ทำจากซับไลน์ที่ซับซ้อนมากขึ้น (เช่นซับไลน์ที่มีมากกว่าสองจุด)

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])
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.