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 Thu 09 April 2015 11:56

guil31
Participant actif
Date d'inscription: 22 Jan 2013
Messages: 79

Problème d'utilisation de ST_Difference

Bonjour,

Je souhaite faire la différence entre 2 couches de lignes:
- route_selection est une sélection de routes
- et route_intersect qui est en fait issu du résultat de l'intersection de ma table route_selection avec des polygones

- route_selection contient 338 objets
- route_intersact contient 250 objets

J'utilise:

Code:

CREATE TABLE route_difference AS 
SELECT ST_Difference( route_selection.the_geom, route_intersect.the_geom) As the_geom 
FROM  route_selection, route_intersect
WHERE ST_Intersects(route_selection.the_geom, route_intersect.the_geom)

Dans ma table résultat j'ai 1023 résultats! (132 GEOMETRYCOLLECTION, 2 MULTILINESTRING et 889 LINESTRING)
De plus visuellement (dans Qgis) la table résultat recouvre toutes mes lignes de route_selection.
Et quand je sélectionne graphiquement un tracé dans la table résultat j'ai 6 objets sélectionnés.

Quelqu'un a une idée de pourquoi je n'obtiens pas la différence avec ST_Difference?
Ou est-ce que quelqu'un à une autre idée pour faire cette opération? (j'ai déjà essayé ST_SymDifference mais cela n'a pas mieux fonctionné)

Hors ligne

 

#2 Fri 10 April 2015 09:05

guil31
Participant actif
Date d'inscription: 22 Jan 2013
Messages: 79

Re: Problème d'utilisation de ST_Difference

J'ai fait des tests complémentaires sur des jeux données plus simple.

Test 1:
- une ligne composée d'un segment [AB]
- une ligne composée de deux segments [AC] et [CD] avec C snapé sur le segment [AB]
La fonction arrive à découper [AB] en C et je récupère un segment [CB]

Test 2:
- une ligne composée de trois segments [AB], [BC] et [CD]
- une ligne composée d'un segment [BE] avec E snapé sur le segment [AB]
- une ligne composée de deux segments [BC] et [CF] avec F snapé sur [CD]
Dans ce cas aucun découpage n'est fait en E et en F et je ne récupère pas [AE] et [FD]

=> Est-ce que finalement ST_Difference fonctionne bien quand le résultat nécessite de découper une ligne pour récupérer plusieurs sous-segments?
Pour précision j'utilise PostGIS 2.0.6 et PostgreSQL 9.1

Hors ligne

 

#3 Fri 10 April 2015 11:20

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

Re: Problème d'utilisation de ST_Difference

Bonjour,

Vous obtenez bien la différence entre les couches, mais ce n'est pas forcément le résultat visuel que vous souhaitez:

Si une ligne d'une table intersecte plusieurs lignes de l'autre table, vous aurez autant de résultats, en superposition les uns sur les autres.
Il faut compléter la requête en ajoutant des "distincts" ou des constructions SQL permettant de filtrer les résultats identiques. (distinct on the_geom peut aider à filter les géométries identiques, en première approximation).

Nicolas

Hors ligne

 

#4 Fri 10 April 2015 11:21

nicolas-f
Juste Inscrit !
Date d'inscription: 10 Apr 2015
Messages: 3

Re: Problème d'utilisation de ST_Difference

Bonjour,

Je pense que la fonction approprié est ST_SPLIT disponible sur PostGIS. Une documentation:

http://www.h2gis.org/docs/dev/ST_Split/


Nicolas Fortin
Laboratoire d'Acoustique Environnementale - Ifsttar
OrbisGIS, Spatial DB , Noise map

Hors ligne

 

#5 Fri 10 April 2015 11:26

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

Re: Problème d'utilisation de ST_Difference

guil31 a écrit:

J'ai fait des tests complémentaires sur des jeux données plus simple.

Test 1:
- une ligne composée d'un segment [AB]
- une ligne composée de deux segments [AC] et [CD] avec C snapé sur le segment [AB]
La fonction arrive à découper [AB] en C et je récupère un segment [CB]

Test 2:
- une ligne composée de trois segments [AB], [BC] et [CD]
- une ligne composée d'un segment [BE] avec E snapé sur le segment [AB]
- une ligne composée de deux segments [BC] et [CF] avec F snapé sur [CD]
Dans ce cas aucun découpage n'est fait en E et en F et je ne récupère pas [AE] et [FD]

=> Est-ce que finalement ST_Difference fonctionne bien quand le résultat nécessite de découper une ligne pour récupérer plusieurs sous-segments?
Pour précision j'utilise PostGIS 2.0.6 et PostgreSQL 9.1


