Nous utilisons des cookies pour vous garantir la meilleure expérience sur notre site. Si vous continuez à utiliser ce dernier, nous considèrerons que vous acceptez l'utilisation des cookies. J'ai compris ! ou En savoir plus !.
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 27 March 2018 12:27

bruhnild
Participant actif
Lieu: Lyon
Date d'inscription: 7 Jun 2014
Messages: 130

Segmenter multilinestring en fonction d'une distance et création point

Bonjour à toutes et à tous,

J’ai une table spatiale d’adresses avec pour chaque entité adresse une géométrie de routes. Ainsi pour un type de voie + nom de voie (ex : avenue habib bourguiba) je vais avoir 20 adresses avec la même géométrie de route.
-    28 avenue habib bourguiba
-    29 avenue habib bourguiba
-    30 avenue habib bourguiba
-    21 avenue habib bourguiba
-    …
-    48 avenue habib bourguiba
Connaissant la longueur de chaque route (st_length) et le nombre d’adresses (intervalle) pour chacune d’entre elle, je peux obtenir st_length/intervalle (intervalle_m) soit la distance théorique entre chaque point adresse.
J’aimerais pouvoir segmenter mes lignes (routes)  en fonction de intervalle_m et créer un point (adresse) à chaque brisure de lignes. J’ai essayé sous postgis les fonctions St_Segmentize

Code:

(SELECT ST_DumpPoints( (ST_Segmentize((geom),intervale_m -- st_length/intervalle 
))) as geom
from ban.v_ban_travail_generate_series
group by  geom, intervale_m )

et St_interpolate_points

Code:

(select     
id, 
ST_line_interpolate_point(st_makeline(st_linemerge(geom)),fraction --1/intervalle
) as geom from  ban.v_ban_travail_generate_series 
group by id, fraction)

mais les résultats ne sont pas bons.

Auriez vous une idée de comment procéder ?

Merci d’avance pour vos retours !

Marine.

Dernière modification par bruhnild (Wed 28 March 2018 08:12)

Hors ligne

 

#2 Wed 28 March 2018 11:23

tumasgiu
Membre
Lieu: Ajaccio
Date d'inscription: 5 Jul 2010
Messages: 1160

Re: Segmenter multilinestring en fonction d'une distance et création point

Voici un exemple très simplifié,
l'astuce est d'utiliser la window function lag qui permet de récupérer
la valeur d'une colonne de l''enregistrement précédent.

Code:

with foo as (select 'LINESTRING(0 0, 0 100)'::geometry geom)
, points as (select s, st_line_interpolate_point(geom, s / st_length(geom)) p ,geom
                FROM foo, generate_series(1, 10) s )
SELECT s, st_makeline(coalesce(lag(p) OVER (ORDER BY s), st_startpoint(geom)) , p) m 
FROM points

Hors ligne

 

#3 Wed 28 March 2018 16:46

bruhnild
Participant actif
Lieu: Lyon
Date d'inscription: 7 Jun 2014
Messages: 130

Re: Segmenter multilinestring en fonction d'une distance et création point

Merci tumasgiu pour l'idée!

J'ai essayé de reproduire ton exemple

Code:

with interpolate as 
(select id_voie, geom , num_deb_fr, num_fin_fr from ban.v_ban_travail), 
points as (select id_voie, s, ST_line_interpolate_point(st_makeline(st_linemerge(geom)), s / st_length(geom)) p ,geom FROM interpolate, generate_series(num_deb_fr,num_fin_fr) s group by s.s, interpolate.geom, interpolate.id_voie)
SELECT id_voie, s as serie, st_makeline(coalesce(lag(p) OVER (ORDER BY s), st_startpoint(geom)) , p) new_geom
FROM points

mais j'ai une erreur de ce type :  ERREUR:  line_interpolate_point: 2nd arg isn't within [0,1]

Lorsque j'écris des valeurs dans le generate serie j'ai bien un résultat mais il ne correspond pas à ce que je souhaite (voir capture resultat_obtenu)

Code:

with interpolate as 
(select id_voie, geom , num_deb_fr, num_fin_fr from ban.v_ban_travail), 
points as (select id_voie, s, ST_line_interpolate_point(st_makeline(st_linemerge(geom)), s / st_length(geom)) p ,geom FROM interpolate, generate_series(1,10) s group by s.s, interpolate.geom, interpolate.id_voie)
SELECT id_voie, s as serie, st_makeline(coalesce(lag(p) OVER (ORDER BY s), st_startpoint(geom)) , p) new_geom
FROM points

J'ai mis en PJ une capture du résultat attendu.

Dernière modification par bruhnild (Wed 28 March 2018 16:51)


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

Hors ligne

 

#4 Thu 29 March 2018 18:32

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

Re: Segmenter multilinestring en fonction d'une distance et création point

Bonjour,

Si je comprends bien, vous voulez a la fois segmenter les lignes et créer des points d'adresse ?

Pour la génération des points d'adresse, pas besoin de la longueur de la route: les fonctions de référencement linéaire se basent sur une fraction de la longueur de la ligne, entre 0 (debut) et 1 (fin de la ligne). Comme vous disposez des numéros d'adresse de debut et de fin, vous pouvez calculer le nombre d'adresses de chaque route. (dans votre exemple, 43 points d'adresse)

