13 votos

Conseguir la intersección de múltiples polígonos de manera eficiente en Python

Me gustaría obtener la intersección de múltiples polígonos. Usando el sistema de Python shapely puedo encontrar la intersección de dos polígonos utilizando el intersection función. ¿Existe una función eficiente similar para obtener la intersección de múltiples polígonos?

Aquí hay un fragmento de código para entender lo que quiero decir:

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) 

Una intersección de dos círculos puede ser encontrada por circle1.intersection(circle2) . Puedo encontrar la intersección de los tres círculos por circle1.intersection(circle2).intersection(circle3) . Sin embargo, este enfoque no es vendible a un gran número de polígonos ya que requiere cada vez más código. Me gustaría una función que tomara un número arbitrario de polígonos y devolviera su intersección.

0 votos

Estoy pensando en almacenar las coordenadas en un diccionario y hacer un bucle a través de él mientras se utiliza from itertools import combinations. Voy a publicar pronto

0 votos

¿Qué quiere decir con "sus intersecciones"? ¿Se refiere a todas las áreas que se cruzan con al menos otro polígono, o a las áreas que todo ¿se cruzan las entradas?

0 votos

Me refiero a la intersección de todos los polígonos, no a al menos uno.

9voto

Nikola Puntos 21

Un posible enfoque podría ser considerar la combinación de pares de polígonos, sus intersecciones y finalmente la unión de todas las intersecciones mediante una unión en cascada (como se sugiere aquí ) :

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 enfoque más eficiente debería utilizar un índice espacial, como Rtree para tratar muchas geometrías (no es el caso de los tres círculos):

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

0 votos

No creo que esto haga lo que el OP quiere. Devuelve las áreas que al menos 2 polígonos, mientras que el PO sólo busca áreas cubiertas por todo los polígonos del conjunto. Véase la aclaración en los comentarios.

4voto

Wartin Puntos 854

¿Por qué no utilizar una iteración o recursividad? algo así como :

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

2voto

Saad Puntos 57

Prueba este código. Es bastante simple en su concepto y creo que te da lo que estás buscando.

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

y si quieres que la salida se almacene como un shapefile utiliza 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)})

esta salida -

enter image description here

3 votos

No creo que esto haga lo que el OP quiere. Devuelve las áreas que al menos 2 polígonos, mientras que el PO sólo busca áreas cubiertas por todo los polígonos del conjunto. Ver aclaración en los comentarios. Además, k y v son malas opciones para los nombres de las variables en su dict de comprensión. Cada una de estas variables se refiere a diferentes elementos de dic.items() , no un par clave-valor. Algo así como a, b sería menos engañoso.

1 votos

Ohh ok si no entendí lo que quiso decir

0 votos

Y se ha entendido bien lo de mis elecciones de k,v simplemente utilizo automáticamente k,v cuando hago un bucle en un diccionario no lo he pensado mucho

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X