การหาจุดหลายเหลี่ยมหลายจุดใน Python อย่างมีประสิทธิภาพ


12

ฉันอยากได้จุดตัดของรูปหลายเหลี่ยมหลายอัน ใช้shapelyแพ็คเกจของ Python ฉันสามารถหาจุดตัดของรูปหลายเหลี่ยมสองรูปได้โดยใช้intersectionฟังก์ชัน มีฟังก์ชั่นที่มีประสิทธิภาพคล้ายกันเพื่อให้ได้จุดตัดของรูปหลายเหลี่ยมหลายรูปแบบหรือไม่?

นี่คือข้อมูลโค้ดเพื่อทำความเข้าใจสิ่งที่ฉันหมายถึง:

from shapely.geometry import Point

coord1 = ( 0,0 )
point1 = Point(coord1)
circle1 = point1.buffer(1)

coord2 = ( 1,1 )
point2 = Point(coord2)
circle2 = point2.buffer(1)

coord3 = ( 1,0 )
point3 = Point(coord3)
circle3 = point3.buffer(1) 

circle1.intersection(circle2)สี่แยกของวงกลมสองวงสามารถพบได้โดย ฉันสามารถหาจุดตัดของทั้งสามวงกลมcircle1.intersection(circle2).intersection(circle3)ได้ อย่างไรก็ตามวิธีนี้ไม่สามารถขายได้กับรูปหลายเหลี่ยมจำนวนมากเนื่องจากต้องใช้รหัสมากขึ้น ฉันต้องการฟังก์ชันที่ใช้รูปหลายเหลี่ยมหลายรูปแบบโดยพลการและคืนค่าจุดตัดของพวกมัน


ฉันคิดว่าอาจเก็บ coords ในพจนานุกรมและวนรอบมันในขณะที่ใช้จาก itertools นำเข้าชุดค่าผสม ฉันจะโพสต์เร็ว ๆ นี้
ziggy

คุณหมายถึงอะไรโดย "ทางแยกของพวกเขา"? คุณหมายถึงพื้นที่ทั้งหมดที่ตัดกันด้วยรูปหลายเหลี่ยมอย่างน้อยหนึ่งรูปแบบหรือพื้นที่ที่อินพุตทั้งหมดตัดกันหรือไม่
jpmc26

ฉันหมายถึงจุดตัดของรูปหลายเหลี่ยมทั้งหมดไม่ใช่อย่างน้อยหนึ่งอัน
เสี้ยน

คุณควรชี้แจงเรื่องนี้ด้านบน (อาจมีตัวอย่างผลลัพธ์) ฉันค่อนข้างแน่ใจว่าคำตอบส่วนใหญ่จะไม่ทำงานตามที่คุณต้องการ (และความจริงที่ว่าผู้ตอบหลายคนเข้าใจผิดเป็นหลักฐานเพียงพอที่คำถามนั้นต้องการการชี้แจง)
jpmc26

1
@ jpmc26 ฉันเพิ่งเพิ่มการอัปเดตไปยังคำตอบของฉันเมื่อใช้ rtree วิธีนี้มีประสิทธิภาพมากขึ้นและสามารถปรับขนาดได้ในขณะนี้ หวังว่านี่จะช่วยได้!
Antonio Falciano

คำตอบ:


7

วิธีการหนึ่งที่เป็นไปได้คือการพิจารณาการรวมกันของรูปหลายเหลี่ยมคู่ทางแยกของพวกเขาและในที่สุดการรวมตัวกันของทางแยกทั้งหมดผ่านสหภาพเรียงซ้อน (เช่นแนะนำที่นี่ ):

from shapely.geometry import Point
from shapely.ops import cascaded_union
from itertools import combinations

circles = [
    Point(0,0).buffer(1),
    Point(1,0).buffer(1),
    Point(1,1).buffer(1),
]

intersection = cascaded_union(
    [a.intersection(b) for a, b in combinations(circles, 2)]
)
print intersection

วิธีที่มีประสิทธิภาพมากขึ้นควรใช้ดัชนีเชิงพื้นที่เช่นRtreeเพื่อจัดการกับรูปทรงเรขาคณิตจำนวนมาก (ไม่ใช่กรณีของวงกลมสามวง):

from shapely.geometry import Point
from shapely.ops import cascaded_union
from rtree import index

circles = [
    Point(0,0).buffer(1),
    Point(1,0).buffer(1),
    Point(1,1).buffer(1),
]
intersections = []
idx = index.Index()

