Blog de Rodolphe Quiédeville

rosarks.eu

jeu 6 mar 2014 - 17:11

Je profite d'avoir la chance de pouvoir ré-écrire Lolix from scratch pour penser aux fonctionnalités qu'il m'aurait plu d'avoir quand je cherchais un travail, sur ce point j'ai toujours été surpris de voir à quel point les entreprises font bien peu d'effort pour aider les candidats à trouver leur locaux. Peut-être que les recruteurs imaginent que tout le monde sait où se trouve leur bureau, ou parce qu'ils imaginent cela comme une première épreuve pour mesurer le niveau de débrouilliardise du candidat, en tout état de cause personnellement je trouve qu'indiquer la sation de bus/tram/métro/vélocation à proximité ne peut être qu'un plus sur une offre d'emploi.

Contrairement à 1998 on a la chance aujourd'hui de disposer d'outils magiques comme Leaflet et OpenStreetMap pour trouver cette information et la visualiser. Seulement dans un projet comme Lolix intégrer ce type de données me parait un peu hors de propos du projet, je souhaite juste pouvoir indiquer sur les offres (préalablement géolocalisées) les services de transports publics à proximité. C'est au bout de cette réflexion que m'est venue l'idée de disposer d'une API simple qui puisse renvoyer au format json les services à proximité d'un point, le tout étant alimenté par les données extraites de la base OpenStreetMap dans laquelle la majorité des informations qui m'intéresse à ce jour.

Ne trouvant pas mon bonheur dans les solutions existantes j'ai codé ces deux derniers jours un nouveau projet Django qui va répondre à mon besoin, rosarks !

Le principe de rosarks est très simple un appel avec un nom de service et une coordonnée renvoit un objet JSON de tous les services de ce type à proximité de ce point, par exemple si je cherche les stations de métros à proximité de 2.45,42.56 la requête sera de la forme :

GET /subway_station/2.45/42.56/

Ce type de recherche aurait pu se faire directement en interrogeant l'API OSM, mais rosarks va un peu plus loin en ré-agrégant des informations, dans le résultat de la requête ci-dessus j'ai non seulement le nom des stations mais aussi le numéro de la ligne de métro, chose qu'il aurait fallut faire en plusieurs requêtes vers l'API ou en requêtes complexes avec un temps de réponses plus ou moins long.

Pour le moment rosarks est alimenté avec les données de la France entière et est ouverte à qui le souhaite. Une dernière chose qui peut servir, le site de rosarks est : rosarks.eu

Le code de rosarks est publié en GNU Affero General Public License.

OSM Pulsation

lun 10 fév 2014 - 16:05

Je maintiens à jour une base de données pour Nominatim en utilisant les delta toutes les minutes, je me suis dit qu'il serait amusant de voir l'évolution des données au cours de la journée.

J'ai écrit un rapide parser xml afin de compter chaque ajout/modification/suppression pour les 3 objets de base que sont les nodes/ways/relations, poussé ces données dans une base sqlite pour l'historique, et dumpé les datas de la journée dans un json par objet. Avec pour la partie graphique la librairie Javascript Rickshaw et le tour est joué :

Le résultats est consultable en temps réel en ligne ici

Je vous demande d'être indulgent sur les points de détails, c'est un travail de quelques heures histoire de s'amuser un peu avec des données et non un projet totalement aboutit.

Utiliser GraphHopper avec Jetty8 sous Debian

sam 30 nov 2013 - 16:45

Actuellement la seule solution documentée pour utiliser GraphHopper est l'utilisation de jetty runner, celle-ci n'est pas satisfaisante dans un mode de production, elle requiert de mettre en place des scripts de lancement. Il est plus simple d'administrer un service de routing en utilisant par exemple jetty ou Tomcat, ce billet va se concentrer sur la configuration de jetty sous Debian Jessie.

Tout d'abord installer le serveur jetty

apt-get install jetty8

Puis on récupère l'archive .war que l'on copie dans le répertoire de webapp de jetty

cd /var/lib/jetty8/webapps wget http://oss.sonatype.org/content/groups/public/com/graphhopper/graphhopper-web/0.2/graphhopper-web-0.2.war

Toujours dans le répertoire webapps on va renommer le fichier war de GraphHopper afin que le déploiement se fasse dans le contexte racine, de même que l'on va supprimer le répertoire existant nommé root. La raison de cette opération peu orthodoxe est que par défaut GraphHopper répond aux requêtes d'api sur l'url /api/ et qu'il n'est pas actuellement possible de paramétrer cela simplement. La seule méthode de contournement est d'indiquer un paramètre host dans l'url ce qui n'est pas des plus ergonomique.

mv graphhopper-web-0.2.war ROOT.war rm -fr root/

On va déployer les fichiers de configuration et de données dans /home/routing, il faut créer ce répertoire, dans lequel on en crée de suite un autre nommé data qui contiendra les données précompilées par GraphHopper

mkdir /home/routing mkdir /home/routing/data/

On crée un fichier de configuration dans le dossier en utilisant l'exemple fournit sur le site du projet, fichier que l'on renomme dans la foulée.

wget https://raw.github.com/graphhopper/graphhopper/master/config-example.properties mv config-example.properties config.properties

Maintenant on va récupérer le fichier qui servira de source de données, on télécharge directement un fichier protobuff depuis le site de Geofabrik, par exemple le fichier de données de la région Nord-Pas de Calais :

wget http://download.geofabrik.de/europe/france/nord-pas-de-calais-latest.osm.pbf

On édite le fichier de configuration pour qu'il corresponde à notre utilisation en ajoutant deux paramètres à la fin de celui-ci. Le premier qui correspond au fichier protobuff utilisé et le second qui indique où GraphHopper doit créer ses fichiers de données.

# data source osmreader.osm=/home/routing/nord-pas-de-calais-latest.osm.pbf # repertoire de données graph.location=/home/routing/data/

