Pages: 1
- Sujet précédent - [PostGis] Découpage d'itinéraire en tronçons -> st_Line_Locate_Point() - Sujet suivant
#1 Tue 22 January 2013 09:54
- guil31
- Participant actif
- Date d'inscription: 22 Jan 2013
- Messages: 79
[PostGis] Découpage d'itinéraire en tronçons -> st_Line_Locate_Point()
Bonjour,
Je suis en train de découper des itinéraires de type LineString en tronçons à partir d'arrêts de type Point.
Pour chaque itinéraire je connais l'enchainement des arrêts qu'il dessert.
Donc pour chaque tronçon que je veux récupérer je connais les points de début et de fin.
Les arrêts ne sont pas snapés sur les itinéraires.
J'utilise donc st_Line_Locate_Point() pour localiser les arrêts sur l'itinéraire
et ensuite st_Line_SubString pour extraire le tronçon de l'itinéraire
Ca donne ca:
St_Line_SubString(itineraire.the_geom,st_Line_Locate_Point(itineraire.the_geom,arret_deb.the_geom),st_Line_Locate_Point(itineraire.the_geom,arret_fin.the_geom))
Ceci marche très bien SAUF quand l'itinéraire forme une boucle et passe plusieurs fois devant l'arrêt.
A ce moment-là st_Line_Locate_Point() me retourne une des solutions seulement et pas forcément celle qui m'intéresse.
=> Est-ce qu'il y a moyen de récupérer toutes les positions possibles de la projection du point sur la ligne?
=> Ou est-ce qu'il y a moyen de forcer à prendre la plus petite position?
=> Ou est-ce que qq a une autre idée?
Merci pour votre aide
Hors ligne
#2 Tue 22 January 2013 12:12
- Nicolas Ribot
- Membre
- Lieu: Toulouse
- Date d'inscription: 9 Sep 2005
- Messages: 1554
Re: [PostGis] Découpage d'itinéraire en tronçons -> st_Line_Locate_Point()
Bonjour,
Pourriez-vous nous donner la requete complete, notamment pour voir comment vous gérez l'enchainement des arrets pour un trajet.
Nicolas
Hors ligne
#3 Tue 22 January 2013 12:42
- guil31
- Participant actif
- Date d'inscription: 22 Jan 2013
- Messages: 79
Re: [PostGis] Découpage d'itinéraire en tronçons -> st_Line_Locate_Point()
J'ai :
- une table itineraire avec des objets linéaires et un identifiant itineraire => code_iti
- une table arret avec des objets ponctuels et un identifiant arret => code_arret
- une table tia avec les tronçons inter-arrêt et pour chacun d'eux je retrouve l'identifiant de l'itinéraire ainsi que les identifiants des arrêts de début et de fin de tronçon => code_iti, code_arret_deb et code_arret_fin
Je souhaite mettre à jour la géométrie de ma table des tronçon tia
(Le sens de digitalisation des itinéraires n'est pas forcément celui qui correspond à l'ordre des arrêts c'est pourquoi je traite différents cas)
UPDATE tia SET the_geom =
CASE
WHEN st_Line_Locate_Point(itineraire.the_geom,deb.the_geom)<st_Line_Locate_Point(itineraire.the_geom,fin.the_geom)
THEN st_Line_SubString(itineraire.the_geom,st_Line_Locate_Point(itineraire.the_geom,deb.the_geom),st_Line_Locate_Point(itineraire.the_geom,fin.the_geom))
WHEN st_Line_Locate_Point(itineraire.the_geom,deb.the_geom)>st_Line_Locate_Point(itineraire.the_geom,fin.the_geom)
THEN st_Line_SubString(itineraire.the_geom,st_Line_Locate_Point(itineraire.the_geom,fin.the_geom),st_Line_Locate_Point(itineraire.the_geom,deb.the_geom))
WHEN st_Line_Locate_Point(itineraire.the_geom,deb.the_geom)=st_Line_Locate_Point(itineraire.the_geom,fin.the_geom)
THEN st_MakeLine(deb.the_geom, fin.the_geom)
END
FROM itineraire, arret as deb, arret as fin
WHERE deb.code_arret = tia.code_arret_deb and fin.code_arret = tia.code_arret_fin AND tia.code_iti = itineraire.code_iti;
Hors ligne
#4 Tue 22 January 2013 15:13
- Nicolas Ribot
- Membre
- Lieu: Toulouse
- Date d'inscription: 9 Sep 2005
- Messages: 1554
Re: [PostGis] Découpage d'itinéraire en tronçons -> st_Line_Locate_Point()
Merci pour ces précisions.
st_line_locate_point projete sur la ligne le point le plus proche d'elle. Il ne peut donc y avoir qu'un seul résultat
Si j'ai bien compris votre problématique, vous voudriez "enlever" la partie du trajet qui est deja "passée" devant un arret, histoire de ne garder que le bout de ligne qui n'a pas encore été découpé en tronçon.
Une solution que je vois pour faire cela est de soustraire a l'itinéraire courant les troncons déjà calculés, histoire de ne conserver, au fur et a mesure, que les parties d'itinéraires non encore découpées en troncon.
Nicolas
Hors ligne
#5 Tue 22 January 2013 15:51
- tumasgiu
- Membre
- Lieu: Ajaccio
- Date d'inscription: 5 Jul 2010
- Messages: 1160
Re: [PostGis] Découpage d'itinéraire en tronçons -> st_Line_Locate_Point()
Salut,
je dis peut être une bêtise mais est ce que passer à une vision topologique de la chose ne serait pas une bonne idée ?
Hors ligne
#6 Tue 22 January 2013 16:13
- Nicolas Ribot
- Membre
- Lieu: Toulouse
- Date d'inscription: 9 Sep 2005
- Messages: 1554
Re: [PostGis] Découpage d'itinéraire en tronçons -> st_Line_Locate_Point()
Pour un traitement general du probleme, oui surement.
Dans le cas du probleme rencontré, il faudrait de tout facon construire la topologie et donc "projeter" d'une facon ou d'une autre les arrets sur les itineraires pour pouvoir les découper.
J'ai compris que c'est cette operation de projection qui ne marche pas dans tous les cas.
Nicolas
Hors ligne
#7 Wed 23 January 2013 09:03
- guil31
- Participant actif
- Date d'inscription: 22 Jan 2013
- Messages: 79
Re: [PostGis] Découpage d'itinéraire en tronçons -> st_Line_Locate_Point()
Oui c'est bien l'opération de projection qui me pose problème.
En fait dans le cas particulier où mon itinéraire fait une boucle et revient ensuite sur lui-même et où l'arrêt se trouve à l'endroit où l'itinéraire passe 2 fois alors il y a bien 2 solutions pour st_Line_Locate_Point() ...
... et je ne récupère pas forcément la bonne.
Pour mieux comprendre le problème j'ai fait un petit schéma en pièce jointe. (Bien sûr en réalité les tronçons se superposent exactement au tracé, j'ai dédoublé les traits juste pour la compréhension.)
Hors ligne
#8 Wed 23 January 2013 16:29
- tumasgiu
- Membre
- Lieu: Ajaccio
- Date d'inscription: 5 Jul 2010
- Messages: 1160
Re: [PostGis] Découpage d'itinéraire en tronçons -> st_Line_Locate_Point()
Sans données supplémentaire, j'ai du mal à imaginer comment tu pourrais te débrouiller.
Les directions possibles des différentes tronçons visibles sur ton schema pourraient peut être t'être utiles.
Et je pense qu'avant de travailler, tu devrais décomposer tes itinéraires en entités plus simple, par exemple un graphe.
Hors ligne
#9 Tue 05 February 2013 10:18
- guil31
- Participant actif
- Date d'inscription: 22 Jan 2013
- Messages: 79
Re: [PostGis] Découpage d'itinéraire en tronçons -> st_Line_Locate_Point()
La remarque de Nicolas par rapport à la soustraction de l'itinéraire courant des tronçons déjà calculés m'a donné une autre idée que j'ai mis en application et testé:
Pour chaque tronçon que je veux extraire, je me base non plus sur l'itinéraire entier, mais sur le morceau d'itinéraire qui va de :
- l'arrêt fin de tronçon, du tronçon précédent
- à l'arrêt fin de tronçon, +1.
Sur mon schéma (http://georezo.net/forum/attachment.php?item=5111) ça donne :
Pour l'arrêt 2:
- je récupère les positions des arrêts 1 et 3
- je récupère la position de l'arrêt 2 en me basant sur la portion d'itinéraire allant de 1 à 3 au lieu de l'itinéraire en entier
ainsi 2 est forcément snapé sur le premier passage entre 1 et 3.
Pour l'arrêt 3:
- je récupère la position de l'arrêt 4 en m'appuyant sur la portion d'itinéraire qui va de 2 à la fin de l'itinéraire
- je récupère la position de l'arrêt 3 en me basant sur la portion d'itinéraire allant de 2 à 4 au lieu de l'itinéraire en entier
.... etc
Pour ce faire j'ai ajouté des champs dans ma table des tronçons:
Code:
CREATE TABLE work.tia ( code_iti character varying, -- Code de l'itinéraire arret_deb character varying, -- Code de l'arrêt de début de tronçon arret_fin character varying, -- Code de l'arrêt de fin de tronçon arret_fin_plus character varying, -- Code de l'arrêt suivant l'arrêt de fin de tronçon ordre integer, -- Ordre d'apparition du tronçon dans l'itinéraire terminus integer, -- Egal à 1 si le tronçon est le dernier tronçon de l'itinéraire, sinon 0 pos_deb numeric(7,6), -- Position sur l'itinéraire de l'arrêt de début du tronçon pos_fin numeric(7,6), -- Position sur l'itinéraire de l'arrêt de fin de tronçon pos_fin_plus numeric(7,6), -- Position, sur l'itinéraire, de l'arrêt qui suit l'arrêt de fin de tronçon length_iti numeric(13,6), -- Longueur de l'itinéraire length_deb_fin_plus numeric(13,6), -- Longueur du tronçon allant de l'arrêt de début à l'arrêt qui suit l'arrêt de fin de tronçon length_deb_fin_iti numeric(13,6), -- Longueur du tronçon allant de l'arrêt de début à la fin de l'itinéraire the_geom geometry(LineString,2154) -- Géométrie des tronçons ) WITH ( OIDS=FALSE ); ALTER TABLE work.tia OWNER TO postgres;
Puis j'ai fait une fonction en plpgsql.
J'ai blindé le tout avec des tests dans tous les sens car mes données ne sont pas nickel.
Voici le code sql (qui peut très certainement être optimisé, mais bon ça marche!)
Les résultats sont plutôt concluants: il me reste encore des erreurs mais c'est plutôt lié à la qualité des donnée sources...
Code:
-- FONCTION maj_tia() - Recherche des positions des arrêts deb, fin et fin + 1 sur l'itinéraire CREATE OR REPLACE FUNCTION work.maj_tia() RETURNS integer AS $BODY$ DECLARE i integer := 0; BEGIN -- Recherche du nombre maximum de tronçon EXECUTE 'SELECT max(ordre) from work.tia' INTO i; -- Pour le dernier tronçon, il n'existe pas d'arrêt fin de tronçon +1 => La position de [arrêt de début + 2] est la fin de l'itinéraire soit 1 UPDATE work.tia SET pos_fin_plus= 1 WHERE work.tia.terminus = 1; FOR j IN 1..i LOOP -- Recherche des positions de [arrêt de début] : Récupération de la position de l'arrêt de fin de tronçon du tronçon précédent UPDATE work.tia SET pos_deb = tia_moins.pos_fin FROM work.tia as tia_moins WHERE tia_moins.code_iti = work.tia.code_iti AND tia_moins.ordre = work.tia.ordre -1 AND tia_moins.arret_fin = work.tia.arret_deb AND work.tia.ordre =j; -- Dans le cas du 1er tronçon ou quand la position de l'arrêt de fin de tronçon du tronçon précédent est inconnue => Calcul de la position en se basant sur l'itinéraire en entier UPDATE work.tia SET pos_deb = st_Line_Locate_Point(carto.itineraire.the_geom,deb.the_geom) FROM carto.itineraire, cimm.arret as deb WHERE carto.itineraire.code_iti = work.tia.code_iti AND deb.code_arret = work.tia.arret_deb AND work.tia.pos_deb IS NULL AND work.tia.ordre =j; -- Calcul de la longueur du tronçon [[arrêt début] -> [fin de l'itinéraire]] UPDATE work.tia SET length_deb_fin_iti = st_length(st_Line_SubString(carto.itineraire.the_geom, work.tia.pos_deb, 1)) FROM carto.itineraire WHERE carto.itineraire.code_iti = work.tia.code_iti AND work.tia.ordre = j; -- Recherche de la position de [arrêt de début + 2] UPDATE work.tia SET pos_fin_plus = WHEN fin_plus.the_geom is NULL THEN 1 ELSE st_Line_Locate_Point(st_Line_SubString(carto.itineraire.the_geom, pos_deb, 1),fin_plus.the_geom)*length_deb_fin_iti / length_iti + pos_deb FROM carto.itineraire, cimm.arret as fin_plus WHERE carto.itineraire.code_iti = work.tia.code_iti AND fin_plus.code_arret = work.tia.arret_fin_plus AND work.tia.ordre =j AND work.tia.terminus IS NULL AND pos_deb <>1; -- Calcul de la longueur du tronçon [[arrêt début] -> [arrêt début + 2]] UPDATE work.tia SET length_deb_fin_plus = CASE WHEN work.tia.pos_deb < work.tia.pos_fin_plus AND work.tia.pos_fin_plus <= 1 THEN st_length(st_Line_SubString(carto.itineraire.the_geom, work.tia.pos_deb, work.tia.pos_fin_plus)) WHEN work.tia.pos_fin_plus < work.tia.pos_deb AND work.tia.pos_deb <= 1 THEN st_length(st_Line_SubString(carto.itineraire.the_geom, work.tia.pos_deb, 1)) END FROM carto.itineraire WHERE carto.itineraire.code_iti = work.tia.code_iti AND work.tia.ordre = j; -- Recherche de la position de [arrêt fin] du tronçon sur le tronçons [[arrêt début] -> [arrêt début + 2]] UPDATE work.tia SET pos_fin = CASE WHEN pos_deb < pos_fin_plus AND pos_fin_plus <= 1 AND GeometryType(st_Line_SubString(carto.itineraire.the_geom, pos_deb, pos_fin_plus)) = 'LINESTRING' THEN st_Line_Locate_Point(st_Line_SubString(carto.itineraire.the_geom, pos_deb, pos_fin_plus),fin.the_geom) *length_deb_fin_plus/ length_iti + pos_deb WHEN pos_fin_plus < pos_deb AND pos_deb <= 1 AND GeometryType(st_Line_SubString(carto.itineraire.the_geom, pos_deb, 1)) = 'LINESTRING' THEN st_Line_Locate_Point(st_Line_SubString(carto.itineraire.the_geom, pos_deb, 1),fin.the_geom) *length_deb_fin_plus/ length_iti + pos_deb END FROM carto.itineraire, cimm.arret as fin WHERE carto.itineraire.code_iti = work.tia.code_iti AND fin.code_arret = work.tia.arret_fin AND work.tia.ordre =j; END LOOP; RETURN i; END $BODY$ LANGUAGE 'plpgsql'; -- FIN de maj_tia() -- Execution de maj_tia() select work.maj_tia();
Quand j'ai la position de tous les arrêts sur l'itinéraire il ne me reste plus qu'à extraire les portions d'itinéraires avec st_Line_SubString()
Code:
-- Découpage des itinéraires en tronçons UPDATE work.tia SET the_geom = st_Line_SubString(carto.itineraire.the_geom,pos_deb, pos_fin) FROM carto.itineraire WHERE carto.itineraire.code_iti = work.tia.code_iti pos_deb < pos_fin;
Hors ligne
#10 Tue 05 February 2013 12:05
- Nicolas Ribot
- Membre
- Lieu: Toulouse
- Date d'inscription: 9 Sep 2005
- Messages: 1554
Re: [PostGis] Découpage d'itinéraire en tronçons -> st_Line_Locate_Point()
Joli !
Merci pour le suivi du sujet.
Nicolas
Hors ligne
Pages: 1
- Sujet précédent - [PostGis] Découpage d'itinéraire en tronçons -> st_Line_Locate_Point() - Sujet suivant