Ottenere in modo efficiente l'intersezione di più poligoni in Python


12

Vorrei ottenere l'intersezione di più poligoni. Usando il shapelypacchetto di Python , posso trovare l'intersezione di due poligoni usando la intersectionfunzione. Esiste una funzione efficiente simile per ottenere l'intersezione di più poligoni?

Ecco uno snippet di codice per capire cosa intendo:

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) 

È possibile trovare un'intersezione di due cerchi circle1.intersection(circle2). Riesco a trovare l'intersezione di tutti e tre i cerchi di circle1.intersection(circle2).intersection(circle3). Tuttavia, questo approccio non è vendibile a un gran numero di poligoni in quanto richiede sempre più codice. Vorrei una funzione che prende un numero arbitrario di poligoni e restituisce la loro intersezione.


sto pensando forse di memorizzare i coords in un dizionario e di eseguirne il loop mentre si utilizza da itertools combinazioni di importazione.
Pubblicherò

Cosa intendi con "loro incroci"? Intendi tutte le aree che si intersecano con almeno un altro poligono o le aree che si intersecano con tutti gli input?
jpmc26,

Intendo l'intersezione di tutti i poligoni, non almeno uno.
scheggia

Dovresti chiarire questo sopra (forse con un output di esempio). Sono abbastanza sicuro che la maggior parte delle risposte non si comporti come desideri. (E il fatto che diversi rispondenti abbiano frainteso è una prova sufficiente che la domanda necessita di chiarimenti.)
jpmc26

1
@ jpmc26 Ho appena aggiunto un aggiornamento alla mia risposta in cui viene utilizzato rtree. L'approccio è ora più efficiente e scalabile. Spero che questo ti aiuti!
Antonio Falciano,

Risposte:


7

Un possibile approccio potrebbe essere quello di considerare la combinazione di coppie di poligoni, le loro intersezioni e infine l'unione di tutte le intersezioni tramite un'unione a cascata (come suggerito qui ):

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

Un approccio più efficiente dovrebbe utilizzare un indice spaziale, come Rtree , per gestire molte geometrie (non nel caso dei tre cerchi):

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

Non credo che questo faccia ciò che l'OP vuole. Restituisce le aree coperte da almeno 2 poligoni, mentre l'OP sta cercando solo le aree coperte da tutti i poligoni nel set. Vedi chiarimenti nei commenti.
jpmc26,

3

Perché non usare un'iterazione o ricorsività? qualcosa di simile a :

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

Dai un colpo a questo codice. è piuttosto semplice nel concetto e credo che ti dia quello che stai cercando.

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

e se vuoi che l'output sia archiviato come shapefile usa 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)})

questo produce -

inserisci qui la descrizione dell'immagine


3
Non credo che questo faccia ciò che l'OP vuole. Restituisce le aree coperte da almeno 2 poligoni, mentre l'OP sta cercando solo le aree coperte da tutti i poligoni nel set. Vedi chiarimenti nei commenti. Inoltre, ke vsono scelte sbagliate per i nomi delle variabili nelle tue dictcomprensioni. Ciascuna di queste variabili fa riferimento a diversi elementi di dic.items(), non una coppia chiave-valore. Qualcosa del genere a, bsarebbe meno fuorviante.
jpmc26,

1
oh, va bene, sì, non ho capito cosa intendesse
ziggy,

e punto ben preso circa le mie scelte di k, v - uso solo automaticamente k, v quando faccio un ciclo in un dizionario ... non ci ho pensato molto
ziggy
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.