Nous utilisons des cookies pour vous garantir la meilleure expérience sur notre site. Si vous continuez à utiliser ce dernier, nous considèrerons que vous acceptez l'utilisation des cookies. J'ai compris ! ou En savoir plus !.
banniere

Le portail francophone de la géomatique


Toujours pas inscrit ? Mot de passe oublié ?
Nom d'utilisateur    Mot de passe              Toujours pas inscrit ?   Mot de passe oublié ?

Annonce

Printemps des cartes 2024

#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)


Fichier(s) joint(s) :
Pour accéder aux fichiers vous devez vous inscrire.

Hors ligne

 

#2 Wed 07 June 2017 16:56

Nicolas Ribot
Membre
Lieu: Toulouse
Date d'inscription: 9 Sep 2005
Messages: 1536

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


Fichier(s) joint(s) :
Pour accéder aux fichiers vous devez vous inscrire.

Hors ligne

 

#3 Thu 08 June 2017 10:08

JD
Moderateur
Date d'inscription: 8 Aug 2013
Messages: 722

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: 1536

Re: Postgresql : découper des polylignes par des polygones

wink 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: 1536

Re: Postgresql : découper des polylignes par des polygones

Oui les versions recentes de PG et postgis permettent de faire des traitements de fou smile

Hors ligne

 

#7 Fri 09 June 2017 09:30

ChristopheV
Membre
Lieu: Ajaccio
Date d'inscription: 7 Sep 2005
Messages: 3168
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

 

Pied de page des forums

Powered by FluxBB