[OSM-dev-fr] Vagabond alpha

Vincent Pottier vpottier at gmail.com
Mer 14 Mar 14:18:30 GMT 2012


Bonjour,
Je vous soumets une version alpha d'un projet de calcul d’itinéraire 
pédestre.
http://osm7.openstreetmap.fr/~vincentpottier/wanderer/?zoom=16&lat=47.17563&lon=6.09716&layers=BTTT


C'est assez rigolo...
1/ On part de chez soi, avec l'outil de tracé de ligne, on trace une 
ligne jusqu'à la route|chemin|sentier... (ou un peu plus loin, histoire 
de calculer l'intersection).
2/ Le tracé est soumis au serveur
3/ Le serveur propose un panel de voies qui croisent le tracé.
4/ On choisit un embranchement dans le panel
5/ La partie parcourue s'ajoute à l'itinéraire
6/ La partie neuve devient le nouveau tracé
7/ #2

Donc plutôt qu'un programme de calcul de plus court chemin (avec ou sans 
pondération), l'idée est de construire le chemin par itération.

Il est probable que ça ne marche pas bien. Ouvrez firebug et guettez les 
erreurs 500.

En local, sur ma machine, le programme tourne mieux :
* Je peux relancer apache et n'ai pas de problème d'ancienne version de 
fichier python en cache de threads.
Par exemple l'appel de
http://osm7.openstreetmap.fr/~vincentpottier/wanderer/ajax.py/?action=wander&forward=1&wkt=LINESTRING(6.0936838571167%2047.174856940402%2C6.0963660661317%2047.177161499931)
me retourne différents résultats selon l'humeur du serveur (selon la 
version en cache du fichier python pour le thread concerné je suppose)
Ce qui fait que dans firebug je vois des erreurs 500... Mais ça devrait 
disparaître avec le temps.

* Ma base locale est en srid:4326 et je n'ai pas à reconvertir les 
données. La base sur osm7 est en srid:900913 et je soupçonne la 
transformation de faire rater des carrefours. Je crois que je vais 
devoir garder toute la chaîne en srid:900913.

* Ma connexion internet est salement entartrée et ça ne passe pas 
bien... Mais c'est un autre problème.

Par contre le jeu de données est plus frais sur osm7 que sur ma machine. 
Il coïncide avec les tuiles d'OSM.

Ci-dessous, la requête SQL qui tue.
De fait, elle est très rapide puisqu'elle fait très tôt une sélection 
sur le champs géométrie qui est indexé. Ce premier résultat est très 
court : quelques voies seulement traversent le tracé. Tous les autres 
calculs se font donc sur un jeux quelques lignes ou quelques dizaines de 
lignes tout au plus. De l'ordre de 25-30 millisecondes sur ma machine.
Certainement qu'elle peut encore être optimisée...
Il n'y a qu'une requête SQL par requête ajax.


WITH actual AS (
-- On prépare le tracé
SELECT
ST_Transform(%(geom)s, %(db_srid)s) AS geom, -- géométrie
%(forward)s AS forward -- sens de parcours du tracé 0 (contresens)|1 
(sens courant)
), translate (en, fr) AS (
-- pour la traduction, mais aussi pour une future présélection des tags 
"highway" valides
-- devrait être injecté par la suite par une variable
VALUES
('steps' ,'escalier'),
('footway' ,'allée'),
('path' ,'sentier'),
('track' ,'chemin'),
('unqualified' ,'route'),
('residential' ,'rue'),
('tertiary' ,'route'),
('secondary' ,'route'),
('primary' ,'route'),
('motorway' ,'autoroute'),
('motorway_link' ,'bretelle')
)
-- On fait du ménage et de la mise en forme du résultat.
SELECT
ST_AsGeoJSON(c.cross_geom) AS cross_geojson,
c.drift_forward AS drift_forward,
ST_AsGeoJSON(c.drift_geom) AS drift_geojson,
c.drift_highway AS drift_highway,
c.drift_name AS drift_name,
COALESCE(
c.drift_name || COALESCE(' (' || c.drift_ref || ')',''),
c.drift_ref,
( SELECT translate.fr
FROM translate
WHERE translate.en = c.drift_highway
),
'route') AS drift_desc,
c.drift_ref AS drift_ref,
ST_Length(c.drift_geom::geography) AS drift_length,

