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


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

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

 

Pied de page des forums

Powered by FluxBB