for pos, circle in enumerate(circles):
    idx.insert(pos, circle.bounds)

for circle in circles:
    merged_circles = cascaded_union([circles[pos] for pos in idx.intersection(circle.bounds) if circles[pos] != circle])
    intersections.append(circle.intersection(merged_circles))

intersection = cascaded_union(intersections)
print intersection

ฉันไม่เชื่อว่านี่เป็นสิ่งที่ OP ต้องการ มันให้พื้นที่ที่ครอบคลุมรูปหลายเหลี่ยมอย่างน้อย 2รูปในขณะที่ OP กำลังมองหาพื้นที่ที่ครอบคลุมรูปหลายเหลี่ยมทั้งหมดในชุดเท่านั้น ดูคำชี้แจงในความคิดเห็น
jpmc26

3

ทำไมไม่ใช้การทำซ้ำหรือเรียกซ้ำ? สิ่งที่ต้องการ :

from shapely.geometry import Point

def intersection(circle1, circle2):
    return circle1.intersection(circle2)

coord1 = ( 0,0 )
point1 = Point(coord1)
circle1 = point1.buffer(1)

coord2 = ( 1,1 )
point2 = Point(coord2)    
circle2 = point2.buffer(1)


coord3 = ( 1,0 )
point3 = Point(coord3)
circle3 = point3.buffer(1)
circles = [circle1, circle2, circle3]
intersectionResult = None

for j, circle  in enumerate(circles[:-1]):

    #first loop is 0 & 1
    if j == 0:
        circleA = circle
        circleB = circles[j+1]
     #use the result if the intersection
    else:
        circleA = intersectionResult
        circleB = circles[j+1]
    intersectionResult = intersection(circleA, circleB)

result= intersectionResult

2

ให้รหัสนี้ยิง มันเป็นแนวคิดที่เรียบง่ายและฉันเชื่อว่าจะทำให้คุณได้รับสิ่งที่คุณกำลังมองหา

from shapely.geometry import Point
from itertools import combinations
dic ={}
dic['coord1']=Point(0,0).buffer(1)
dic['coord2']=Point(1,1).buffer(1)
dic['coord3']=Point(1,0).buffer(1)
inter = {k[0]+v[0]:k[1].intersection(v[1]) for k,v in combinations(dic.items(),2)}
print inter

และถ้าคุณต้องการเก็บเอาท์พุทเป็น shapefile ให้ใช้ fiona:

from shapely.geometry import Point,mapping
import fiona
from itertools import combinations
schema = {'geometry': 'Polygon', 'properties': {'Place': 'str'}}
dic ={}
dic['coord1']=Point(0,0).buffer(1)
dic['coord2']=Point(1,1).buffer(1)
dic['coord3']=Point(1,0).buffer(1)
inter = {k[0]+v[0]:k[1].intersection(v[1]) for k,v in combinations(dic.items(),2)}
print inter
with fiona.open(r'C:\path\abid', "w", "ESRI Shapefile", schema) as output:
    for x,y in inter.items():
        output.write({'properties':{'Place':x},'geometry':mapping(y)})

ผลลัพธ์นี้ -

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


3
ฉันไม่เชื่อว่านี่เป็นสิ่งที่ OP ต้องการ มันให้พื้นที่ที่ครอบคลุมรูปหลายเหลี่ยมอย่างน้อย 2รูปในขณะที่ OP กำลังมองหาพื้นที่ที่ครอบคลุมรูปหลายเหลี่ยมทั้งหมดในชุดเท่านั้น ดูคำชี้แจงในความคิดเห็น นอกจากนี้kและvเป็นตัวเลือกที่แย่สำหรับชื่อตัวแปรในdictความเข้าใจของคุณ ตัวแปรเหล่านั้นแต่ละตัวอ้างถึงองค์ประกอบต่าง ๆ ของdic.items()ไม่ใช่คู่คีย์ - ค่า สิ่งที่ชอบa, bจะทำให้เข้าใจผิดน้อยลง
jpmc26

1
โอ้ไม่เป็นไรฉันไม่เข้าใจว่าเขาหมายถึงอะไร
ziggy

และเป็นจุดที่ดีเกี่ยวกับการถ่าย k เลือกวีของฉัน - ฉันเพียงแค่ใช้โดยอัตโนมัติ k, โวลต์เมื่อบ่วงผ่าน dictionary..didnt สามารถให้มันมากคิด
Ziggy
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.