#1 Fri 24 November 2017 17:51
- p.jeremie
- Participant assidu
- Lieu: Valence
- Date d'inscription: 10 Sep 2017
- Messages: 427
[Postgis] Soustraction de polygones
Bonjour,
Je suis en train de me casser les dents sur l'opération suivante :
- j'ai une table dans postgres avec tous les polygones correspondants à des contraintes (zones à exclure)
- j'ai une table avec tous les polygones des communes de ma région
Je souhaite créer une table avec :
- tous les polygones des communes, soustraits des zones à exclure.
J'ai essayé avec le code suivant, mais je ne récupère que les communes pour lesquels au moins un bout de polygone a été enlevé :
Code:
create materialized view tmp.non_eclu AS -- select communes.insee, st_difference(communes.geom,contraintes.geom) as geom from tmp.communes_osm_aura communes, tmp.table_contraintes contraintes where st_intersects(communes.geom, contraintes.geom);
Une piste pour m'aider ?
Hors ligne
#2 Fri 24 November 2017 22:41
- Nicolas Ribot
- Membre
- Lieu: Toulouse
- Date d'inscription: 9 Sep 2005
- Messages: 1554
Re: [Postgis] Soustraction de polygones
Bonsoir:
Faites une jointure type LEFT JOIN
... FROM tmp.communes_osm_aura communes left join
tmp.table_contraintes contraintes on st_intersects(...)
Nico
Hors ligne
#4 Sun 26 November 2017 01:14
- Theos2000
- Participant assidu
- Date d'inscription: 15 Jun 2015
- Messages: 221
Re: [Postgis] Soustraction de polygones
Bonjour,
je me permet de participer car je suis sur la même problématique que p.jeremie,
mon cas est similaire puisque dans le cas d'une conso foncière je dois exclure des bâtiments polygones
j'ai essayé plusieurs manière de différencier en utilisant des left join sans succès :
-St_difference qui tourne en boucle
-Case when st_intersects, st_contains, st_within qui à la particularité de bien indiquer les alias issue du case when et meme lorsque l'alias est spécifié dans un where ===> affiche malgrés tout tous les batiments.
Quelle est la requête type pour exclure une géométrie , il y aurait il une subtilité qui m'échappe...sans doute !
Merci pour votre aide ou vos remarques
PJ : Exemple de requête
Dernière modification par Theos2000 (Sun 26 November 2017 01:15)
Hors ligne
#5 Sun 26 November 2017 13:50
- p.jeremie
- Participant assidu
- Lieu: Valence
- Date d'inscription: 10 Sep 2017
- Messages: 427
Re: [Postgis] Soustraction de polygones
Merci pour les réponses.
Comme il s'agissait de mon premier message sur le forum, j'ai pu continuer à chercher avant que mon message soir en ligne, et j'avais en effet inclus un left join.
Concernant
Il faudrait faire aussi un coalesce(st_difference(....), communes.geom)
En me basant sur la réponse de Nicolas à ce message https://georezo.net/forum/viewtopic.php … difference
J'arrivais à la requête suivante :
Code:
create materialized view tmp.non_exclu AS select communes.insee, st_difference(communes.geom, coalesce(contraintes.geom, 'GEOMETRYCOLLECTION EMPTY'::geometry)) as geom from tmp.communes_osm_aura communes left join ( select a.insee, st_union(b.geom) as geom from tmp.communes_osm_aura a join tmp.table_contraintes b on (a.geom && b.geom and st_intersects(a.geom, b.geom) ) group by a.insee ) contraintes on (communes.insee = contraintes.insee) ;
Si je comprends bien, gvellut tu ferais plutôt
Code:
(...) select communes.insee, coalesce(st_difference(communes.geom, contraintes.geom), communes.geom) as geom (...)
Les deux ont l'air de créer les mêmes données dans la vue.
Par contre, il y a un truc qui me chiffonne, c'est que je me retrouve avec 3 sortes de geometry :
Code:
select geometrytype(geom), count(*) from tmp.non_exclu group by 1 --- 'GEOMETRYCOLLECTION','75' 'MULTIPOLYGON','3938' 'POLYGON','82'
Alors que dans la table des communes, j'ai seulement des MULTIPOLYGON
Code:
select geometrytype(geom), count(*) from tmp.communes_osm_aura group by 1 --- 'MULTIPOLYGON','4095'
Et surtout, comment ça se fait que j'ai autant de communes dans la vue, alors que certaines sont chevauchées à 100% par une contrainte ?
Autrement dit, je devrais avoir moins que 4095 lignes dans la vue... Je suppose que ça a un lien avec mes 3 types de geometry mais je ne comprends pas bien pourquoi...
edit : suppression mise en gras dans sections code, ce qui ne fonctionne pas, pour ne pas perturber la lecture...
Dernière modification par p.jeremie (Tue 28 November 2017 14:07)
Hors ligne
#6 Sun 26 November 2017 16:23
- Nicolas Ribot
- Membre
- Lieu: Toulouse
- Date d'inscription: 9 Sep 2005
- Messages: 1554
Re: [Postgis] Soustraction de polygones
Bonjour,
Les différents types de géométries sont normaux:
la diff entre deux polygones peut donner un PG, un MPG, une ligne, un point, une combinaison de tout cela => GeometryCollection
Dans votre cas, vous vous interessez à des surfaces, il faut donc filtrer ces collections pour ne garder que des éléments surfaciques (PG ou MPG): st_collectionExtract(geom, 3).
Ca explique aussi pourquoi toutes les communes ressortent dans votre vue: meme en cas de recouvrement quasi parfait, la différence doit générer des géométries (lignes, point...). Elles devraient disparaitre lors de l'extraction des surfaces.
Il faudra ensuite forcer le résultat final en multipolygon (st_multi), pour garder une table clean au niveau géométrique.
Pour mieux visualiser les étapes du processus, vous pouvez créer une table intermédiaire contenant l'union des contraintes par commune:
Code:
create unlogged table comm_contrainte as ( SELECT a.insee, st_union(b.geom) AS geom FROM tmp.communes_osm_aura a JOIN tmp.table_contraintes b ON (st_intersects(a.geom, b.geom)) GROUP BY a.insee );
Puis faire la différence entre les communes et cette table:
Code:
... st_multi( st_collectionExtract( st_difference( c.geom, coalesce(cc.geom, 'GEOMETRYCOLLECTION EMPTY'::geometry) ), 3 ) ) as geom from commune c left join comm_contrainte cc on c.insee = cc.insee ...
Nicolas
Hors ligne
#7 Tue 28 November 2017 16:37
- p.jeremie
- Participant assidu
- Lieu: Valence
- Date d'inscription: 10 Sep 2017
- Messages: 427
Re: [Postgis] Soustraction de polygones
merci.
Pour mieux visualiser les étapes du processus, vous pouvez créer une table intermédiaire contenant l'union des contraintes par commune:
(...)
Puis faire la différence entre les communes et cette table
J'ai procédé comme ça pour mieux comprendre le cheminement, mais j'ai toujours un truc qui me chiffonne.
La première partie est claire, j'ai pour chaque commune l'union de ses contraintes dans une table intermédiaire.
C'est la deuxième partie qui me pose soucis.
J'ai autant de lignes dans la table finale que dans la table des communes.
Je m'attendais à n'avoir que les communes qui ont encore un bout "dispo" (autrement dit qui n'ont pas 100% de leur surface chevauchée par une contrainte).
Je précise que j'ai des zones de contraintes qui sont plus grandes que certaines communes (et donc ces communes sont bien complètement chevauchées).
J'ai donc ajouté une condition pour ne garder que les geometry non vides.
Je n'ai pas trouvé d'autre moyen que d'ajouter une requête qui englobe la requête avec les st_multi, st_collectionExtract et st_difference, car sinon je dois répéter tout le paquet de fonctions dans le where ! Autrement dit, pas possible de faire référence à l'alias geom car ambigu.
J'arrive à la requête suivante (j'ai choisi de faire un WITH plutôt qu'une table intermédiaire) :
Code:
create materialized view tmp.non_exclu AS -- union des contraintes par commune with contraintes_communes as ( select communes.insee_com as insee, st_union(contraintes.geom) as geom from ressources.communes_ign_aura communes join tmp.table_contraintes contraintes on (st_intersects(communes.geom, contraintes.geom)) group by communes.insee_com ) select insee, geom from (select communes.insee_com as insee, -- récupération des multipolygones correspondants à la différence -- entre les geom des communes et l'union des contraintes des communes st_multi( st_collectionExtract( st_difference( communes.geom, coalesce(cc.geom, 'GEOMETRYCOLLECTION EMPTY'::geometry) ), 3 ) ) as geom from ressources.communes_ign_aura communes left join contraintes_communes cc on communes.insee_com = cc.insee ) as s -- filtrage des géométries vides where st_isempty(s.geom) is not true;
Et comme ça je ne récupère plus les communes 100% concernées par des contraintes.
Ca explique aussi pourquoi toutes les communes ressortent dans votre vue: meme en cas de recouvrement quasi parfait, la différence doit générer des géométries (lignes, point...). Elles devraient disparaitre lors de l'extraction des surfaces.
Remarque : du coup j'ai constaté que les communes ne disparaissent par lors de l'extraction !
Je me demande même si elle est bien nécessaire maintenant que j'ai ajouté un un filtre sur les géométries vide... car je récupère la même table avec et sans le st_collectionExtract().
Remarque 2 : ça pourrait être sympa sur ce forum d'avoir des blocs code larges comme le message et la coloration syntaxique du SQL en mettant par exempe [ code = sql ]. Une piste : https://fluxbb.org/resources/mods/flux-geshi/
Remarque 3 : j'accepte le tutoiement
Hors ligne