Séparez les polygones en fonction de l'intersection à l'aide de PostGIS

36

J'ai une table de polygones PostGIS où certains s'entrecroisent. C'est ce que j'essaie de faire:

  • Pour un polygone donné sélectionné par id, donnez-moi tous les polygones qui se croisent. Fondamentalement,select the_geom from the_table where ST_Intersects(the_geom, (select the_geom from the_table where source_id = '123'))
  • À partir de ces polygones, je dois créer un nouveau polygone tel que l'intersection devienne un nouveau polygone. Donc, si le polygone A coupe le polygone B, j'aurai 3 nouveaux polygones: A moins AB, AB et B moins AB.

Des idées?

atogle
la source
1
Hmmm, je pense que vous voyez où vous voulez en venir, mais un simple graphique pourrait faire des merveilles pour m'aider (et aider les autres) à voir exactement ce que vous voulez.
Jason
Ajoutés dans ma réponse.
Adam Matan

Réponses:

29

Puisque vous avez dit que vous obteniez un groupe de polygones se croisant pour chaque polygone qui vous intéresse, vous pouvez créer ce que l'on appelle une "superposition de polygone".

Ce n'est pas exactement ce que fait la solution d'Adam. Pour voir la différence, regardez cette image d'une intersection ABC:

Intersection ABC

Je crois que la solution d’Adam créera un polygone "AB" couvrant à la fois les surfaces "AB! C" et "ABC", ainsi qu’un polygone "AC" recouvrant "AC! B" et "ABC", ainsi que " BC "polygone qui est" BC! A "et" ABC ". Ainsi, les polygones de sortie "AB", "AC" et "BC" chevaucheraient tous la zone "ABC".

Une superposition de polygone produit des polygones qui ne se chevauchent pas. AB! C serait donc un polygone et ABC, un polygone.

Créer une superposition de polygones dans PostGIS est en réalité assez simple.

Il y a essentiellement trois étapes.

L'étape 1 consiste à extraire le trait (notez que j'utilise l' anneau extérieur du polygone, cela devient un peu plus compliqué si vous voulez gérer correctement les trous):

SELECT ST_ExteriorRing(polygon_col) AS the_geom FROM my_table) AS lines

L'étape 2 consiste à "nouer" le travail de ligne (produire un nœud à chaque intersection). Certaines bibliothèques comme JTS ont des classes "Noder" que vous pouvez utiliser pour cela, mais dans PostGIS, la fonction ST_Union le fait pour vous:

SELECT ST_Union(the_geom) AS the_geom FROM (...your lines...) AS noded_lines

L'étape 3 consiste à créer tous les polygones possibles qui ne peuvent pas se chevaucher et qui peuvent provenir de toutes ces lignes, à l'aide de la fonction ST_Polygonize :

SELECT ST_Polygonize(the_geom) AS the_geom FROM (...your noded lines...)

Vous pouvez enregistrer la sortie de chacune de ces étapes dans une table temporaire ou les combiner dans une seule instruction:

CREATE TABLE my_poly_overlay AS
SELECT geom FROM ST_Dump((
    SELECT ST_Polygonize(the_geom) AS the_geom FROM (
        SELECT ST_Union(the_geom) AS the_geom FROM (
            SELECT ST_ExteriorRing(polygon_col) AS the_geom FROM my_table) AS lines
        ) AS noded_lines
    )
)

J'utilise ST_Dump parce que la sortie de ST_Polygonize est une collection de géométries et qu'il est (généralement) plus pratique de disposer d'un tableau dans lequel chaque ligne est l'un des polygones constituant la superposition de polygone.

Jeff
la source
Notez que ST_ExteriorRinglaisse tomber tous les trous. ST_Boundarypréservera les anneaux intérieurs, mais créera également un polygone à l'intérieur.
jpmc26 le
L'union des anneaux extérieurs se bloque lorsqu'il y a trop de polygones. Malheureusement, cette solution "simple" ne fonctionne que pour les petites couvertures.
Pierre Racine
13

Si je comprends bien, vous voulez prendre (A est la géométrie de gauche, B est la droite):

Image de A∪B http://img838.imageshack.us/img838/3996/intersectab1.png

Et extrait:

A ∖ AB

Image de A ∖ AB http://img830.imageshack.us/img830/273/intersectab2.png

UN B

Image de l’AB http://img828.imageshack.us/img828/7413/intersectab3.png

