#1 Fri 10 May 2019 16:46
- zack
- Participant occasionnel
- Date d'inscription: 16 Jul 2014
- Messages: 33
POSTGIS - Découper polygones par des lignes
Bonjour,
Dans une chaîne de traitement QGIS j'essaye de découper des polygones par des lignes.
Ces lignes sont issus de st_shortestline sur postgis. J'ai étendue chaque ligne de 1m pour éviter des problèmes de précision.
L'outil "couper avec des lignes" de QGIS fonctionne sur une petite zone de test, mais pas sur une commune entière, beaucoup trop de lignes et de polygones (quelques milliers pour chaque).
Du coup j'essaye de voir pour intégrer la fonction st_split. Elle semble marcher en une demi-heure pour la commune entière. Mais le résultat n'est pas du tout bon, j'ai des dizaines de milliers de lignes dans la table, et pourtant en les chargeant dans QGIS mes polygones semblent non découpés.
Je pense que ça vient du fait que st_split crée une geometry_collection et que le ST_CollectionExtract ne marche justement pas dans le cas d'un st_split.
Du coup est-ce que quelqu'un sait quelle fonction écrire ? Je ne suis pas hyper à l'aise avec PostGIS
La fonction suivante ne marche pas donc, il me donne une erreur à cause du multilinestring qui n'est pas supporté...
Code:
DROP TABLE if exists blabla; CREATE TABLE blabla AS SELECT ST_CollectionExtract(ST_Split(rect.geom, line.the_geom),3) FROM public.polygones_zone_test as rect, public.lignes_zone_test as line
Merci à vous !
Hors ligne
#2 Mon 13 May 2019 13:54
- tumasgiu
- Membre
- Lieu: Ajaccio
- Date d'inscription: 5 Jul 2010
- Messages: 1160
Re: POSTGIS - Découper polygones par des lignes
Salut,
tout d'abord,
le message d'erreur semble indiquer que la colonne géométrique
de votre table lignes_zone_test est de type multi linestring.
A ce moment là, il faudrait les extraire avec st_dump.
Ensuite, le résultat que vous obtenez vient du fait que
votre requête exécute pour st_split pour chaque combinaison
des géométries de vos deux tables.
Cette fonction, utilisée avec une géométrie et une ligne de découpe
qui sont géométriquement disjointes, aura pour résultat la géométrie originale.
Pour supprimer ces résultats inutiles, il faudrait rajouter une condition de jointure
entre vos deux tables pour ne retenir que les éléments qui s'intersectent :
Code:
SELECT ST_CollectionExtract(ST_Split(rect.geom, line.the_geom),3) FROM public.polygones_zone_test as rect JOIN public.lignes_zone_test as line ON st_intersects(rect.geom, line.the_geom)
Si vous ne l'avez pas déjà fait, vous devriez ajouter un index géométrique
sur l'une de vos deux tables (typiquement celles qui contient le plus
grand nombre de ligne), cela accélérera probablement le temps de traitement.
Mais je ne suis pas sur que cela soit le résultat que vous attendiez,
supposez un polygone traversé par plusieurs lignes,
chaque découpage se déroulera indépendamment avec toujours le polygone orignal en entier.
Pour découper avec une multi ligne, il vous faudrait passer à postgis 2.5
Dernière modification par tumasgiu (Mon 13 May 2019 13:55)
Hors ligne
#3 Thu 16 May 2019 17:23
- zack
- Participant occasionnel
- Date d'inscription: 16 Jul 2014
- Messages: 33
Re: POSTGIS - Découper polygones par des lignes
Bonjour,
Merci pour cette réponse. J'ai installé PostgreSQL 10 et Postgis 2.5.2 en local (windows 10) pour faire des tests avant d'upgrader le PostgreSQL de mon serveur Debian. Le code que vous donnez ne donne pas d'erreur, même avec du multi-linestring.
Le nombre de polygones en sortie semble cohérent, et visuellement, les polygones apparaissent découpés à certains emplacements de lignes mais pas à tous. Certains polygones ont disparu. Mais lorsque j'essaye de faire une sélection d'un polygone, il me sélectionne le même grand ensemble qu'avant la découpe. Et je ne peux faire aucune modification, même suppression de polygone, QGIS indique que le fournisseur de données ne gère pas l'effacement des entités.
Peut-être que passer par une commande postgis n'est pas la solution à mon problème...
Hors ligne
#4 Thu 16 May 2019 17:59
- tumasgiu
- Membre
- Lieu: Ajaccio
- Date d'inscription: 5 Jul 2010
- Messages: 1160
Re: POSTGIS - Découper polygones par des lignes
Les polygones ayant disparus sont certainement ceux n'intersectant avec
aucune ligne.
Je crois comprendre à quel résultat vous voulez aboutir, il faudrait changer
un peu la requête :
Code:
SELECT st_collectionextract( st_split(rect.geom, coalesce(ST_CollectionHomogenize(st_collect(line.the_geom))), 'LINESTRING EMPTY'::geometry('LINESTRING')), 3) AS geom FROM polygones_zone_test as rect LEFT JOIN public.lignes_zone_test as line ON st_intersects(rect.geom, line.the_geom) GROUP BY rect.geom
L'idée est de regrouper, pour chaque polygone,
toutes les LINESTRING qui le traverse en une seule MULTILINESTRING
et d'appeler st_split avec celle ci.
Les polygones qui ne sont traversés par aucune ligne
sont quand même renvoyées grâce au LEFT JOIN,
et on transforme la MULTILINESTRING NULL qui leur sont associée
par une LINESTRING vide, pour que le st_split fonctionne et
renvoie le polygone tel quel.
Dernière modification par tumasgiu (Thu 16 May 2019 18:04)
Hors ligne
#5 Thu 16 May 2019 18:01
- tumasgiu
- Membre
- Lieu: Ajaccio
- Date d'inscription: 5 Jul 2010
- Messages: 1160
Re: POSTGIS - Découper polygones par des lignes
Le fait que vous ne puissiez faire aucune modification via QGIS vient du fait
que celui ci ne permet de modification qui si une clef primaire est présente
dans la table.
Hors ligne
#6 Wed 22 May 2019 17:47
- zack
- Participant occasionnel
- Date d'inscription: 16 Jul 2014
- Messages: 33
Re: POSTGIS - Découper polygones par des lignes
Bonjour,
Merci pour votre réponse. Je n'ai pas eu de notification Georezo donc je ne l'avais pas vu jusqu'à aujourd'hui... désolé...
J'ai donc testé votre code.
Code:
DROP TABLE if exists blabla; CREATE TABLE blabla AS SELECT st_collectionextract( st_split(rect.geom, coalesce((ST_CollectionHomogenize(st_collect(line.geom))), 'LINESTRING EMPTY'::geometry('LINESTRING'))), 3) AS geom FROM polygones_zone_test as rect LEFT JOIN public.lignes_zone_test as line ON st_intersects(rect.geom, line.geom) GROUP BY rect.geom
J'ai ajouté des parenthèses dans la condition COALESCE puisque que le st_split avait trois conditions de géométrie ce qui ne lui plaisait pas, je ne sais pas si cette correction est bien juste mais il me semble que oui.
Il ne pose plus de problème sur le st_split, mais il me dit que le SRID n'est pas le même sur les deux couches (ERROR: ERREUR: Operation on mixed SRID geometries) alors que j'ai fait un st_srid et j'ai bien 2154 sur les deux couches... est-ce qu'une fonction préalable modifie le SRID?
Merci du temps consacré à me répondre !
Hors ligne
#7 Wed 22 May 2019 18:01
- tumasgiu
- Membre
- Lieu: Ajaccio
- Date d'inscription: 5 Jul 2010
- Messages: 1160
Re: POSTGIS - Découper polygones par des lignes
Non je pense que le problème vient du second argument de la fonction coalesce.
Pour rappel coalesce renvoie son premier argument si il est different de NULL
et son second argument sinon.
Donc dans le cas ou aucune ligne n'intersecte avec une zone,
la requête va tenter de faire un split avec une linestring vide.
Hors votre zone est en EPSG:2154, alors que la linestring vide
n'a pas de SRID défini.
Pour remédier à cela, changer la chaine "LINESTRING EMPTY"::Geometry('LINESTRING'),
par "SRID=2154;LINESTRING EMPTY"::Geometry('LINESTRING', 2154).
Dernière modification par tumasgiu (Wed 22 May 2019 18:02)
Hors ligne
#8 Wed 22 May 2019 18:07
- zack
- Participant occasionnel
- Date d'inscription: 16 Jul 2014
- Messages: 33
Re: POSTGIS - Découper polygones par des lignes
Rebonjour,
Merci j'avais solutionné ce problème en faisant un setSRID sur le coalesce mais votre solution marche aussi.
Du coup la fonction marche, je conserve bien tous les polygones, et ils sont, d'apparence, bien découpés aux emplacements des lignes.
En revanche, j'ai toujours le même nombre de polygones que sur la couche initiale. Il me crée des polygones multi-part.
Je peux solutionner ça en éclatant ensuite mes polygones en single part mais peut-être y a t'il une solution sur le code d'origine.
Un grand merci !
Hors ligne
#9 Wed 22 May 2019 22:46
- tumasgiu
- Membre
- Lieu: Ajaccio
- Date d'inscription: 5 Jul 2010
- Messages: 1160
Re: POSTGIS - Découper polygones par des lignes
Pas à ma connaissance, je pense qu'il faut que vous les eclatiez
à l'aide st_dump.
De rien pour l'aide.
Hors ligne
#10 Thu 23 May 2019 15:07
- zack
- Participant occasionnel
- Date d'inscription: 16 Jul 2014
- Messages: 33
Re: POSTGIS - Découper polygones par des lignes
Bonjour,
J'ai encore un petit message d'erreur que je n'avais pas sur ma petite zone de test...
ERROR: ERREUR: GEOSUnion: TopologyException: found non-noded intersection
Il s'agit d'endroits ou j'ai des lignes qui se croisent, ce qui est rare mais qui peut arriver.
J'ai essayé d'utiliser st_makevalid, d'après ce que j'ai pu trouver comme info sur les différents forums, en le plaçant à divers endroits du code, mais il me renvoie toujours la même erreur.
De ce que je comprend, il suffirait de créer des nœuds aux croisements des lignes pour avoir une topologie valide?
Hors ligne
#11 Thu 23 May 2019 17:02
- tumasgiu
- Membre
- Lieu: Ajaccio
- Date d'inscription: 5 Jul 2010
- Messages: 1160
Re: POSTGIS - Découper polygones par des lignes
Est ce que la requête suivante fonctionne ?
Code:
select st_split( 'POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 'MULTILINESTRING((-1 -1, 2 2), (2 -1, -1 2))' ) ;
Hors ligne
#12 Thu 23 May 2019 17:05
- zack
- Participant occasionnel
- Date d'inscription: 16 Jul 2014
- Messages: 33
Re: POSTGIS - Découper polygones par des lignes
Oui, sans problème
Hors ligne
#13 Thu 23 May 2019 17:20
- tumasgiu
- Membre
- Lieu: Ajaccio
- Date d'inscription: 5 Jul 2010
- Messages: 1160
Re: POSTGIS - Découper polygones par des lignes
Donc, st_split sait gérer une multiligne qui a deux élements se croisant.
Je pencherais plus pour un problème de coordonnée trop proches.
Vous pouvez essayer de régler le problème avec st_snaptogrid.
Avant il faudrait isoler la parité de la requête qui coince,
le st_intersects ou le st_split...
Hors ligne
#14 Thu 23 May 2019 17:59
- zack
- Participant occasionnel
- Date d'inscription: 16 Jul 2014
- Messages: 33
Re: POSTGIS - Découper polygones par des lignes
Merci !
J'ai donc rajouté un st_snaptogrid sur la partie lignes de la fonction st_split. Je l'ai mis un peu arbitrairement je l'avoue, ne sachant pas trop ce que ça donnerait. Et ça marche bien. Le paramètre de 0.0001 est parfaitement arbitraire également.
Code:
DROP TABLE if exists blabla; CREATE TABLE blabla AS SELECT st_collectionextract( st_split(rect.geom, st_snaptogrid(coalesce((ST_CollectionHomogenize(st_collect(st_makevalid(line.geom)))), 'SRID=2154;LINESTRING EMPTY'::geometry('LINESTRING')),0.0001)), 3) AS geom FROM public.polygones as rect LEFT JOIN public.lignes as line ON st_intersects(rect.geom, line.geom) GROUP BY rect.geom
Hors ligne