#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/
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
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
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.
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
Hors ligne
#9 Fri 10 April 2015 12:53
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