การตัดเส้นเพื่อรับการข้ามโดยใช้ Python กับ QGIS?


10

ฉันมีชุดของเส้นที่แสดงถึงรถบัส เส้นบางเส้นทับซ้อนกันและใช้ถนนเส้นเดียวกัน

ป้อนคำอธิบายรูปภาพที่นี่

ฉันสามารถสกัดโหนด ป้อนคำอธิบายรูปภาพที่นี่

อย่างไรก็ตามฉันสนใจที่จะแยกวกเท่านั้นเช่นนี้: ป้อนคำอธิบายรูปภาพที่นี่

ฉันจะทำสิ่งนี้ได้อย่างไร ฉันกำลังมองหาวิธีด้วย QGIS หรือ Python

ฉันลองใช้วิธีการตัดกันจาก GDAL Python แต่สิ่งนี้จะให้ผลตอบแทนฉันในจุดสูงสุดเท่านั้น

วิธีเส้นแยกจาก QGIS ผลตอบแทนที่ฉันข้ามถ้าสองเส้นข้าม อย่างไรก็ตามในกรณีที่รถบัสสองสายวิ่งไปไกลกว่าเส้นทางของพวกเขาบนถนนสายเดียวกันมันก็ไม่ได้ทำให้ฉันเห็นว่าพวกเขาอยู่ตรงไหน


คุณได้ลองใช้เครื่องมือการตัดกันเส้นใน QGIS: เครื่องมือวิเคราะห์เวกเตอร์> การแยกบรรทัด ... มันจะไม่ทำให้คุณสิ้นสุดและเริ่มต้นโหนดของบรรทัด แต่แยกทั้งหมด
จาคอบ

ใช่ฉันเขียนเกี่ยวกับสิ่งนี้ในคำถาม
ustroetz

ฉันไม่ชัดเจนเกี่ยวกับสิ่งที่คุณถามส่วนหนึ่งเป็นเพราะเส้นทั้งหมดเป็นสัญลักษณ์ในภาพของคุณ - ฉันไม่สามารถบอกเส้นทางที่แตกต่างกันเพื่อทำความเข้าใจว่าคุณกำลังมองหาโหนดใดหรือทำไมมีจำนวนมากใน ภาพที่สอง เส้นทางบังเอิญบนถนนหรือไม่? พวกมันคือส่วนของเส้นสองจุดหรือโพลีนต่อเนื่องหรือไม่? ฉันสังเกตว่าพฤติกรรมที่คุณอธิบายนั้นเหมือนกับเครื่องมือตัดของ ArcGIS - เส้น / เส้นที่มีเอาต์พุตของเส้นทำให้คุณเหลื่อมกัน แต่เส้น / เส้นที่มีจุดออกให้การข้ามเท่านั้น
Chris W

ตามนั้นเพื่อให้ได้สิ่งที่ฉันคิดว่าคุณต้องการคุณอาจต้องใช้ทั้งสองวิธี รับการข้าม (บรรทัด / บรรทัด = จุด) จากนั้นรับการทับซ้อน (บรรทัด / บรรทัด = บรรทัด) และแยกโหนดเริ่มต้น / สิ้นสุดสำหรับเส้นทับซ้อนเหล่านั้น สิ่งเหล่านั้นควรเป็นจุด / โหนดทั้งหมดที่คุณกำลังมองหา
Chris W

คำตอบ:


21

โหนด:

คุณต้องการสองสิ่งจุดสิ้นสุดของ polylines (ไม่มีโหนดกลาง) และจุดตัดกัน มีปัญหาเพิ่มเติมจุดสิ้นสุด polylines บางจุดก็เป็นจุดตัด:

ป้อนคำอธิบายรูปภาพที่นี่

ทางออกคือการใช้ Python และโมดูลShapelyและFiona

1) อ่าน shapefile:

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

2) ค้นหาจุดสิ้นสุดของเส้น ( หนึ่งจะได้รับจุดสิ้นสุดของ polyline อย่างไร ):

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] 

ป้อนคำอธิบายรูปภาพที่นี่

3) คำนวณจุดตัด (วนซ้ำผ่านรูปทรงเรขาคณิตคู่ในชั้นด้วยโมดูลitertools ) ผลลัพธ์ของการแยกเป็น MultiPoint และเราต้องการรายการคะแนน:

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

ป้อนคำอธิบายรูปภาพที่นี่

4) กำจัดรายการที่ซ้ำกันระหว่างจุดสิ้นสุดและจุดตัด (ตามที่คุณเห็นในรูป)

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

5) บันทึก shapefile ผลลัพธ์

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

ผลสุดท้าย:

ป้อนคำอธิบายรูปภาพที่นี่

ส่วนของเส้นตรง

ถ้าคุณต้องการเซกเมนต์ระหว่างโหนดคุณต้อง "planarize" ( Planar Graphไม่มีขอบตัดกัน) shapefile ของคุณ สิ่งนี้สามารถทำได้โดยฟังก์ชันunary_union ของ Shapely

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

ป้อนคำอธิบายรูปภาพที่นี่


ขอบคุณ @Gene สำหรับคำตอบโดยละเอียด ฉันแก้ไขส่วนที่มันไปกับรูปทรงเรขาคณิตที่แตกต่างกัน ในกรณีของฉันการตัดกันก็ส่งคืนเส้นเรขาคณิตคอลเลกชัน ฯลฯ แต่สิ่งนี้ขึ้นอยู่กับข้อมูลอินพุต ฉันยังไม่ชัดเจนพอในคำถามของฉัน
ustroetz

คำตอบที่ดี ฉันอาจเพิ่มว่ามันไม่จำเป็นที่จะต้องทำต่อไปนี้: result = endpts.extend([pt for pt in inters if pt not in endpts])เพราะมันปรากฏว่าปรับเปลี่ยนวิธีการ.extend endptในกรณีของฉันresult = Noneหลังจากการดำเนินการนั้น มันเป็นendptsที่สิ้นสุดที่มีการตั้งค่าผลลัพธ์
user32882
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.