Il faut alors découper la route par autant de points d'adresse avec st_lineInterpolatePoint(route, fraction):

Code:

WITH tmp AS (
    SELECT
      id_voie,
      num_fin - num_debut AS num_add,
      geom
    FROM route
), tmp1 AS (
    SELECT
      t.*,
      g,
      g / num_add :: FLOAT AS fraction
    FROM tmp t CROSS JOIN generate_series(0, num_add) AS g
) select id_voie, g as num_add, st_lineinterpolatepoint(geom, fraction) as geom_add
from tmp1;

Requete à ajuster si on veut mapper les adresses aux extrémités de la route: adresses aux fractions 0 et 1 de la ligne (startPoint et endPoint de la route)

Pour segmenter la route, la méthode de tumasgiu est smart (pas besoin de faire un croisement sur la meme table), mais attention: dans l'exemple, la ligne n'est découpée que sur 10% de sa longueur:
Avec st_lineInterpolatePoint, si on veut découper une geom en n morceaux, il faut générer les valeurs: 0/n, 1/n, 2/n ... n/n pour découper entre 0 et 1.

Nico


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

Hors ligne

 

#5 Sun 01 April 2018 17:43

bruhnild
Participant actif
Lieu: Lyon
Date d'inscription: 7 Jun 2014
Messages: 130

Re: Segmenter multilinestring en fonction d'une distance et création point

Bonjour,

Merci beaucoup pour votre aide, j'ai pu terminer ma requête. Je suis sure qu'elle est simplifiable mais elle répond aux besoins. Certaines adresses ne commencent pas à systématiquement à 1. J'ai du faire une jointure sur le gid pour pouvoir retrouver mes bons numéros d'adresses:

Code:

CREATE OR REPLACE VIEW ban.v_ban AS 
SELECT 
a.gid, 
concat(b.num_voi_fr,'_',b.suffixe_fr,'_',b.nom_imm_fr,'_',b.typ_voi_fr,'_',b.nom_voi_fr,'_',b.ville_fr,'_',b.cd_post_fr)::varchar  as id,
b.id_voie, 
b.typ_voi_fr, b.typ_voi_ar, 
b.nom_voi_fr, b.nom_voi_ar, 
b.num_voi_fr, b.num_voi_ar,
b.suffixe_fr, b.suffixe_ar,
b.nom_imm_fr, b.nom_imm_ar, 
b.cd_post_fr, b.cd_post_ar,
b.ville_fr,b.ville_ar,
b.pays_fr, b.pays_ar,
b.cd_tour_fr, b.cd_tour_ar, 
b.ctr_rat_fr, b.ctr_rat_ar, 
b.nb_pro_fr, b.nb_pro_ar, 
b.nb_ind_fr, b.nb_ind_ar, 
b.nb_tot_af, b.nb_tot_ar, 
b.source, 
b.dat_maj, 
b.geonyme,  
a.geom
FROM
(SELECT
gid,
id_voie,
typ_voi_fr,
nom_voi_fr,
num_voi_fr+1 as num_voi_fr,
geom_add as geom
FROM
(WITH num_voi AS (
    SELECT
      id_voie,
      typ_voi_fr,
      nom_voi_fr,
      num_fin_fr - num_deb_fr AS num_voi_fr,
      geom
    FROM ban.v_ban_travail
), genere_add AS (
    SELECT
      t.*,
      g,
      g / num_voi_fr :: FLOAT AS fraction
    FROM num_voi t CROSS JOIN generate_series(0, num_voi_fr) AS g
) select row_number() over() AS gid, id_voie, typ_voi_fr,nom_voi_fr,g as num_voi_fr, st_lineinterpolatepoint(ST_LineMerge(geom), fraction) as geom_add
from genere_add)a)a
LEFT JOIN
(
SELECT   row_number() over() AS gid, * 
FROM
(SELECT
id_voie,
typ_voi_fr, typ_voi_ar, 
nom_voi_fr, nom_voi_ar, 
generate_series(num_deb_fr,num_fin_fr)as num_voi_fr,null::int as num_voi_ar, 
suffixe_fr, suffixe_ar, 
nom_imm_fr, nom_imm_ar, 
cd_post_fr, cd_post_ar,
ville_fr,ville_ar,
pays_fr, pays_ar,
cd_tour_fr, cd_tour_ar, 
ctr_rat_fr, ctr_rat_ar, 
nb_pro_fr, nb_pro_ar, 
nb_ind_fr, nb_ind_ar, 
nb_tot_af, nb_tot_ar, 
source, 
dat_maj, 
geonyme, 
geom
from ban.v_ban_travail)a)b
ON a.gid=b.gid
;

Je travaille sur une base de route avec beaucoup d'erreurs dans les noms d'adresses et je me retrouve fréquemment avec des bouts de tronçons portant le même nom à des endroits différents d'une unité administrative. J'ai du corriger quelques routes afin d'aller au bout de mes tests, sinon j'obtenais cette erreur: ERREUR: line_interpolate_point: 1st arg isn't a line

Hors ligne

 

Pied de page des forums

Powered by FluxBB