[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