Vous auriez les données de test ?

nico

Hors ligne

 

#6 Fri 10 April 2015 11:47

guil31
Participant actif
Date d'inscription: 22 Jan 2013
Messages: 79

Re: Problème d'utilisation de ST_Difference

ci-joint mes données tests (au format shp)

Pour ligne_1 et ligne_2, je souhaite récupérer les segments de ligne_2 qui ne sont pas recouverts par ligne_1
Pour route_1 et route_2, je souhaite récupérer les segments de route_1 qui ne sont pas recouverts par route_2


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

Hors ligne

 

#7 Fri 10 April 2015 12:22

guil31
Participant actif
Date d'inscription: 22 Jan 2013
Messages: 79

Re: Problème d'utilisation de ST_Difference

J'ai également lancé st_difference sur mes données réelles, mais avant j'ai effectué une union sur ma table route_intersect (le réseau partiel).
C'est presque ce que je veux, sauf que dans mon résultat il n'y a pas de découpage de route_selection aux extrémités de route_intersect.
ci-joint une capture d'écran

Par ailleurs j'ai voulu tester le split en effectuant le découpage de ligne (route_selection) par des points (extrémités de route_intersect)
Visiblement j'ai des geometrycollection qui ne passent pas dans le split ... je cherche donc aussi comment passer ces objets en points.


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

Hors ligne

 

#8 Fri 10 April 2015 12:32

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

Re: Problème d'utilisation de ST_Difference

Merci,

Voici le résultat de la différence de ligne_2 - ligne_1 : (cf img)

Code:

select a.gid as gid_a, b.gid as gid_b, st_difference(b.geom, a.geom)
from ligne_1 a join ligne_2 b on st_intersects (a.geom, b.geom);

On obtient bien deux lignes: la ligne_2 elle meme lors de la différence avec la ligne_1 qui la touche en ses sommets
le segment de ligne_2 lors de la différence avec la ligne_1 qui recouvre ligne_2:

Suivant le résultat que vous voulez obtenir, il faut rajouter des conditions (ne prendre en compte que les lignes qui s'overlap par exemple), ou filtrer les qui sont identiques après la différence: Là, seul le segment non partagé est retenu:

Code:

with tmp as (
  SELECT
      a.gid AS gid_a,
      b.gid AS gid_b,
      st_difference(b.geom, a.geom) as geom
    FROM ligne_1 a JOIN ligne_2 b ON st_intersects(a.geom, b.geom)
) select t.* 
  from tmp t 
where not exists (
  select null 
  from ligne_2 l 
  where l.geom = t.geom
);

Comme le disait Nicolas, st_split peut être intéressant aussi suivant votre contexte. Par contre, il y a des restrictions sur la géometrie qui sert de splitter.

Avec vos données:

Code:

select a.gid as gid_a, b.gid as gid_b, st_split(st_geometryN(b.geom, 1), st_geometryN(a.geom, 1))
from ligne_1 a join ligne_2 b on st_intersects (a.geom, b.geom);

12:27:33 [XX000] ERROR: Splitter line has linear intersection with input

Nicolas


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

Hors ligne

 

#9 Fri 10 April 2015 12:53

VielOu
Participant occasionnel
Lieu: Toulouse
Date d'inscription: 20 Nov 2012
Messages: 12
Site web

Re: Problème d'utilisation de ST_Difference

Bonjour,

L'affectation d'un St_Union à la couche d'intersection permettrait d'aller vers le résultat attendu.
Partitionnement gratuit

Cordialement,

Vivien VIEL

Hors ligne

 

#10 Fri 10 April 2015 14:49

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

Re: Problème d'utilisation de ST_Difference

Oui effectivement, l'union de la couche de découpe est nécessaire pour obtenir les segments voulus.

Dans le jeu de données route_1 et route_2, il y a en plus un problème de précision des coordonnées: le point terminal de la ligne 2 ne touche pas la ligne 1, à la précision des coordonnées près: les deux segments ne sont pas confondus et lors du calcul, le découpage s'arrête au sommet commun.

Il faudrait nettoyer les données avec st_snapToGrid ou des opérations de snapping des réseaux avant l'opération.

Nico

Hors ligne

 

#11 Mon 13 April 2015 10:09

guil31
Participant actif
Date d'inscription: 22 Jan 2013
Messages: 79

Re: Problème d'utilisation de ST_Difference

Bonjour,

ok pour ST_Union et pour les filtres.

Je n'avais pas vu que mes données n'étaient pas snapés (pourtant je les avait crée sous ArcGis en utilisant un snap sur la ligne .....)

Finalement pour mes données réelles j'ai toujours le problème: pas de découpage de route_selection aux extrémités de route_intersect (cf post du 10 avril à 12:22)

Hors ligne

 

#12 Tue 14 April 2015 10:30

guil31
Participant actif
Date d'inscription: 22 Jan 2013
Messages: 79

Re: Problème d'utilisation de ST_Difference

J'ai fini par y arriver et voici la solution que j'ai trouvé
sachant qu'au départ j'avais des routes (route) et des polygones (buffer) et que je voulais générer deux tables:
- les routes à l'intérieur des polygones (route_inside)
- les routes à l'extérieur des polygones  (route_outside)
avec un découpage des routes à l'intersection des routes et des polygones

J'ai rencontré beaucoup de difficultés liées au fait qu'un point n'est jamais exactement sur une ligne .... tout ca c'est une question de tolérance
et je trouve surprenant que ST_Diffrence ne découpe pas les lignes ... mais utilise le sommet le plus proche.

Du coup j'ai utilisé la méthode suivante (on peut certainement optimiser):
- création du contour de buffer (buffer_contour)
- création des points à l'intersection de buffer et de route (point_intersect)
- découpage des routes au niveau de ces points (route_decoup). Pour cela j'ai utilisé le code proposé par Nicolas Ribot dans son post du 27/04/2013: http://georezo.net/forum/viewtopic.php?id=84911 (merci Nicolas)
- ajout d'un identifiant unique dans le table route_decoup
- création de la table route_inside contenant les objets de route_decoup situés à l'intérieur de buffer (pour cela j'ai utilisé le point situé au milieu de chaque objet de route_decoup)
- création  de la table route_outside contenant les objets de route_decoup situés à l'extérieur de buffer (ce sont les identifiants de route_decoup qui ne sont pas dans route_inside)