c.crop_forward AS crop_forward,
ST_AsGeoJSON(c.crop_geom) AS crop_geojson,
ST_Length(ST_Transform(c.drift_geom,4326)::geography) AS crop_length,
ST_AsGeoJSON(ST_LineMerge(ST_Collect(c.crop_geom, c.drift_geom))) AS 
fork_geom_geojson,
c.drift_geom AS drift_wkb,
-- en dessous, c'est juste pour éviter de m'énerver quand j'oublie la 
virgule dans les manipulations de champs
'' AS void

FROM (
WITH expanded AS (
SELECT
crossed.further_highway AS further_highway,
crossed.further_name AS further_name,
crossed.further_ref AS further_ref,
crossed.further_geom AS further_geom,
-- for several crossing of the two ways
(ST_Dump(crossed.cross_geom)).geom AS cross_geom,
crossed.actual_geom AS actual_geom,
crossed.actual_forward AS actual_forward,
'' AS void
FROM (
-- on calcule les croisements
-- plusieurs croisement possibles entre deux voies
-- d'où le ST_Dump dans le select de "expanded"
SELECT
further.highway AS further_highway,
further.name AS further_name,
further.ref AS further_ref,
ST_Transform(further.way,4326) AS further_geom,
ST_Intersection(
ST_Transform(further.way,4326),
ST_Transform(actual.geom,4326)) AS cross_geom,
ST_Transform(actual.geom,4326) AS actual_geom,
actual.forward AS actual_forward,
'' AS void
FROM
actual,
%(db_table_prefix)sline AS further
WHERE
ST_Intersects(further.way, actual.geom)
AND further.highway IS NOT NULL
-- AND NOT hw_to.osm_id = hw_from.osm_id
AND NOT ST_Contains(further.way, actual.geom)
) AS crossed
WHERE ST_NPoints(cross_geom) = 1
)
-- On calcule les morceaux de géométries à conserver : line_substring
-- sur le tracé en cours : crop,
-- et sur le prolongement envisagé : drift
-- On applique un sens de parcours (forward) selon la partie amont : 
substring(0,n)|aval: substring(n,1)
-- On joint (UNION) les cas amont (drift_forward=0) et aval 
(drift_forward=1)
SELECT
expanded.cross_geom AS cross_geom,
0 AS drift_forward,
ST_Line_SubString(
expanded.further_geom,
0,
ST_Line_Locate_Point(expanded.further_geom, expanded.cross_geom)
) AS drift_geom,
expanded.further_highway AS drift_highway,
expanded.further_name AS drift_name,
expanded.further_ref AS drift_ref,

expanded.actual_forward AS crop_forward,
CASE WHEN
expanded.actual_forward = 0
THEN
ST_Line_SubString(
expanded.actual_geom,
ST_Line_Locate_Point(expanded.actual_geom, expanded.cross_geom),
1
)
ELSE
ST_Line_SubString(
expanded.actual_geom,
0,
ST_Line_Locate_Point(expanded.actual_geom, expanded.cross_geom)
)
END AS crop_geom,
'' AS void
FROM expanded

UNION ALL
SELECT
expanded.cross_geom AS cross_geom,
1 AS drift_forward,
ST_Line_SubString(
expanded.further_geom,
ST_Line_Locate_Point(expanded.further_geom, expanded.cross_geom),
1
) AS drift_geom,
expanded.further_highway AS drift_highway,
expanded.further_name AS drift_name,
expanded.further_ref AS drift_ref,

expanded.actual_forward AS crop_forward,
CASE WHEN
expanded.actual_forward = 0
THEN
ST_Line_SubString(
expanded.actual_geom,
ST_Line_Locate_Point(expanded.actual_geom, expanded.cross_geom),
1
)
ELSE
ST_Line_SubString(
expanded.actual_geom,
0,
ST_Line_Locate_Point(expanded.actual_geom, expanded.cross_geom)
)
END AS crop_geom,
'' AS void
FROM expanded
) as c
WHERE
ST_Length(c.drift_geom::geography) > 0
AND
ST_Length(c.crop_geom::geography) > 0
ORDER BY
ST_Length(c.crop_geom::geography),
ST_Length(c.drift_geom::geography)

Vos critiques, observations, remarques, optimisations...
sont les bienvenues.
Amusez-vous et explorez...
--
FrViPofm



Plus d'informations sur la liste de diffusion dev-fr