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

Rencontres QGIS 2025

L'appel à participation est ouvert jusqu'au 19 janvier 2025!

#1 Wed 24 April 2013 17:25

ppluvinet
Participant assidu
Lieu: VALENCE
Date d'inscription: 6 Aug 2007
Messages: 617

POSTGIS : couper des lignes par des points

Bonjour,
J'ai des polylignes que je veux segmenter par une couche de points. Ces points sont préalablement  snappés aux lignes.
J'ai testé deux solutions dont aucune est concluante :

Code:

--solution 1 avec st_difference
drop table lines_dec;
create table lines_dec as 
select  a.idline, (ST_Dump(ST_difference(a.geom,b.geom))).geom as geom
from lines a , points_multi b 
where
st_intersects(a.geom,b.geom) and a.idline= b.idline;

--solution 2 avec st_split
drop table lines_dec;
create table lines_dec as 
select  a.idline, (ST_Dump(ST_Split(a.geom,b.geom))).geom as geom
from lines a , points_non_multi b 
where
st_intersects(a.geom,b.geom);

Pour la solution 1, j'ai préalablement fusionné (avec un st_union) les points qui intersectent la même ligne. Le résultat (lines_dec) n'est rien d'autre que les segments de ma polyline qui intersectent mes points. Les segments n'ont pas été sectionné par les points.

Pour la solution 2, les segments sont bien sectionnés par les points. Or, dans le cas où j'ai plusieurs points sur une même ligne, comme la fonction st_split n'accepte pas les Multipoint, j'ai des segments qui se chevauchent (sorte de doublons)....

Auriez-vous une autre solution ? Merci d'avance,

Pascal


Pascal PLUVINET

Hors ligne

 

#2 Thu 25 April 2013 08:27

Nicolas Granier
Participant assidu
Date d'inscription: 19 Apr 2007
Messages: 271

Re: POSTGIS : couper des lignes par des points

Bonjour,

J'ai mis au moins 2 jours à faire ma requête de découpage alors si je peux vous en faire bénéficier c'est avec plaisir.

Tout d'abord voici les conclusions que j'ai pu tirer de mes tests :
-un point n'est jamais positionné exactement sur un tronçon de ligne, tout n'est qu'une question de tolérance.
- il faut effectivement regrouper les points en une couche sinon ca duplique les résultats en sortie.

voici la requete :

Code:

select couche_de_ligne.champ1,couche_de_ligne.champ2,
ST_SNAP((ST_DUMP(st_difference(couche_de_ligne.the_geom,point))).geom,all_point,0.1) as the_geom 
from (select ST_Multi(ST_Union(st_expand(couche_de_point.the_geom, 0.05))) as point from couche_de_point ) as t1, 
couche_de_ligne,(select ST_MULTI(ST_COLLECT(couche_de_point.the_geom))as all_point from couche_de_point) as t2

et voici l'explication :
Afin de palier au problème de tolérance, je convertis mes points en buffer (très petit 5cm). J'ai préalablement assemblé ces points en une seule couche de multipoint (avec ST_UNION). Je découpe avec ST_Différence puis ST_Dump comme dans votre solution 1, et je rajoute un ST_SNAP à 10cm, pour recoller les extrémités de mes lignes découpées sur les points de découpage eux-même, mais que j'ai assemblé avec ST_COLLECT ET non ST_UNION afin de leur conserver des géométries différenciées.

Nicolas GRANIER

Hors ligne

 

#3 Thu 25 April 2013 09:42

ppluvinet
Participant assidu
Lieu: VALENCE
Date d'inscription: 6 Aug 2007
Messages: 617

Re: POSTGIS : couper des lignes par des points