Au lancement de jetty GraphHopper va pré-traiter les données du fichier .pbf afin de préparer ses tables de recherches qu'il stockera dans le répertoire /home/routing/data/ Si vous voulez mettre les données à jour il suffit télécharger un nouveau fichier de données et de relancer jetty, le fichier de données étant plus récent GrapHopper relancera une analyse.

Le serveur jetty tournant sous Debian avec l'utilisateur jetty il faut définir les bons attibuts de propriété aux répertoires ainsi qu'à tous les fichiers présents dans celui-ci.

chown -R jetty.jetty /home/routing

Dernière modification, éditer le fichier /etc/default/jetty8 pour paramétrer le démarrage automatique et indiquer le fichier de configuration de GraphHopper

# change to 0 to allow Jetty to start NO_START=0 # Additional arguments to pass to Jetty JETTY_ARGS=-Dgraphhopper.config=/home/routing/config.properties

Par défaut comme souvent sur Debian le démon va écouter seulement sur le localhost, à vous de régler le paramètre JETTY_HOST suivant vos besoins.

Il ne reste plus qu'à lancer jetty avec le script d'init avec l'utilisateur privilégié root

invoke-rc.d jetty8 restart

A ce stade GraphHopper est prêt à répondre sur le port 8989 de votre machine et à vous indiquer la route !

Test de GraphHopper

mar 26 nov 2013 - 17:40

GraphHopper est outil de routage comme OSRM qui a été traité dans un précédent billet.

La sortie hier la version 0.2 est l'occasion de tester ce nouvel outil, dont le développement a été commencé il y a un peu plus d'un an, et de le comparer à OSRM.

L'environnement de test est comme à mon habitude une distribution Debian, afin de minimiser le travail de déploiement on va se reposer au maximum sur les paquets. Graphhopper requiert une version 7 ou 8 de JRE, ce qui va nous obliger à utiliser la version testing aka Jessie, il faut tout d'abord installer le paquet default-jre.

apt-get install default-jre

La suite de la procédure décrite dans le Quickstart est claire et permet le lancement de GraphHopper après quelques récupérations de fichier en ligne dont jetty runner et le war de GraphHopper. La méthode de déploiement avec jetty runner est peu propice à une mise en production bien que fonctionnelle, j'ai bien essayé de déployer le .war avec Jetty ou Tomcat7 mais en vain, n'étant pas un expert java cela semble normal ; il sera sage d'attendre un peu de packaging autour de l'outil avant d'en envisager une exploitation sereine.

Le résultat obtenu diffère de OSRM qui ne fournit qu'une API quand GraphHopper propose une solution tout en un, on obtient directement une interface web interrogeable sur le port configuré (ici 8989), il est également possible d'interroger directement l'API sur l'url /api/route, pour un aperçu le résultat est identique à la démo en ligne. Basé sur Leaflet la fond de carte est agréablement complété d'un cadre matérialisant la bounding-box des données traitées.

Autre différence notoire est le temps de préparation des données, bien que l'on travaille directement avec des fichiers .pbf dans les deux cas sans passer par une base de données, GraphHopper comme osrm nécessite de construire les arbres de données. GraphHopper fait ceci directement lors du lancement quand osrm nécessite de passer par les étapes osrm-extract et osrm-prepare.

La différence majeure va venir du temps de précompilation, sur une machine avec 6 core, 12Gb de RAM et des disques SSD j'ai obtenu les résultats suivants. J'ai utilisé une première fois le fichier de la ville de Berlin et en second celui de la France, tous deux obtenus sur Geofabrik.

BerlinFrance GraphHopper17 sec 32min osrm37sec71min

Le résultat est assez net, le temps de précompilation des données est deux fois inférieur avec GraphHopper ce qui lui donne un avantage considérable pour qui voudrait mettre à jour ses données régulièrement sur une emprise de taille conséquente.

La prochaine étape sera de mesurer les temps de réponses des deux API, ce que je vais m'employer à faire rapidement avec Tsung, je publierai les résultats ici.

bbox étendue sur l'overpass-api

lun 9 sep 2013 - 17:04

L'overpass API d'OpenStreetMap permet de récupérer des données en contruisant des requêtes plus ou moins complexe. Une requête simple comme récupérer tous les noeuds de type camping sur une zone couvrant l'Europe s'écrie :

<query type="node"> <has-kv k="tourism" v="camp_site"/> <bbox-query s="41" w="-11" n="71" e="31"/> </query> <print/>

SImple a analyser une telle requête sera malheureusement trop conséquente pour être traitée au vu de la zone couverte. Une solution consiste à découper la bbox en zones plus petites qui seront rapidement traitées par le serveur, l'automatisation de ce découpage est la raison d'être d'ovpwild.py.

ovpwild.py va lire un fichier de requête et une bbox en paramètres et effectuer autant de requêtes que de carré de 1°x1° nécessaire pour couvrir toute la zone. Pour réaliser la requête ci-dessus il suffit d'écrire un fichier de requête contenant :

<query type="node"> <has-kv k="tourism" v="camp_site"/> <bbox-query s="{south}" w="{west}" n="{north}" e="{east}"/> </query> <print/>

et d'exécuter la commande :

ovpwild.py -n 71 -s 46 -e 31 -w -11 -q campsite.overpas -o /tmp/

Le répertoire /tmp contiendra autant de fichiers que de requêtes qu'il ne restera plus qu'à charger dans une base postgis avec osm2pgsql par exemple.

Le scripts possède différentes options comme la reprise sur erreur, le réglage du timeout, le nombre de ré-essai automatique, la taille des zones unitaires, ... Toutes les options étant consultables par ovpwild.py -h.

ovpwild.py est publié sous licence GPLv3, où il peut être téléchargé et forké sur Gitorious (lien download).

Pour obtenir tous les noeuds dans une zone élargie il est également possible de récupérer les dumps de Geofabrik et de les traiter avec osmfilter, mais dans mon cas la machine effectuant les traitements est utilisée aussi pour le rendu, un tel traitement est trop lourd et impactant pour les autres services.