et B ∖ AB

Image de B ∖ AB http://img839.imageshack.us/img839/5458/intersectab4.png

C’est-à-dire trois géométries différentes pour chaque paire qui se croise.

Commençons par créer une vue de toutes les géométries qui se croisent. En supposant que le nom de votre table soit polygons_table, nous utiliserons:

CREATE OR REPLACE VIEW p_intersections AS    -- Create a view with the 
SELECT t1.the_geom as t1_geom,               -- intersecting geoms. Each pair
       t2.the_geom as t2_geom                -- appears once (t2.id<t2.id)
    FROM polygons_table t1, polygons_table t2  
         WHERE t1.id<t2.id AND t1.the_geom && t2.the_geom 
                           AND intersects t1.the_geom, t2.the_geom;

Maintenant, nous avons une vue (pratiquement, une table en lecture seule) qui stocke des paires de zones géographiques se coupant, où chaque paire n'apparaît qu'une seule fois en raison de la t1.id<t2.idcondition.

Maintenant , nous allons rassembler vos intersections - A∖AB, ABet B∖AB, à l' aide de SQL UNIONsur les trois requêtes:

--AB:
SELECT ST_intersection(t1.the_geom, t2.the_geom) 
    AS geom 
    FROM p_intersections

UNION 

--AAB:
SELECT ST_Difference(t1.the_geom, t2.the_geom) 
    AS geom 
    FROM p_intersections

UNION

--BAB:
SELECT ST_Difference(t2.the_geom, t1.the_geom) 
    AS geom 
    FROM p_intersections;

Remarques:

  1. L' &&opérateur sert de filtre devant l' intersectsopérateur pour améliorer les performances.
  2. J'ai choisi de créer une VIEWrequête gigantesque au lieu d'une. Ceci est pour la commodité seulement.
  3. Si vous vouliez dire ABest l'union et non l'intersection de Aet B- Utilisez ST_Union au lieu de st_intersection à la UNIONrequête aux endroits appropriés.
  4. Le signe est un signe Unicode pour Set difference; supprimez-le du code s'il confond votre base de données.
  5. Les images sont une gracieuseté de la belle catégorie Théorie des ensembles de Wikimedia Commons .
Adam Matan
la source
Mon ticket de bug sur meta: meta.gis.stackexchange.com/questions/79/…
Adam Matan
Belle explication! Les résultats sont les mêmes que dans la solution scw, mais son chemin devrait être plus rapide (ne pas calculer / ou stocker / intersections supplémentaires de A et B)
stachu
Merci! Je pense que je ne stocke aucune information supplémentaire, car je crée uniquement des vues SQL, pas des tables.
Adam Matan
Oui, c'est vrai, mais vous calculez des intersections supplémentaires de A et B, ce qui n'est pas nécessaire
stachu
5
Les images dans cette réponse ne fonctionnent plus.
Fezter
8

Ce que vous décrivez, c’est la façon dont l’ opérateur Union fonctionne dans ArcGIS, mais c’est un peu différent de celui d’Union ou d’Intersection dans le monde GEOS. Le manuel Shapely contient des exemples de fonctionnement des ensembles dans GEOS . Cependant, le wiki de PostGIS a un bon exemple en utilisant un travail au trait qui devrait faire l'affaire pour vous.

Alternativement, vous pouvez calculer trois choses:

  1. ST_Intersection (geom_a, geom_b)
  2. ST_Difference (geom_a, geom_b)
  3. ST_Difference (geom_b, geom_a)

Ceux-ci devraient être les trois polygones que vous avez mentionnés dans votre deuxième point.

scw
la source
2
L'exemple de wiki PostGIS est bon
fmark le
ST_Intersects ne rendrait-il pas un booléen s’ils se croisent ou non? Je pense que ST_Intersection fonctionnerait.
Jason
Oui, une faute de frappe de ma part - corrigée dans l'original maintenant, merci Jason!
scw
-2

Quelque chose comme:

INSERT INTO new_table VALUES ((Sélectionnez id, the_geom de old_table où st_intersects (the_geom, (sélectionnez the_geom de old_table où id = '123')) = true

EDIT: vous avez besoin de l'intersection réelle du polygone.

INSERT INTO valeurs new_table ((sélectionnez id, ST_Intersection (the_geom, (sélectionnez the_geom from old où id = 123))

voir si ça marche.

George Silva
la source