Et bien bravo  !  Ca fonctionne !  c'est efficace et relativement élégant à la fois ! Plusieurs sujets (notamment anglophones) traitent de ce sujet mais aucun n'envisage une solution si efficace (du moins ceux que j'ai pu lire). Merci Nicolas.

A bientôt,


Pascal PLUVINET

Hors ligne

 

#4 Thu 25 April 2013 09:52

Nicolas Granier
Participant assidu
Date d'inscription: 19 Apr 2007
Messages: 271

Re: POSTGIS : couper des lignes par des points

Mais de rien. J'ai fait moi même pas mal de veille sans trouver un truc qui fonctionne à 100%, alors j'ai assemblé plusieurs morceaux de sql pour parvenir à cette solution.
A bientôt.

Nicolas GRANIER

Hors ligne

 

#5 Sat 27 April 2013 18:46

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

Re: POSTGIS : couper des lignes par des points

Bonjour Nicolas,

La methode est interessante !

Cependant, en regroupant tous les points dans une seule couche, les index spatiaux ne peuvent plus etre utilisés lors de la requete.
Pour gagner en performance, il est possible de regrouper les points par ligne dans une collection, puis de faire la difference entre une ligne et ce groupe de points.

Le snap est ensuite fait entre les multilinestring et leurs multipoints respectifs.
La premiere requete fabrique les groupes de multipoints par ligne, en gardant l'id de la ligne pour faire la jointure dans la requete d'apres.
Elle fabrique aussi une collection des points initiaux, pour permettre le snapping entre les lignes et leurs points:

Code:

with mpoint_by_line as (
    select l.gid as lgid, (st_collect(st_expand(p.geom, 0.01))) as cut, st_collect(p.geom) as geom
    from points p, lines l
    where st_dwithin(l.geom, p.geom, 0.01)
    group by l.gid
) select l.gid, (st_dump(st_snap(st_difference(l.geom, mp.cut), mp.geom, 0.1))).geom as geom
from mpoint_by_line mp, lines l
where mp.lgid = l.gid;

La difference de perf peut etre interessante sur les gros volumes de données:
~ 290 ms contre 24500 ms avec le meme jeu de données.

Nicolas

Hors ligne

 

#6 Sat 27 April 2013 20:14

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

Re: POSTGIS : couper des lignes par des points

Re smile

Je me suis demandé s'il etait possible de realiser la meme chose avec les fonctions de referencement linéaire, qui permettent de couper des lignes et de projeter des points sur des lignes proches, realisant un snapping tres precis et tres rapide.

Le principe est de trouver pour chaque ligne, la position de chaque point de decoupage par rapport a la ligne: 0 represente le debut de la ligne, 1 la fin de la ligne. Il s'agit de la localisation du point sur la ligne.

Puis, pour pouvoir realiser le decoupage des lignes initiales en se servant des differentes localisations des points sur la ligne, une table est construite en creant un champ index, incremental ( partie "rank() over (partition...)" ) . Cet index va permettre de fabriquer un record avec les champs: geom, localisation, localisation + 1

Enfin, les lignes initiales sont découpés par les localisations des points (st_line_substring), en realisant les jointures qui vont bien:

Code:

-- premiere table des positions des points par rapport a "leurs" lignes
with locus as (
        -- on genere la position du debut de la ligne (index 0)  pour le premier segment à découper
    select l.gid, 0 as l
    from lines l

    UNION ALL

        -- on genere la position de la fin de la ligne (index 1)  pour le dernier segment à découper
    select l.gid, 1 as l
    from lines l

    UNION ALL

        -- calcul des positions des points par rapport aux lignes
    select l.gid, st_line_locate_point(l.geom, p.geom) as  l
    from lines l, points p
    where st_dwithin(l.geom, p.geom, 0.01)
    
    order by gid, l
), 
-- deuxieme table qui ajoute un index croissant par position croissante, pour permettre de faire la jointure plus tard sur elle-meme:
loc_with_idx as (
    select gid, l, rank() over (partition by gid order by l) as idx
    from locus
) 
-- decoupage final de chaque ligne avec les positions des points sur la ligne, grace a st_line_substring
select l.gid, st_line_substring(l.geom, loc1.l, loc2.l) as geom 
from loc_with_idx loc1, loc_with_idx loc2, lines l
where l.gid = loc1.gid
and loc1.gid = loc2.gid
and loc2.idx = loc1.idx+1;

L'avantage de cette methode est que le snapping entre les points et les lignes est super rapide et precis, quelque soit la precision.

En terme de vitesse, c'est tres performant ! : 90ms avec le meme jeu de donnée que dans le post précédent.

Hors ligne

 

#7 Mon 29 April 2013 08:18

Nicolas Granier
Participant assidu
Date d'inscription: 19 Apr 2007
Messages: 271

Re: POSTGIS : couper des lignes par des points

Bonjour Nicolas,

Effectivement je me trouve devant des temps de calculs  assez importants (enfin c'est relatif), je parle de 6H de traitement sur ma machine pour environ 10 000 tronçons à découper par 50 000 points. J'avais juger que mes 6 h de traitements étaient acceptables ... vue que je n'avais pas d'autre solution hmm
Pour mon prochain gros calcul,  j'essaye le "with" avec l'utilisation des index spatiaux.

Nicolas GRANIER

Hors ligne

 

#8 Mon 29 April 2013 09:55

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

Re: POSTGIS : couper des lignes par des points

Bonjour,

Oui 6h de traitement pour cette volumetrie, c'est un peu trop.
la methode la plus rapide (referencement lineaire) prend environ 20 s pour une volumetrie de 109133 lignes des communes croisées avec 800 000 points sur ces lignes.
La methode WITHIN prend environ 120% de plus.

Nicolas

Hors ligne

 

Pied de page des forums

Powered by FluxBB