Le routage avec OpenStreetMap

dim 3 juin 2012 - 19:23

Dans l'ecosystème OpenStreetMap je n'avais pas encore testé le processus de Routage en général et encore moins le projet OSRM qui monte en ce moment. Actuellement en pleine phase de développement, la dernière version 0.3 n'en est pas moins utilisable. Ce billet sera un retour d'expérience sur l'installation et l'utilisation de ce projet, j'ai utilisé pour cela la version de développement disponible sur GitHub.

Installation

Plutôt que de décrire ici l'installation et la compilation d'OSRM j'ai mis à jour la partie Debian/Squeeze du wiki officiel.

Préparation des données

Les données OSM doivent être préparées et mises en forme pour que OSRM puisse les exploiter, c'est dans certes partie de formatage des données que OSRM tire sa rapidité dans les calculs d'itinéraires, vous pouvez vous en rendre compte en utilisant la démo officielle basée sur une base mondiale. Cette préparation se fait avec les commandes osrm-extract et osrm-prepare. Prenons pour exemple le fichier de la Croatie téléchargé depuis les exports de Geofabrik, la première commande sera :

./osrm-extract croatia.osm.pbf

Cette commande d'extraction va générer 2 nouveaux fichiers dans le répertoire courant, croatia.osrm.names et croatia.osrm.restrictions, le deuxième sera utilisé de suites pour la préparation des données :

./osrm-prepare croatia.osrm croatia.osrm.restrictions

Une fois ces 2 étapes passées nous avons les fichiers nécessaires à l'utilisation d'OSRM.

Optimisation des traitements

Comme de nombreux process lié à OSM la manipulation des données requiert de la RAM et de l'espace disque de façon significative, OSRM utilise un fichier temporaire qui peut rapidement dépasser la centaine de Giga Octets si vous travaillez sur les zones de la taille de l'Europe ou équivalent. Pour spécifier à OSRM où placer son fichier de travail temporaire créez un fichier .stxxl contenant la ligne :

disk=/home/tmp/stxxl,50000,mmap

qui indique, l'emplacement, la taille en Go et la méthode utilisée pour y accéder, pour plus de détails voir la page Running OSRM du wiki officiel. Enfin la prise en compte du fichier se fait par la déclaration d'une variable d'environnement :

export STXXLCFG=/home/www/osrm/Project-OSRM/.stxxl Exécution du serveur

