Ефективне отримання перетину декількох багатокутників у 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). Однак такий підхід не піддається великій кількості багатокутників, оскільки він вимагає все більше коду. Я хотів би функцію, яка займає довільну кількість многокутників і повертає їх перетин.


Я думаю, можливо, збережіть координати у словнику та перегляньте його, використовуючи комбінації з імпорту itertools. Я опублікую незабаром
ziggy

Що ви маєте на увазі під їх перехрестями? Ви маєте на увазі всі області, що перетинаються принаймні з одним іншим багатокутником, або області, які перетинаються всі входи?
jpmc26

Я маю на увазі перетин усіх багатокутників, принаймні, не одного.
осколок

Ви повинні уточнити це вище (можливо, на прикладі результату). Я впевнений, що більшість відповідей не так поводяться. (І той факт, що кілька відповідачів неправильно зрозуміли, є достатньою доказовою ознакою, що питання потребує уточнення.)
jpmc26

1
@ jpmc26 Я щойно додав оновлення до своєї відповіді, де використовується rtree. Підхід зараз більш ефективний та масштабований. Сподіваюся, це допомагає!
Антоніо Фальчіано

Відповіді:


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

Я не вірю, що це робить те, що хоче ОП. Він повертає області, які охоплюють щонайменше 2 багатокутники, тоді як ОП шукає лише області, охоплені всіма багатокутниками у наборі. Пояснення див. У коментарях.
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

і якщо ви хочете, щоб вихід зберігався як файл форми, використовуйте 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
Я не вірю, що це робить те, що хоче ОП. Він повертає області, які охоплюють щонайменше 2 багатокутники, тоді як ОП шукає лише області, охоплені всіма багатокутниками у наборі. Пояснення див. У коментарях. Крім того, kі vце поганий вибір варіантів імен у ваших dictрозуміннях. Кожна з цих змінних посилається на різні елементи dic.items(), а не пара ключ-значення. Щось подібне a, bбуло б менш оманливим.
jpmc26

1
ой гаразд, так, я не зрозумів, що він має на увазі
зиггі

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.