#1 Wed 07 June 2017 14:22
- Lucie D.
- Participant actif
- Date d'inscription: 21 Oct 2013
- Messages: 137
Postgresql : découper des polylignes par des polygones
Bonjour,
Pour info, j'ai déjà reçu de l'aide via notre liste de diffusion interne, mais je me permets de poster ici aussi pour optimiser les chances de résolution de mon problème. Je tiendrai au courant la liste et ce forum en fonction de mes avancements.
Je dispose d'une couche des tronçons routes et d'une couche des parcelles cadastrales à l'échelle d'un département.
Je souhaite découper mes tronçons routes par mes parcelles pour déterminer les tronçons qui sont à l'intérieur des parcelles et ceux qui ne le sont pas.
Pour cela, voici comment je procède :
Je crée une couche vide :
Code:
CREATE TABLE troncons_decoupe (id varchar, geom_inter geometry(Multilinestring, 2154));
Ensuite je fais une première requête d'insertion des bouts de tronçons qui se situent à l'intérieur de mes parcelles :
Code:
INSERT INTO troncons_decoupe SELECT tr.id, st_multi(st_collectionextract(st_intersection(tr.geom,par.geom),2)) as geom_inter FROM tronçons_routes as tr, parcelles as par WHERE NOT ST_IsEmpty(st_intersection(tr.geom,par.geom)) AND st_intersects(tr.geom, par.geom);
Ensuite le but serait d'intégrer les bouts de tronçons qui croisent les parcelles mais qui ne sont pas à l'intérieur :
Code:
INSERT INTO troncons_decoupe SELECT tr.id, st_multi(st_collectionextract(st_difference(tr.geom, st_union(par.geom)),2)) as geom_inter FROM tronçons_routes as tr, parcelles as par WHERE NOT ST_IsEmpty(st_difference(tr.geom,st_union(par.geom))) AND st_intersects(tr.geom, par.geom);
La requête avec le st_intersection fonctionne très bien, mais le st_différence tourne depuis plus de 20 jours...
Il m'a déjà été conseillé de retirer le not st_isempty pour optimiser les temps de calcul (car il ne permet pas l'utilisation des index). A l'échelle de la commune, c'est vrai que la différence est évidente.
Ensuite, il m'a été recommandé de grouper les parcelles proches et de les unir au lieu de les unir sur l'ensemble du département pour éviter d'avoir un seul très gros polygone difficilement gérable par postgre (utilisation de st_clusterDBSCAN). Là encore, la requête tourne encore (depuis moins longtemps mais c'est parce que je l'ai lancée plus tard!). Il m'a été proposé d'utiliser un st_crosses à la place du st_intersects, mais ça ne change pas grand chose non plus.
Dans tous les cas je remercie les personnes qui m'ont donné plein d'astuces. Malheureusement ce n'est toujours pas suffisant.
Donc je me suis tournée vers le st_split qui, malheureusement, me retourne autant de tronçons qu'il y a de découpages possibles (et donc avec des bouts de tronçons qui se chevauchent...). Ainsi, dans le schéma que je joins à mon message, le tronçon sera découpé entre les points :
- A-B, A-C, A-D, A-E
- B-A, B-C, B-D, B-E
- C-A, C-B, C-D, C-E
- D-A, D-B, D-C, D-E
- E-A, E-B, E-C, E-D
Or, moi, je ne souhaite conserver que le découpage A-B, B-C, C-D, D-E.
J’utilise une requête du style (sachant que, pour l'instant, je travaille principalement avec postgis 2.1 mais que j'ai la possibilité de travailler avec postgis 2.3) :
Code:
(st_dump(st_split(r.geom,(st_dump(st_boundary(p.geompar))).geom))).geom
Ce st_split pourrait m'aider mais il ne me retourne pas le bon résultat.
Quelqu'un aurait une idée?
Merci beaucoup pour votre aide et désolée pour ce long message!
Bien cordialement,
Lucie D.
Dernière modification par Lucie D. (Wed 07 June 2017 14:24)
Hors ligne
#2 Wed 07 June 2017 16:56
- Nicolas Ribot
- Membre
- Lieu: Toulouse
- Date d'inscription: 9 Sep 2005
- Messages: 1554
Re: Postgresql : découper des polylignes par des polygones
Bonjour,
Pour ce genre de problématique (si je la comprends bien, ce qui n'est pas sûr), les fonctions de référencement linéaires marchent bien (https://postgis.net/docs/reference.html … eferencing).
Elles permettent de localiser un point par rapport à une ligne et de découper une ligne entre deux points de localisation (=locus).
Ces fonctions sont très (très) performantes par rapport à des intersections classiques, notamment entre point et ligne (pb de précision des points par rapport aux lignes).
Ici, pour découper des routes par rapport à des parcelles, on peut calculer les points d'intersection entre les routes et les contours des parcelles, puis calculer les locus de ces points d'intersection par rapport à chaque route, puis enfin découper les routes entre les locus consécutifs trouvés: le découpage est ultra rapide.
Les données: Tables route (routes bdtopo) et parc (parcelles cadastrales) sur Paris.
Les parcelles sont fusionnées et dumpées pour extraire des polygones simples (plus de frontieres entre parcelles contigües) => table parcfusion:
Code:
drop table if exists parcfusion; CREATE TABLE parcfusion as ( select (st_dump(st_union(geom))).path, (st_dump(st_union(geom))).geom from parc ); alter table parcfusion add column id SERIAL PRIMARY KEY ; create index parcfusion_geom_gist on parcfusion USING GIST (geom); VACUUM ANALYSE parcfusion;
Ensuite, dans la CTE inter, on calcule l'intersection entre les routes et les contours externes des parcelles => on obtient des points ou des multipoints qu'on dump.
Dans la CTE locus, on calcule le locus (=localisation du point sur la ligne, entre 0 et 1) entre chaque route et les points d'intersection.
On en profite pour rajouter artificiellement les locus 0 et 1 (début et fin de ligne) pour chaque route. On a alors tout le temps, pour les routes, une sequence de valeurs entre 0 et 1 qui sont les points de découpage de la route.
Dans locus_id, on génère un id croissant continu sur les locus, apres avoir ordonné comme il faut dans l'etape précédente: par id de route, puis locus.
Dans route_cut, on fait un self-join sur la table locus_id histoire de pouvoir mettre sur une meme colonne une route, son locus n et le locus n+1: on découpe la route entre ses deux locus. On obtient alors des segments à l'intérieur ou à l'extérieur des parcelles. Dans une étape finale (pas faite ici), on peut retrouver les segments contenus dans les parcelles (le plus efficace pour cela est de comparer les longueurs d'intersection parcelle/troncon vs troncon).
Le processus tourne en qq secondes sur Paris: on fait une seule intersection entre les routes et les parcelles (apres fusion de celles-ci, qui peut prendre un peu de temps).
Code:
with inter as ( SELECT r.gid, p.id, (st_dump(st_intersection(r.geom, st_boundary(p.geom)))).geom AS geom, r.geom as rgeom FROM route r JOIN parcfusion p ON st_intersects(r.geom, p.geom) ), locus as ( select gid, st_linelocatepoint(rgeom, geom) as locus, rgeom from inter union all select gid, 0 as locus, rgeom from inter UNION ALL select gid, 1 as locus, rgeom from inter order by gid, locus ), locus_id as ( SELECT row_number() OVER () AS id, * FROM locus where locus between 0.001 and 0.999 ), route_cut as ( SELECT l1.gid as gid1, st_linesubstring(l1.rgeom, l1.locus, l2.locus) as geom FROM locus_id l1 JOIN locus_id l2 ON l1.gid = l2.gid AND l2.id = l1.id + 1 ) select * from route_cut;
Quelques captures en attachement pour montrer le process: les parcelle initiales et les routes, puis les parcelles fusionnées, enfin les troncons de route a cheval sur des parcelles, découpés par les points d'intersection route/parcelle.
Nicolas
Hors ligne
#3 Thu 08 June 2017 10:08
- JD
- Moderateur
- Date d'inscription: 8 Aug 2013
- Messages: 726
Re: Postgresql : découper des polylignes par des polygones
Post limpide.
C'est dommage qu'il n'y ait pas un système de vote sur le forum, car j'aurais bien voté !
Bonne journée,
Hors ligne
#4 Thu 08 June 2017 10:47
- Nicolas Ribot
- Membre
- Lieu: Toulouse
- Date d'inscription: 9 Sep 2005
- Messages: 1554
Re: Postgresql : découper des polylignes par des polygones
merci
Hors ligne
#5 Thu 08 June 2017 14:36
- Lucie D.
- Participant actif
- Date d'inscription: 21 Oct 2013
- Messages: 137
Re: Postgresql : découper des polylignes par des polygones
Super! Moi aussi je vote!
Malheureusement je pars en vacances ce soir et n'aurai pas bien le temps de regarder la requête cet après-midi...
Incroyable tout ce qu'on peut faire avec Postgresql! O_O
Merci pour ce post effectivement très bien détaillé!
Je vous tiens au courant!
Bien cordialement,
Lucie D.
Hors ligne
#6 Thu 08 June 2017 15:08
- Nicolas Ribot
- Membre
- Lieu: Toulouse
- Date d'inscription: 9 Sep 2005
- Messages: 1554
Re: Postgresql : découper des polylignes par des polygones
Oui les versions recentes de PG et postgis permettent de faire des traitements de fou
Hors ligne
#7 Fri 09 June 2017 09:30
- ChristopheV
- Membre
- Lieu: Ajaccio
- Date d'inscription: 7 Sep 2005
- Messages: 3197
- Site web
Re: Postgresql : découper des polylignes par des polygones
Bonjour,
vraiment cool !! Merci Nicolas.
Christophe
L'avantage d'être une île c'est d'être une terre topologiquement close
Hors ligne