Et voici le code:

Code:

-- création du contour de buffer: buffer_contour
CREATE table buffer_contour AS SELECT ST_Boundary(the_geom) as the_geom FROM buffer;

--- création de la table des points issus de l'intersection de route avec buffer_contour: point_intersect
CREATE table point_intersect AS 
    SELECT gid, id,(st_dump(st_force_2d(ST_Intersection(buffer_contour.the_geom, (st_dump(st_force_2d(route.the_geom))).geom)))).geom as the_geom 
    FROM buffer_contour, route;

--- création des routes découpées par point_intersect: route_decoup 
CREATE TABLE route_decoup AS
SELECT decoup.gid, decoup.the_geom
FROM
    -- 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 route 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 route l

        UNION ALL

        -- calcul des positions des points par rapport aux lignes
        select l.gid, st_line_locate_point(l.the_geom, p.the_geom) as  l
        from route l, point_intersect p
        where st_dwithin(l.the_geom, p.the_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.the_geom, loc1.l, loc2.l) as the_geom 
    from loc_with_idx loc1, loc_with_idx loc2, route l
    where l.gid = loc1.gid
    and loc1.gid = loc2.gid
    and loc2.idx = loc1.idx+1) AS decoup;

-- ajout d'un identifiant unique pour chaque route_decoup
ALTER TABLE route_decoup ADD COLUMN id SERIAL NOT NULL;

-- création d'une table des tronçons de route à l'intérieur du buffer
CREATE TABLE Route_inside AS
    SELECT route_decoup.id as id, route_decoup.gid as gid, Route_decoup.the_geom as the_geom
    FROM 
        route_decoup, 
        (SELECT route_decoup_centre.id as id, route_decoup_centre.gid as gid, route_decoup_centre.the_geom as the_geom
        FROM 
            buffer,
            (SELECT route_decoup.id as id, route_decoup.gid as gid, ST_Line_Interpolate_Point(route_decoup.the_geom, 0.5) as the_geom FROM route_decoup) AS route_decoup_centre            
        WHERE ST_within(route_decoup_centre.the_geom, buffer.the_geom)) AS route_decoup_centre_inside
    WHERE route_decoup.id = route_decoup_centre_inside.id;

-- création d'une table des tronçons de route à l'extérieur du buffer
CREATE TABLE Route_outside AS
    SELECT route_decoup.id as id, route_decoup.gid as gid, route_decoup.the_geom as the_geom
    FROM route_decoup
    WHERE route_decoup.id NOT in (SELECT Route_inside.id FROM Route_inside);

Hors ligne

 

Pied de page des forums

Powered by FluxBB