web-dev-qa-db-fra.com

Manière plus rapide d'intersection de polygone avec galbée

J'ai un grand nombre de polygones (~ 100000) et j'essaie de trouver un moyen intelligent de calculer leur zone d'intersection avec une grille régulière.

Actuellement, je crée les polygones et les cellules de la grille en utilisant galbés (en fonction de leurs coordonnées de coin). Ensuite, en utilisant une simple boucle for, je passe par chaque polygone et le compare aux cellules de grille voisines.

Juste un petit exemple pour illustrer les polygones/cellules de la grille.

from shapely.geometry import box, Polygon
# Example polygon 
xy = [[130.21001, 27.200001], [129.52, 27.34], [129.45, 27.1], [130.13, 26.950001]]
polygon_shape = Polygon(xy)
# Example grid cell
gridcell_shape = box(129.5, -27.0, 129.75, 27.25)
# The intersection
polygon_shape.intersection(gridcell_shape).area

(BTW: les cellules de la grille ont les dimensions 0,25x0,25 et les polygones 1x1 au maximum)

En fait, c'est assez rapide pour un combo polygone/cellule de grille individuel avec environ 0,003 secondes. Cependant, l'exécution de ce code sur une énorme quantité de polygones (chacun peut intersecter des dizaines de cellules de grille) prend environ 15+ minutes (jusqu'à 30+ minutes selon le nombre de cellules de grille qui se croisent) sur ma machine, ce qui n'est pas acceptable. Malheureusement, je ne sais pas comment il est possible d'écrire un code d'intersection de polygones pour obtenir la zone de chevauchement. Avez-vous des conseils? Existe-t-il une alternative à galbée?

37
HyperCube

Pensez à utiliser Rtree pour identifier les cellules de la grille qu'un polygone peut recouper. De cette façon, vous pouvez supprimer la boucle for utilisée avec le tableau de lat/lons, qui est probablement la partie lente.

Structurez votre code quelque chose comme ceci:

from shapely.ops import cascaded_union
from rtree import index
idx = index.Index()

# Populate R-tree index with bounds of grid cells
for pos, cell in enumerate(grid_cells):
    # assuming cell is a shapely object
    idx.insert(pos, cell.bounds)

# Loop through each Shapely polygon
for poly in polygons:
    # Merge cells that have overlapping bounding boxes
    merged_cells = cascaded_union([grid_cells[pos] for pos in idx.intersection(poly.bounds)])
    # Now do actual intersection
    print poly.intersection(merged_cells).area
56
Mike T

Il semble que le The Shapely User Manual soit plutôt obsolète, mais depuis 2013/2014, Shapely a strtree.py avec la classe STRtree. Je l'ai utilisé et cela semble bien fonctionner.

Voici un extrait de la docstring:

STRtree est un arbre R créé à l'aide de l'algorithme Sort-Tile-Recursive. STRtree prend une séquence d'objets géométriques comme paramètre d'initialisation. Après l'initialisation, la méthode de requête peut être utilisée pour effectuer une requête spatiale sur ces objets.

>>> from shapely.geometry import Polygon
>>> polys = [ Polygon(((0, 0), (1, 0), (1, 1))), Polygon(((0, 1), (0, 0), (1, 0))), Polygon(((100, 100), (101, 100), (101, 101))) ]
>>> s = STRtree(polys)
>>> query_geom = Polygon(((-1, -1), (2, 0), (2, 2), (-1, 2)))
>>> result = s.query(query_geom)
>>> polys[0] in result
True
16
Phil