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

Printemps des cartes 2024

#1 Fri 05 September 2014 20:23

ousao
Juste Inscrit !
Date d'inscription: 5 Sep 2014
Messages: 1

Calcul distance entre différentes lignes d'une même table

Bonjour,

Merci de votre attention, mon problème est le suivant:

J'ai une base de données avec des origines et destinations, je dispose des lon et lat en points pour les deux, et de géométrie dans la table du type: point_origine geometry(Point,4269), point_destination geometry(Point,4269).

Je souhaite calculer la distance entre chaque point origine et toutes les destinations de la même table et ne garder que la distance minimale. En gros je souhaite obtenir une nouvelle table qui aura comme lignes: garder le lieu de destination des personnes mais en modifiant leur lieu d'origine de tel sorte qu'il soit le plus proche de leur lieu de destination et qu'il figure parmi les différents points origines de la table de base. Les colonnes de la nouvelle table seront:  lon origine, lat origine, lon dest, lat dest, distance

Merci de votre aide!!

Dernière modification par ousao (Fri 05 September 2014 20:24)

Hors ligne

 

#2 Mon 08 September 2014 10:42

sigdu80
Participant actif
Date d'inscription: 2 Sep 2010
Messages: 112

Re: Calcul distance entre différentes lignes d'une même table

Bonjour ousao,

nouvelle table :
ses champs : lon origine, lat origine, lon dest, lat dest, distance
regrouper par : lieu de destination
opération d'agrégation : distance la plus courte, entre les coordonnées de destination et d'origine

j'ai l'impression qu'il faudrait faire les choses en plusieurs étapes mais :
- je mène une réflexion rapide pour arriver au but, sans souci d'être optimisé
- un jeu d'essai que tu fournirais, permettrait aux membres de tester des choses
- avec des WINDOW, ce serait peut-être plus optimisée mais je ne maîtrise pas assez bien pour dire çà de tête.
- il y a peut-être des fonctions postGIS qui pourrait aider plus

ne faudrait-il pas chercher en 1er donc, la distance min par coordonnées de point de destination ?

Code:

SELECT lon_dest,lat_dest,min(st_distance(METTRE LES BONNES INFOS)) as distance_min
    FROM tableOrigine 
    GROUP BY lon_dest,lat_dest

puis connaître les coordonnées des points d'origine, correspondant à la distance la plus courte :

Code:

SELECT lon origine, lat origine, lon dest, lat dest,table_distancemin.distance_min
FROM tableOrigine
   JOIN 
    (SELECT lon_dest,lat_dest,min(st_distance(METTRE LES BONNES INFOS)) as distance_min
    FROM tableOrigine 
    GROUP BY lon_dest,lat_dest) table_distancemin  ON (tableOrigine.lon_dest = table_distancemin.lon_dest AND tableOrigine.lat_dest = table_distancemin.lat_dest 
WHERE st_distance(METTRE LES BONNES INFOS tableOrigine) = st_distance(METTRE LES BONNES INFOS table_distancemin) 
ORDER BY lon_dest,lat_dest;

Ensuite, on rebalaie la table d'origine (pour avoir autant de ligne entre la table d'origine et la nouvelle table) en récupérant les infos de distance et de coordonnées du point d'origine le plus proche, et on injecte dans la nouvelle table avec un INSERT INTO ... SELECT.


Mais qu'en penses-tu ?

Dernière modification par sigdu80 (Mon 08 September 2014 11:09)

Hors ligne

 

#3 Mon 08 September 2014 11:20

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

Re: Calcul distance entre différentes lignes d'une même table

Bonjour,

Les points étant en lat/long, vous pouvez utilisez le type GEOGRAPHY, qui permet un calcul des distances en tenant compte de la forme de la terre (calcul en coordonnées sphériques). Vous pouvez aussi utiliser la fonction st_distance_spheroid() sur votre table, pour calculer des distances exactes.
Vous pouvez également stocker le résultat final sous forme de LINESTRING, ou le startPoint serait le point de départ et le endPoint le point de destination.

Pour convertir votre table en geography WGS 84:

alter table trajets alter column point_origine type geography(point, 4326) using st_Transform(point_origine, 4326)::geography;
alter table trajets alter column point_destination type geography(point, 4326) using st_Transform(point_destination, 4326)::geography;

Il y a plusieurs façons de faire en fonction de la volumétrie de la table:

• si la table contient peu de lignes, un calcul de toutes les trajectoires possibles pour chaque destination, en ne gardant que la plus courte permet de répondre à la question. Cette méthode n'utilise pas les index, sauf si vous savez que les distances minimales ne seront jamais supérieures à une certaine distance. Les Windows Functions sont utiles, dans ce cas.

Le principe est de faire un croisement entre la table et elle même, pour pouvoir calculer tous les couples (origine-destination) et de classer par distance la plus petite pour chaque identifiant de destination:

Si Utilisation de distance_spheroid (point WGS 84) plutot que la reprojection de la table:

oid: identifiant du point_origine, did: identifiant du point destination, id: identifiant unique de la table trajet (PK)

Code:

with tmp as (
  select t.oid, t1.did, t1.id, t.point_origine, t1.point_destination, 
    row_number() over (PARTITION BY t1.did order by st_distance_Spheroid(t.point_origine, t1.point_destination, 'SPHEROID["WGS 84",6378137,298.257223563]')) as rn
  from trajets t, trajets t1
  
) select t.id, t.did, t.oid,
    -- construction de la ligne de trajet entre une destination et l'origine la plus proche
    st_makeLine(point_origine, point_destination) as geom
from tmp t
where rn = 1;

• Si la table contient bcp de lignes, il faut mieux utiliser un index sur les plus proches voisins, en cherchant pour chaque ligne le point le plus proche de chaque destination.
Cet opérateur de plus proche voisin ne marche que dans la clause ORDER BY d'une requete: il donne le point le plus proche d'un point donné.
Ici, on veut tester toutes les combinaisons entre destinations et origines pour trouver le trajet le plus court, on utilise l'opérateur dans une sous requete exprimée dans le SELECT:

La requete est plus complexe à écrire. (edit: en fait non, moins complexe meme wink )

Code:

SELECT DISTINCT on (t.did) t.did, t.id as dest_id, 
  (
    select t1.oid
    from trajets t1
    order by t1.point_origine <-> t.point_destination
    limit 1) as ori_id
from trajets t;

Pour reconstruire des lignes de trajets uniques comme dans l'exemple 1, il faut refaire des jointures à partir de cette requetes vers la table trajets: deux jointures pour pouvoir retrouver la ligne du point d'origine et la ligne du point destination.

La sous requete a été modifiée avec un DISTINCT ON pour faire apparaitre l'identifiant unique d'une ligne de destination.

Code:

with tmp as (
  SELECT DISTINCT on (t.did) t.did, t.id as dest_id, 
    (
      SELECT t1.id
      FROM trajets t1
      ORDER BY t1.point_origine <-> t.point_destination
      LIMIT 1) AS ori_id
  FROM trajets t
) select t.dest_id, st_makeline(tr1.point_origine, tr2.point_destination) as geom
from tmp t join trajets tr1 on t.ori_id = tr1.id
  join trajets tr2 on t.dest_id = tr2.id;

Nicolas

En ligne

 

Pied de page des forums

Powered by FluxBB