Nous avons nos fichiers, lançons le serveur. Le pararamétrage de celui-ci se fait dans le fichier server.ini, il est à noter que pour le moment le nom et l'emplacement de ce fichier n'est pas paramétrable, il est définit en dur dans [Routed.cpp| https://github.com/DennisOSRM/Project-OSRM/blob/master/routed.cpp#L95] on note la jeunesse du projet à ce genre de détail. Le fichier de configuration permet de définir :

  • le nombre de thread lancés
  • l'adresse IP d'écoute pour le démon
  • le port d'écoute

Il définit de même l'emplacement des fichiers de données qui ont été préparés lors des étapes précédentes :

  • hsgrData=/home/osrm-data/croatia.osrm.hsgr
  • nodesData=/home/osrm-data/croatia.osrm.nodes
  • edgesData=/home/osrm-data/croatia.osrm.edges
  • ramIndex=/home/osrm-data/croatia.osrm.ramIndex
  • fileIndex=/home/osrm-data/croatia.osrm.fileIndex
  • namesData=/home/osrm-data/croatia.osrm.names
  • timestamp=/home/osrm-data/croatia.osrm.timestamp

On note que le fichier de données original n'est pas utilisé pas OSRM, seuls les fichiers générés le sont. Il faut avant de se lancer dans du routage mondial s'attarder un peu sur le poids de ces fichiers. On est partit avec un fichier .pbf de 28Mo et on obtient :

24M croatia.osrm.edges 53M croatia.osrm.fileIndex 75M croatia.osrm.hsgr 168K croatia.osrm.names 11M croatia.osrm.nodes 8.1M croatia.osrm.ramIndex 8.0K croatia.osrm.restrictions

Soit un total de 207Mo pour les 28 de départ, je vous laisse faire la règle de 3 adequat sur un full planet ! Mais une fois de plus le jeu en vaut la chandelle.

Utilisation

OSRM implémente en partie HTTP/1.1, l'interrogation se fait au travers de requête GET, les résultats sont renvoyés sous forme de fichier JSON, l'API est décrite sur la wiki dans la page Server API. Il existe 3 commandes à ce jour locate, nearest et viaroute qui servent respectivement à trouver le noeud le plus proche, identifier le noeud le plus proche sur une route, et obtenir le trajet entre 2 points. Je ne détaille pas le format JSON de retour obtenu, c'est très bien expliqué dans Server API. Un service web classique se basera donc sur 3 appels successifs, un premier pour trouver le point de départ en utilisant nearest, un appel pour le point d'arrivée également avec nearest et la route entre ces points avec viaroute. Il faut noter que le format de résultat de viaroute suit celui utilisé par Navengine de Cloudmade

Exemples de requête :

http://server:5000/nearest?52.555485441735&13.342227642887 http://server:5000/viaroute?loc=52.5,&13.34&loc=49.25,16.32

Pour la mise en forme de la route sur un fond de carte, viaroute renvoit un multiline encodé avec le polylinealgorithm de Google Maps. Un exemple de décodage en JS est disponible dans l'implémentqion OSRM-Web OSRM.RoutingGeometry.js

Normalement vous avez tout pour monter votre service de routage, je me suis fait pour ma part une rapide implémentaiton http://carto.quiedeville.org/osrm/. Basée sur une partie de l'Europe vous pouvez l'utiliser en gardant à l'esprit que c'est du POC, donc souvent ça bug.

Bilan

Projet jeune par son manque de packaging et de personnalisation dans l'utilisation, mais très prometteur. J'ai particulièrement apprécié la possibilité de faire du multi-modal route / ferry par exemple.

Bilan des backports pour Openstreetmap

mar 6 déc 2011 - 11:08

L'avantage indéniable de Debian sur d'autres distributions est à mes yeux sa stabilité exemplaire, cela entraine malheureusement d'avoir régulièrement des versions un peu obsolète des logiciels empaquetés. Il est possible de contourner cela en créant des backports de la version de développement de Debian (Wheezy) vers la version stable (Squeeze). J'ai réalisé les backports des principaux outils utilisés dans l'univers OpenStreetMap, ceux-ci sont diponibles sur mon dépôt privé (voir ce billet pour la mise en place du dépôt sur votre machine.

A ce jour les outils ci-dessous sont disponibles dans ces versions :

  • dans-gdal-scripts 0.18
  • gdal 1.7.3
  • mapnik 2.0.0
  • osm2pgsql 0.70.5
  • openlayers 2.11
  • gpsprune 13.1
  • viking 1.2.1

Les paquets n'ont pas été poussés dans le dépôt des backports officiels car ils représentent une utilisation trop faible au vu de la communauté Debian, un paquet comme osm2pgql est utlilisé à ce jour par moins de 300 personnes d'après popcon quand les outils apache2 le sont par plus de 60000 (popcon apache2-utils).

Nouvelles cartes des éoliennes

mer 22 juin 2011 - 23:02

En avril 2010 j'ai réalisé une première carte des éoliennes en france, cette carte utilise un fichier de données GML comme source de données. Afin de pouvoir réaliser une carte mondiale des éoliennes en particulier et des sources d'énergie en général j'ai mis en place une instance GeoServer avec une base de données Postgis comme source.

Ceci m'a permis de réaliser cette nouvelle carte de couverture mondiale qui recense aujourd'hui 40 781 éoliennes au plan mondial.

Cette carte sera mise à jour une fois par semaine dans un premier temps puis quotidiennement si la puissance machine le permet.

Rendu de tuile dynamique sous Debian Squeeze

lun 23 mai 2011 - 13:18

Nous allons mettre en oeuvre une méthode génération de tuile à la volée en utilisant l'outil TileCache sur une distribution Debian Squeeze. Le principe de TileCache exposé ici et de servir par Apache un cgi qui va générer une tuile en utilisant le moteur de rendu mapnik et la stocker sur le disque pour ne pas avoir à la regénérer à chaque appel. La procédure part d'une installation minimale de la dernière version stable de Debian à savoir Squeeze.

Première étape, installer quelques outils de travail qui ne sont pas liés au sujet qui ici nous importe mais dont nous aurons besoin. Cette action se fait avec l'utilisateur root évidemement, chaque futur changement d'utilisateur unix sera clairement explicité.

apt-get install subversion wget unzip bzip2 apache2

Sans trop détailler cette partie nous allons installer une base de données spatiale.

apt-get install postgresql postgis postgresql-8.4-postgis osm2pgsql

Si votre environnement par défaut n'utilise pas une locale en UTF-8 vous aurez à recréer votre cluster postgres, pour cela détruisez l'actuel (toutes données seront perdues) et recréé le par défaut en UTF-8. Les trois commandes suivantes supprime le cluster actuel, créé le nouveau et le démarre.

pg_dropcluster --stop 8.4 main pg_createcluster 8.4 main --locale fr_FR.UTF-8 pg_ctlcluster 8.4 main start

Pour les manipulations purement postgresql on travaille toujours avec l'utilisateur unix postgres, On passe donc sous cet utilisateur

su - postgres

On vérifie que le cluster est par défaut en utf-8 avec la commande :

psql -l

La colone encoding doit indique 'UTF8'

On créée un utilisateur sans privilèges particulier qui sera utilisé plus loin dans la configuration de mapnik.

createuser -S -D -R -P render

on considère dans la suite du billet que vous affectez ici le mot de passe 'render' à cet utilisateur ; dans la vrai vie personne n'ose faire une chose pareille évidemment :-)

Création de la base de données nommée render, que l'on affecte à l'utilisateur "render"

createdb -O render render

Les trois commandes suivantes servent à spatialiser la base. Cela permet de stocker et manipuler les objets géométriques directement avec des primitives postgres.

createlang plpgsql render psql -q -d render -f /usr/share/postgresql/8.4/contrib/postgis-1.5/postgis.sql psql -q -d render -f /usr/share/postgresql/8.4/contrib/postgis-1.5/spatial_ref_sys.sql

Les 3 commandes précédentes doivent être siliencieuses en cas de succès.

On rend la propriété des objets créés à notre utilisateur "render" (les commandes ont été lancées avec le user "postgres")

psql -d render -c 'ALTER TABLE geometry_columns OWNER TO render' psql -d render -c 'ALTER TABLE spatial_ref_sys OWNER TO render' psql -d render -c 'ALTER VIEW geography_columns OWNER TO render'

Il nous reste à effectuer l'installation du moteur de rendu mapnik et à charger le fichier de données dans la base de données Désormais nous allons travailler avec un utilisateur dédié au rendering

Retour en root pour installer la paquets nécessaires

apt-get install python-mapnik mapnik-utils

et création d'un utilisateur lambda

adduser render

On passe sous cet utilisateur render pour la suite.

su - render

Installation de mapnik depuis le dépôt svn officiel d'openstreetmap dans le répertoire /home/render/mapnik

svn co http://svn.openstreetmap.org/applications/rendering/mapnik

Toutes les informations nécessaires au rendu ne sont pas stockées dans la base de données, une partie est utilisée depuis des fichiers de formes appelés Shapefiles. On trouvera par exemple dans ceux-ci le contour des continents, qui contrairement aux autres données dans OSM bougent bien peu. Avant de pouvoir faire nos rendus nous allons donc les récupérer grâce à un script bash qui télécharge les fichiers nécessaires et les décompresse dans le répertoire courant :

cd mapnik && bash get-coastlines.sh

Là vous pouvez aller prendre un café, un sandwich ou une entrecôte suivant le débit de votre liaison internet. Le total des fichiers réléchargés dépasse les 450Mo.

A cette étape nous nous rappochons d'OpenStreetMap et allons récupérer les données pour les charger dans notre base. Nous récupérons le fichier pour la région Basse-Normandie, à vous d'adapter pour coller à votre besoin. Les deux sources de fichiers d'export les plus utilisés aujourd'hui sont Geofabrik et Cloudmade, arbitrairement nous utiliserons Cloudmade.

wget http://downloads.cloudmade.com/europe/western_europe/france/basse-normandie/basse-normandie.osm.bz2

Le chargement des données dans la base se fait avec le logiciel osm2pgsql, celui-ci utilise en entrée un fichier de données (comme celui fraichement téléchargé) et un fichier de style qui permet de filtrer les clés sur les objets en fonction de ce que l'on veut afficher sur notre carte. Le packaging de debian évoluant moins rapidement que les tags dans OSM nous allons légèrement adapter le fichier de style ajoutant la clé 'addr:housename' au fichier de style pour que notre démonstration fonctionne.

cp /usr/share/osm2pgsql/default.style . echo 'node,way addr:housename text linear' >> default.style

Longue étape, le chargement des données se fait avec la commande :

osm2pgsql -s -S default.style -d render basse-normandie.osm.bz2

là encore pour pouvez aller vous ressourcer en alcaloïde méthylxanthine ,

Avec les sources de mapnik est distibué le style utilisé pour le rendu sur le site openstreetmap.org autant l'utiliser. Étant assez complexe il est découpé en plusieurs fichiers xml qu'il faut réassembler en spécifiant la connexion à postgresql qui sera utilisée pour le rendu. Cela se fait en utilisant le script pyhton generate_xml.py de la façon suivante :

./generate_xml.py --host=localhost --port=5432 --user=render --password=render --dbname=render osm.xml > osm-local.xml

Le fichier osm-local.xml sera celui utilisé au final par mapnik, il fait tout de même 9682 lignes, on voit bien l'intérêt du découpage.

J'en profite pour féliciter ceux qui sont arrivés jusque ici et les rassurent aussi, on voit le bout.

Si on fait le point, nous avons nos données de stockées dans la base et le moteur de rendu est installé et configuré, ne nous reste donc plus qu'à passer au sujet principal de ce billet, à savoir TileCache :

Installation se fait au travers du paquet eponyme

apt-get install tilecache

La configuration s'effectue dans le fichier dans /etc/tilecache.cfg auquel nous ajouterons juste une section finale composée de :

[osm] type=Mapnik mapfile=/home/render/mapnik/osm-local.xml spherical_mercator=true tms_type=google

Cette simple configuration conclue l'installation et il ne nous reste qu'à tester l'ensemble

Par défaut TileCache va stocker les tuiles générées dans /tmp/tilecache à vous d'adapter au besoin. Dans un prochain billet on verra le cache des tuiles directement dans Memcached.

Ma machine de test s'appelle geti que vous remplacerez dans l'url suivante par le nom de votre machine

L'appel de cette url devrait vous afficher la ville de Cherbourg

http://geti/cgi-bin/tilecache.cgi/1.0.0/osm/12/2029/1395.png

Vous reconnaitrez facilement la forme de l'url que vous pourrez utiliser avec Leaflet par exemple.

Pour tester plus en avant votre installation vous pouvez récupérer un fichier simple de test disponible sur mon serveur, adaptez le nom de la machine dans le code et placez le fichier à la racine de votre site web, vous disposerez d'une carte navigable avec des tuiles générées à la volée !

wget http://carto.quiedeville.org/leaflet/article-test.html

Bugs, problèmes, mécompréhension, les commentaires sont ouverts.

Leaflet, un nouveau concurrent pour OpenLayers ?

dim 22 mai 2011 - 16:20

Dans un précédent billet j'évoquais les possibilités de réduction de taille de la librairie OpenLayers, avoisinant le méga de données en natif je trouve cette librairie un peu trop gourmande. En réduisant au maximum les fonctionnalités j'arrivais à une taille de 154Ko ce qui permettait d'afficher des tuiles issue d'OpenStreetMap et d'avoir les fonctionnalités de déplacement et de zoom de base.

Si la problématique de la taille est primordiale dans votre déploiement de carte ligne vous serez intéressé par la nouvelle librairie Leaflet que vient de publier Cloudmade. Conçue pour les applis web et mobiles Leaflet ne pèse à ce jour que 64Ko. On ne retrouve que les fonctions de bases, mais déjà bien assez pour la plupart des cartes vues sur le web. Les fonctions de bases sont présentes avec en plus des possibilités d'ajout d'objets géometriques et les interactions minimales pour ouvrir les classiques popups. Publiée sous licence BSD le code est disponible sur Github, vous pourrez y signaler des bugs éventuels ou demander des nouvelles fonctionnalités sur la page de suivi d'anomalie.

Même si tous les exemples utilisent comme source le service MApzen de Cloudmade, il est possible d'utiliser n'importe quel serveur de tuile. J'ai fait une carte sommaire de la Bretagne avec les tuiles OSM standards, je suis assez emballé de la rapidité d'affichage,

Je vous invite à laisser en commentaire vos impressions et éventuellement à débattre de ses avantages/inconvénients par rapport à OpenLayers ; dont on attend la version 2.11 dans les jours/semaines à venir.

Service de frame pour cartes libres

lun 31 Jan 2011 - 15:18

Une remarque fréquemment entendue lors des présentations du projet OpenStreetMap est l'apparente compléxité à mettre une carte sur son site ; comparaison généralement faite avec d'autres services de cartes en ligne que nous ne nommerons pas ici.

Il est déjà possible d'obtenir un code d'iframe grâce au bouton Export sur le site du projet ; mais cette option n'est pas suffisemment connue ni facilement accessible à la diffusion des cartes dans les pages contact des sites web.

Pour remédier à cela et participer à la diffusion du projet OSM j'ai mis en ligne un service web de mise à disposition de frame nommé cartosm.eu.

Le service permet la création du code HMTL à insérer sur un site web pour y ajouter une iframe contenant une carte avec différentes options. Les cartes générées sont configurables pour y inclure une épingle, les rendre fixes, ajouter un lien vers une carte plus grande, ...


Voir sur une carte plus grande

La carte ci-dessus est ajoutée à ce billet en y insérant le code HTML suivant :

<iframe width="330" height="250" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="http://cartosm.eu/map?lon=-3.4549803733223&lat=47.637733494058&zoom=18&width=330&height=250 &mark=true&nav=true&pan=true&style=default"></iframe><br /><div id="cartosmlink"><a href="http://www.openstreetmap.org/?lat=47.637733494058&lon=-3.4549803733223&zoom=18&layers=M" style="text-align:left;">Voir sur une carte plus grande</a></div>

Réduire la taille de la librairie OpenLayers

ven 21 Jan 2011 - 14:55

La librairie OpenLayers est constituée d'un ensemble de classe, de fonctions, de librairies externes, qui sont séparés dans 292 fichiers Javascript. Le principe de la construction de la librairie est de rassembler tous les fichiers pour n'avoir au final qu'un seul .js à mettre sur votre serveur web. Nous allons décrire ici la méthode qui permet de pour choisir quelles parties seront incluses dans le fichier final. Pour ma part j'ai l'habitude d'exclure tous les objets type Marker des cartes qui ne sont composées que de tuiles de bases, on enlèvera de même tous les contrôles inutilisés.

Tout d'abord, récupérez l'archive contenant les sources sur le site du projet, la version à la rédaction de ce billet est la 2.10.

wget http://www.openlayers.org/download/OpenLayers-2.10.tar.gz

Décompressez ensuite l'archive obtenue et placez vous dans le répertoire build qui contient les scripts de construction.

tar xvfz OpenLayers-2.10.tar.gz cd OpenLayers-2.10/build/

On trouve dans le répertoires les scripts build.py et buildUncompressed.py écrits en python. Les fichiers de profile full.cfg library.cfg, et lite.cfg, le fichier de licence et un traditionnel README.txt qui contient un peu d'aide, juste un peu.

Le script nommé build.py prend 2 options. La première permet de spécifier le fichier de profile à utiliser (par défaut full.cfg) et la deuxième le nom du fichier généré (par défaut OpenLayers.js)

exécution du programme :

./build.py

ou

./build.py full

on note que le fichier de profil est à indiquer sans l'extension .cfg

build.py utilise jsmin (présent dans le répertoire tools/ de l'archive) pour minifier le code généré, si vous ne souhaitez pas le faire il vous faudra alors utiliser le script buildUncompressed.py pour construire votre librairie. La génération non compressée aboutit à un fichier de 2.6M, on réservera cette version pour les devs :-)

Par défault le script build.py utilise le fichier de configuration full.cfg qui comme son nom l'indique contient l'ensemble des librairies et classes du projet OpenLayers ainsi que les inclusions externes. Les fichiers sont placés dans le répertoire lib/ dans la racine de l'archive. La création du build full donne

Total files merged: 269 Compressing using jsmin.

Pour une taille de 929K.

Une compilation avec la configuration plus légère en utilisant le profile lite.cfg aboutit à 128K pour seulement 23 fichiers de sources utilisés, le gain est net et sans appel.

On aboutit avec ce fichier au minimum requis pour afficher une carte dans une page web, un minimum de contôles sont toutefois nécessaires pour permettre à l'internaute d'interagir sur la carte. C'est dans ce sens que j'ai créé le fichier ci-dessous qui me permet d'aboutir à un fichier de 154K ce qui fait tout de même un gain de 80% en taille.

[first] OpenLayers/SingleFile.js OpenLayers.js OpenLayers/BaseTypes.js OpenLayers/BaseTypes/Class.js OpenLayers/Util.js [last] [include] OpenLayers/Map.js OpenLayers/Layer/TMS.js OpenLayers/Control/Attribution.js OpenLayers/Control/PanZoom.js OpenLayers/Control/Navigation.js OpenLayers/Control/ArgParser.js [exclude]

Un fichier de profile se décrit en 4 sections qui contiennent chacune un ensemble de nom de fichier faisant référence au répertoire lib/ de la racine. Les fichiers présents dans include sont inclus dans le fichier final quand ceux de la section exclude en sont exclus. Il est possible de laisser la section include vide et de ne seulement spécifier que ceux qui ne seront pas utilisés, dans ce cas tous les fichiers sources sont inclus ; c'est d'ailleurs le choix fait dans le profil full.

Un fichier présent dans la section first sera inclus en début de processus, pour la section last il sera poussé à la fin du fichier, un fichier présent dans l'une de ces 2 sections doit figurer également dans la section include sinon une erreur se produit. La section include à prédominance sur la section exclude, un fichier présent dans les 2 sera inclus au final.

Dans la version par défaut la localisation française n'est pas incluse, on ajoutera la ligne "OpenLayers/Lang/fr.js" dans la section include pour corriger cela, raison de plus pour les francophones de construire eux mêmes leur librairie.

Il ne faut pas voir la finalité de la réduction de taille comme un gain en temps de transferts, au vu du volume de tuiles qui accompagnent une carte cela ne serait pas pertinent. Le gain le plus intéressant se trouve au niveau de l'exécution du code javascript dans le navigateur pour une part. D'autre part moins on à de code exposé, moins on a de bugs potentiels.

Un dernier intérêt à mettre en place cette méthode et vous l'aurez vite compris c'est que vous pouvez inclure votre propre code Javascript dans la lib et ne plus avoir qu'un seul fichier .js à charger pour animer vos cartes, et un fichier de moins, c'est une socket de moins, des octets en moins, une ligne de log en moins ...

Proposition de nouveau rendu mapnik

ven 12 nov 2010 - 17:50

Le rendu actuel des réserves naturelles dans mapnik fait que lorsque qu'une réserve est composée de terres émergées et de surface aquatique la limite entre les deux est peu intuitif à la lecture de la carte. J'ai ouvert un ticket ce jour pour proposer un nouveau rendu à base d'image hachurée sur fond transparent.

Le rendu actuel donne ce résultat :

et le nouveau celui-ci

Pour de plus grandes images vous pouvez consulter cette comparaison entre les deux rendus que je vous invite à commenter ici.

Installer la librairie OpenLayers sur votre serveur

jeu 11 nov 2010 - 12:16

Utiliser une librairie JavaScript distante est une dépendance dangeuresue pour un site web, en cas de problème sur le site OpenLayers les cartes sur vos sites ne seraient plus affichées, pour éviter cela nous allons voir comment installer la librairie à la racine de votre serveur web.

La librairie sera installée à la racine du serveur web dans un répertoire nommé opl210.

Première étape récupérer l'archive sur le site, ici nous la sauvegardons dans la racine du serveur.

wget http://www.openlayers.org/download/OpenLayers-2.10.tar.gz

On décompresse l'archive dans le répertoire courant

tar xvfz http://www.openlayers.org/download/OpenLayers-2.10.tar.gz

Il ne nous reste qu'à copier les fichiers nécessaires dans le répertoire opl210.

cp OpenLayers-2.10/OpenLayers.js opl210/ cp -r OpenLayers-2.10/img/ opl210/ cp -r OpenLayers-2.10/theme/ opl210/

Nous pouvons désormais supprimer l'archive OpenLayers-2.10.tar.gz et le répertoire OpenLayers-2.10 qui ne sont plus utiles.

Nous utiliserons maintenant dans notre page html la librairie locale en indiquant dans les headers l'emplacement de celle-ci :

<script type="text/javascript" src="/opl210/OpenLayers.js"></script>

Inutile de préciser où sont stockées les images et les styles utilisés, la librairie les cherche par défaut dans le répertoire/url où celle-ci se trouve. Dans le prochain billet nous verrons lors de la personnalisation de la carte comment indiquer des répertoires différents afin de pouvoir organiser les fichiers à son habitude.

NB : le fichier readme.txt contient une erreur sur l'emplacement du fichier OpenLayers.js ne pas s'y fier, j'ai ouvert un ticket pour corriger cette erreur

La mise en oeuvre de ce billet est consultable dans : local.html

OpenLayers et les projections

lun 8 nov 2010 - 13:15

Dans ce deuxième billet consacré à Openlayers nous allons aborder les sytèmes géodésiques et les projections. Sans entrer dans les détails il faut savoir que la représentation de la terre qui est ronde sur une feuille de papier plane représente un casse tête depuis des siècles à tous les cartographes, pour faire cela au mieux (avec le minimum de déformations) on a inventé les systèmes géodésiques et les projections cartographiques.

Quand vous utilisez un GPS dans votre voiture, en randonnée ou en vélo la position que vous lisez sur l'écran est exprimée en longitude et latitude dans le système géodésique WGS 84. L'EPSG qui se charhe de référencer les différents systèmes lui a attribué le numéro 4326, les codes EPSG sont une référence pour les outils manipulant des données géographiques comme Postgis ou OpenLayers, ils sont d'ailleurs utilisés par aussi par l'Open Geospatial Consortium.

Tout serait simple si OpenLayers utilisait ce système pour référencer les tuiles qui composent la carte, mais OpenLayers utilise le système 900913, car c'est ce système qui est utilisé lors de la création des tuiles, nous devons donc l'utiliser pour positionner notre carte, comme nous l'avons fait dans le précédent billet. Je reviendrais plus tard sur les origines du système 900913, les habitués de l'écriture cowboy pourront déjà faire des recherches sur le moteur éponyme.

Un peu de pratique maintenant et positionnons notre carte avec des données WGS 84. Dans notre précédent exemple nous avons centré la carte sur la position 30000,580000, position exprimée dans le système 900913.

var center = new OpenLayers.LonLat(30000,5800000);

Afin de pouvoir spécifier center dans le système WGS 84 nous allons créer 2 objets de projection avec la classe OpenLayers.Projection, un objet pour le WGS 84 en utilisant son code EPSC 4326, et un pour le système attendu par OpenLayers 900913.

var projFrom = new OpenLayers.Projection("EPSG:4326"); var projTo = new OpenLayers.Projection("EPSG:900913")

Nous allons donc cette fois pourvoir définir notre centre avec une coordoonée en longitude est de 0.2694 approximatif, et une latitude nord de 46.1224.

var center = new OpenLayers.LonLat(0.269494585,46.1224893);

Il ne nous reste plus qu'à tranformer notre point center avec la fonction transform pour obtenir un point nommé cproj que l'on pourra utiliser pour positionner la carte.

var cproj = center.transform(projFrom, projTo);

Le contenu de center est transformé d'un système de projection source projFrom dans un système destination projTo, ce qui nous permet d'obtenir dans la variable cproj une position exprimée dans le système 900913, il ne nous reste plus qu'à utiliser cette position pout centrer la carte.

map.setCenter(cproj, 5);

La mise en oeuvre de ce billet est consultable dans : projections.html

Utiliser OpenLayers et OpenStreetMap : la carte minimale

mer 3 nov 2010 - 18:50

Ce billet est le premier d'une série sur la vulgarisation d'OpenStreetMap et OpenLayers. Nous allons voir ici qu'il est très simple aujourd'hui d'inclure une carte nabvigable dans une page web.

Le code de ce billet est mise en oeuvre dans : minimal.html

L'intégration d'une carte dans une page web consiste à ajouter une balise <div> avec un id nommé ici map. L'initialisation de la carte se fera au chargement de la page, pour cela on ajoute un appel à la fonction javascript init() dans la balise <body>.

<body onload="init()"> <div>Démonstration de carte openstreetmap minimale</div> <div id="map"></div> </body>

Dans l'en-tête de la page on définira la fonction init() comme suit. Dans cette première approche on se contente d'une carte simple que l'on positionne sur un point définit au niveau de zoom 5. Dans un prochain billet on verra comment utiliser un système de coordonnées plus commun.

<script type="text/javascript"> function init(){ // Création d'un objet map var map = new OpenLayers.Map('map'); // Ajout d'un calque en utilisant le rendu par défaut map.addLayer( new OpenLayers.Layer.OSM() ); // Création du point central de la carte à partir //de coordonnées géographiques var center = new OpenLayers.LonLat(30000,5800000); // Positionnement de la carte sur le point central, // au niveau de zoom 5 map.setCenter(center, 5); } </script>

Les propriétés visuelles de la carte, sa taille et la bordure noire sont définies comme pour tout objet html par une feuille de style CSS directement en utilisant l'identifiant de l'objet <div>.

#map { width: 600px; height: 400px; border: 1px solid black; }

Nous avons maintenant une carte dans notre page web sur laquelle il est possible de se déplacer, de modifier le niveau de zoom, de faire glisser à la souris et bien d'autres choses encore. Les connaisseurs reconnaîtront le rendu utilisé dans cet exemple, c'est le rendu réalisé par mapnik, utilisé sur le portail OpenStreetMap. Rendu que nous n'avons pas choisi et que nous verrons comment changer dans un prochain billet. Vous pouvez maintenant intégrer dans votre CMS à base de logiciel libre une carte à base de données libres.

Calculateur d'espace disque pour tuiles OpenStreetMap

dim 10 oct 2010 - 13:05

L'espace disque est un aspect important de la mise à disposition de carte sur Internet. Si vous travaillez sur une zone finie du globe il est intéressant de connaître rapidement l'espace disque nécessaire à la génération à priori de l'ensemble des tuiles que vous allez servir. Confronté régulièrement à cette problématique j'ai fait un tableur (OpenOffice) pour calculer l'espace disque et le nombre de tuiles pour une zone donnée (bounding box pour les intimes). La taille moyenne de la tuile est mésurée sur un serveur de production avec le rendu mapnik par défaut, les tuiles prises en compte sont des tuiles consultées par des humains et non un extrait statistique de l'ensemble des tuiles, ceci afin de donner plus de sens à la valeur moyenne. Ce tableur est publié ici sous licence GPL v3.

Aide à la toponymie dans OSM

mer 23 juin 2010 - 17:15

Lors des imports massifs les données sources peuvent être intégralement en majuscule ou en minuscule, il faut alors reprendre un à un tous les noms pour les écrire correctement. Cette tâche est longue et fastidieuse, pour réduire cette lourdeur j'ai écris une fonction à intégrer dans une base PostgreSQL en PL/Perl qui simplifie grandement le travail de ré-écriture. La fonction osm_capitalize suit les règles définies dans le Code officiel géographique de l'INSEE. Au vu des règles suivies la fonction n'est valide que pour les toponymes français.

Un exemple d'utilisation de la fonction, la première colonne présente le nom tels que trouvés dans un import, et la colonne de gauche le même nom passé au travers de la fonction.

Le petit pré | Le Petit Pré Le petit du champs des prés | Le Petit du Champs des Prés LE PETIT DU CHAMPS DES PRÉS | Le Petit du Champs des Prés la près d'hier | La Près d'Hier Bourg-en-bresse | Bourg-en-Bresse BOURG-EN-BRESSE | Bourg-en-Bresse l'epine | L'Epine L'EPINE | L'Epine LA ROCHE-SUR-YON | La Roche-sur-Yon CLAVANS-EN-HAUT-OISANS | Clavans-en-Haut-Oisans l'isle-jourdain | L'Isle-Jourdain PONT D'AIN | Pont d'Ain SAINT-ANDRÉ-D'HUIRIAT | Saint-André-d'Huiriat

Mise à jour du 26 juin : le code a migré chez Gitorious

Premier import massif

mer 16 juin 2010 - 10:37

La mairie de Guipel a fournit les données géographiques en sa possession à l'équipe de contributeurs d'OpenStreetMap j'ai été chargé de procéder à cet import, je tiens ici à remercier François, Steven et Pierre pour leur confiance. Bien que modeste dans le volume des données à traiter cet import m'a permis de toucher à une autre facette du projet OpenStreetMap. J'avais déjà étudié l'import de données automatisé avec le traitement des coordonnées des éoliennes (voir billet ci-contre) mais je n'avais pas encore manipulé de shapefile, ce qui est désormais chose faîte.

Pour se rendre compte de l'intérêt de cet import on peut comparer les deux images suivantes ; avant l'import ...

et après l'import

Cet import a été rendu possible grâce à la documentation de François Van Der Biest sur l'import de Crozon.

Si vous cherchez Guipel sur la carte en ligne c'est ici

J'ai pris beaucoup de plaisir dans l'étude et la réalisation de cet import massif, j'espère avoir l'occasion d'en réaliser d'autres très prochainement.

Que soit ici remercié la mairie de Guipel pour la fourniture de ces données, l'import n'est qu'une étape dans l'intégration de Guipel dans la carte OSM, la seconde aura lieu le samedi 19 juin 2010 avec une carto-partie sur place.

50 éoliennes supplémentaires

lun 31 mai 2010 - 12:09

La société Valorem a répondu positivement à ma sollicitation pour obtenir les coordonnées de leurs éoliennes. Celle-ci m'a transmis les coordonnées Lambert de leurs turbines que j'ai pu intégrer dans OpenStreetMap après conversion des coordonnées en WGS84 avec OsmApi.

L'ajout en masse des 50 points ont été faits au sein du changeset 4860587.

Pages