Linux Embedded

Le blog des technologies libres et embarquées

Exploitation de la base de donnée Open Street Map pour la conception de cartes dynamiques "offline"

Introduction

Etat des lieux de l’exploitation des cartes géographiques dynamiques sur interfaces graphiques

Le couplage entre la puissance de calcul des systèmes embarquées et leurs systèmes de géolocalisation donne aujourd’hui naissance à de nombreux services basés sur l’utilisation de données géographiques. Ces données sont le plus souvent exploitées sous forme de cartes interactives.

La plus connue des applications utilisant ce type de cartes est bien entendu Google Maps. De nombreux sites internet utilisaient jusqu'à aujourd’hui ce serveur de cartes pour afficher des informations géographiques correspondant à leurs services.

A partir de 2012, ce service est devenu payant pour les sites à fort trafic (supérieur 25000 requêtes par jour). Une nouvelle révision tarifaire a eu lieu à partir du 11 juin 2018 réduisant le nombre de requêtes gratuite à 28000 par MOIS. Les sommes à payer pour garder le service de cartographie de Google en place sont plutôt rédhibitoires (environ 6€ pour chaque millier de chargements supplémentaires).

A titre d'exemple, un site qui était à la limite gratuite de chargement de 25000 cartes par jour passe d'une tarification de 0€ à 4068€ par mois. De nombreux services basées sur Google Map voient leur business model s'effondrer suite à cette flambée des coûts d'exploitation et cherche aujourd'hui une solution alternative à Google Maps.

L’objectif ici n’est pas de remettre en cause le modèle économique de Google, mais plutôt nous rendre compte des risques économiques et éthiques liés à notre dépendance par rapport aux Bases De Données (BDD) privées.

Dans le cadre de la BDD géographique, il existe une belle et solide alternative à Google Maps. Elle se nomme Open Street Map (OSM).

Open Street Map est un projet international collaboratif fondé en 2004 ayant pour but de créer une carte libre du monde. Ce projet collecte les données du monde entier sur les routes, les voies ferrées, les rivières, les forêts, les bâtiments et bien plus encore, pour ainsi constituer une carte du monde libre et accessible par chacun. Les données cartographiques collectées sont ré-utilisables sous licence libre ODbL (Open Database Licence) depuis le 12 septembre 2012.

Je vous laisse juger de la qualité de cette base de données et de son rendu (lien vers Open Street Map).

Le côté collaboratif vient du fait que vous pouvez également devenir contributeur à l’enrichissement de cette base de données géographique en identifiant les éléments d’une carte satellitaire connus et/ou reconnaissables. Il suffit juste de vous enregistrer et de suivre un petit tutoriel qui décrit les bonnes manipulations à effectuer pour pouvoir enrichir la BDD et c'est parti !

Les outils et services se basant sur OSM se sont considérablement développés ces dernières années, et les logiciels Open Source se font ici la part belle à l’exploitation de cette source dite d"Open Data".

 

Architectures pour l'exploitation des données géographiques

L'exploitation de la base de donnée géographique d'OSM peut se faire de différentes façon. Elles sont représentées sur le schéma ci-dessous :

Parmi ces chemins, il en existe un que nous ne pouvons pas utiliser avec OSM. Il concerne l’exploitation directe des cartes à partir du serveur openstreetmap.org, comme nous pourrions le faire au travers de l’application Google Maps sur notre téléphone portable. Contrairement à Google, la fondation OpenStreetMap est une organisation à but non lucratif et possède des moyens limités. Les serveurs d’OSM n’ont tout simplement pas la capacité de répondre à un nombre de requêtes élevées (cf Politique d'usage des tuiles).

Malgré cette restriction, il nous reste tout de même de nombreuses méthodes pour exploiter la richesse de cette base de donnée.

Obtention de cartes dynamiques à partir de tuiles

La méthode de visualisation de carte dynamique à partir de tuile est appelée  TMS (Tile Map Service). Elle permet la visualisation et le déplacement de carte sur un écran avec différents niveaux de zoom. Cette méthode permet d'adapter l’information à afficher en fonction du zoom et d'obtenir une résolution optimale.

Cette méthode est basée sur la concaténation d’images appelées "tuiles", de taille fixe de 256 x 256 pixels au format png. Une tuile affichée au niveau n correspondra à 4 tuiles affichés au niveau n+1. Avec 18 niveaux de zoom, le nombre total de tuiles à générer pour afficher l’ensemble de la map monde sera de plus de 68 milliards de tuiles (4^18).

L’ensemble des tuiles est obtenu par combinaison des données géographiques et des feuilles de styles grâce une opération de rendu. Les feuilles de style transforment l’information contenue dans la base de donnée en objet graphique et à partir de règles liées :

  • à la nature de l’information géographiques
  • au niveau de zoom (de manière à limiter la surcharge d’informations des cartes sur des faibles niveaux de zoom)

Je vous invite donc pour la suite de ce tutoriel à vous limiter à une zone géographique très réduite. Le temps de rendu et la taille des dossiers de tuiles peuvent rapidement devenir très élevée.

 

Création et exploitation de nos cartes "offline"

Notre objectif est d’héberger la carte et son outil de visualisation au sein d’un système embarqué. Nous sommes ici en mode "hors ligne" et le schéma de production/exploitation des cartes (issu du schéma précédent) est le suivant :

 

Création de nos propres tuiles

Le chemin que nous allons suivre pour concevoir nos propres tuiles est le suivant :

  • Téléchargement des données géographiques complètes ou partielles issues de la base d'OSM
  • Intégration de ces données dans une base de données spatiale locale nommée postgresSQL/ postGIS via l’outil osm2pgsl
  • Transformation de BDD locale en tuiles grâce à l'outil Mapnik

Nous avons utilisé la distribution UBUNTU 16.04 LTS sur un ordinateur standard pour produire notre carte et le système d'exploitation Raspbian sur Raspberry Pi pour la visualiser.

Téléchargement des données en provenance d’OSM

Les données géographiques OSM du monde entier sont téléchargeables en un seul fichier (environ 39GB) sur le serveur officiel de la fondation. Une mise à jour de cette base de donnée est effectuée toutes les semaines et est également disponible en format "diff".
Pour éviter d’avoir à télécharger les données de l’ensemble du globe, d’autres sites proposent en téléchargement un découpage plus fin (continent/pays/région) de cette base.
Voici une liste non exhaustive des sites proposant ce découpage :

Les données téléchargées sont au format PBF (Protocol buffer Binary Format) basé sur le format binaire protobuf de Google. Cet encodage est moins volumineux et plus rapide à lire et à écrire que des fichiers XML compressés au format bzip ou gzip (également disponible sur le site OSM).

 

Intégration des données OSM dans une base de données spatiale locale

  • Construction de notre base de données postgreSQL/postGIS

PostgreSQL est un système de gestion de bases de données relationnelles et objets (SGBD). Ce SGBD possède une extension pour gérer les bases de données spatiales nommées postGIS (Geografic Information System). Elle permet la manipulation d’informations géographiques sous forme de géométries (points, lignes, polygones), identifiées par des tags conformément au standard établis par l’Open Geospatial Consortium. Cette extension permet d’héberger une BDD géographique comme OSM.

Voici la procédure à suivre pour installer la base de données postgreSQL/postGIS :

Installation du paquet postgreSQL :

moi@machine$ sudo apt-get install postgresql-<version>-postgis

Utilisez l'utilisateur de postgreSQL pour pouvoir exécuter les commandes qui suivent :

moi@machine$ sudo -u postgres -i

"postgres" est l'utilisateur du serveur postgreSQL. Le but étant simplement de constituer un rendu de tuiles en local et non de mettre à disposition cette BDD à d'autres utilisateurs, j’utilise donc directement cet utilisateur pour constituer la base de données OSM postgreSQL/postGIS.

Creation de la base de donnée osm :

postgres@machine$ createdb -E UTF8 -O postgres osm

postgres = nom d’utilisateur
osm = base de données créée

Lien des extensions postgis à la base de donnée osm :

postgres@machine$ psql -d osm -f /usr/share/postgresql/<version>/contrib/postgis.sql
postgres@machine$ psql -d osm -f /usr/share/postgresql/<version>/contrib/postgis_comments.sql
postgres@machine$ psql -d osm -f /usr/share/postgresql/<version>/contrib/spatial_ref_sys.sql

Ouverture de l’outil d’édition en ligne de commande postgreSQL pour la BDD OSM :

postgres@machine$ psql -d osm
osm=#

Vérification de la présence des tables « geography_columns » et « geometry_columns » spécifique à la base de donnée spatiale postGIS :

osm=# \d (permet d’observer la création des tables / défaut suite à l’intégration de postGIS)

List of relations
Schema  |        Name        | Type  |  Owner
--------+--------------------+-------+----------
public  | geography_columns  | view  | postgres
public  | geometry_columns   | view  | postgres

osm=# \q (sortie de l’éditeur de commande de postgreSQL)
postgres@machine$ (ctrl-D) (retour à notre compte utilisateur standard)
moi@machine$

Notre base de données est maintenant prête à recevoir les données en provenance de notre fichier "<carte>.osm.pbf".

  • Chargement de notre BDD avec l’outil osm2pgsql

C’est au travers de l’outil osm2pgsql que nous allons réaliser le transfert du fichier <carte>.osm.pbf dans notre base de données postGIS.

Chargement du paquet osm2pgsql :

moi@machine$ sudo apt install osm2pgsql

Passage en utilisateur postgres pour lancer la commande osm2pgsql :

moi@machine$ sudo -u postgres -i
postgres@machine$

Le chargement de la base de donnée doit se faire via le compte utilisateur du serveur de BDD.

Lancement de l’outil osm2pgsql pour la conversion de données ".osm.pbf" vers la base postGIS :

postgres@machine$ osm2pgsql -m -s -U postgres -d gis carte.osm.pbf
NB :

Le root directory de l'utilisateur postgres est /var/lib/postgresql. Afin d’éviter les problèmes de droit d’accès au fichier, le fichier <carte>.osm.pbf sera à placer au préalable dans cette arborescence (ex : /var/lib/postgresql/data/<map>.osm.pbf).

La BDD sur postGIS est maintenant constituée. On peut vérifier la présence des nouvelles tables créées à la suite de l’importation.

postgres@machine$ psql -d osm
osm=#
osm=# \d

List of relations
Schema  |        Name        | Type  |  Owner
--------+--------------------+-------+----------
public  | geography_columns  | view  | postgres
public  | geometry_columns   | view  | postgres
public  | planet_osm_line    | table | postgres
public  | planet_osm_nodes   | table | postgres
public  | planet_osm_point   | table | postgres
public  | planet_osm_polygon | table | postgres
public  | planet_osm_rels    | table | postgres
public  | planet_osm_roads   | table | postgres
public  | planet_osm_ways    | table | postgres
public  | spatial_ref_sys    | table | postgres

 

Transformation de BDD locale en tuiles grâce à l'outil Mapnik

Notre BDD est maintenant constituée et stockée sur notre ordinateur. Nous allons maintenant transformer l’information géographique en tuiles dont l’apparence sera figée.
Chaque tuile sera identifiée en fonction de sa position géographique et stockée dans un dossier correspondant à son niveau de zoom.
Nous utilisons l’outil Mapnik pour effectuer cette transformation.

Utilisation de Mapnik

Mapnik est constitué d’un ensemble d’outils écrits en C++ et Python permettant la transformation de tuiles.

Récupération des fichiers Mapnik depuis le dépot subversion d'OSM :

$ svn checkout https://svn.openstreetmap.org/applications/rendering/mapnik
$ cd mapnik

Le fichier README dans le dossier principal donne des informations intéressantes sur l’ensemble des outils disponibles dans Mapnik.

Récupération des shapefiles :

$ mkdir  world_boundaries/
$ ./get-coastlines.sh

L’exécution de ce script permet la récupération de l’ensemble des "shapefiles" nécessaires à la construction de la carte dans le fichier world_boundaries. Ces shapefiles seront ensuite exploités par le dernier script de réalisation de tuile.

Note sur les shapefiles :

Les shapefiles sont largement utilisés pour contenir des données vectorielles géographiques. Ils sont en fait une collection de différents fichiers comme nous l’observons dans le dossier "world_boundaries". Ces shapefiles (.shp) sont accompagnés de fichiers de même nom aux suffixes différents (".shp", ".shx", ".dbf", ".prj",".cpg",".index") et contiennent des informations complémentaires aux "shapefiles".

Pour les niveaux de zoom les plus bas, Mapnik utilise des données externes sous forme de shapefiles afin de représenter :

  • les lignes côtières
  • les frontières
  • les grandes villes

L’affichage des lignes côtières est souvent plus complexe. Beaucoup de logiciels de rendu ont besoin de polygones réellement fermés pour générer un rendu de carte correct. La complexité, la constance et le besoin d’établir une géométrie robuste font que ces types d’informations sont stockées au format "shapefile".

Ce format permet également de répondre au besoin de partage des informations importantes pour d'autres systèmes de gestion de données géographiques (QGIS par exemple).

Edition et exécution du script "set-mapnik-env"

Ce script permet de définir l’ensemble des variables d’environnement nécessaires à la construction des tuiles. Tous les paramètres à renseigner sont intégrés à l'intérieur du script.

Définition des variables d’environnement du shell :

$ source ./archive/set-mapnik-env

Vérification des variables d’environnement MAPNIK :

$ env | grep MAPNIK
MAPNIK_TILE_DIR=/home/widev/mapnik/tiles_europe/
MAPNIK_DBPORT=5432
MAPNIK_SYMBOLS_DIR=/home/widev/mapnik/symbols/
MAPNIK_DBPASS=smile
MAPNIK_MAP_FILE=/home/widev/mapnik/osm.xml
MAPNIK_WORLD_BOUNDARIES_DIR=/home/widev/mapnik/world_boundaries/
MAPNIK_PREFIX=planet_osm
MAPNIK_DBNAME=osm
MAPNIK_DBHOST=localhost
MAPNIK_DBUSER=postgres

Constitution du fichier osm.xml :

$ ./generate_xml.py --dbname osm --host 'localhost' --user postgres --port 5432 --password 'your_pwd'

NB : Il y a une redondance sur les paramètres d’entrées caractérisés par les variables d’environnement et les paramètres du script ./generate_xml.py que je ne sais pas expliquer.

La présence à la fin du script d’une variable bbox (bounding box) permet de définir les frontières de génération des tuiles. La fonction render_tiles() qui suit permet de lancer le processus de génération de ces tuiles. L’utilisateur est donc libre de définir plusieurs zones géographiques dont il voudra obtenir des tuiles. Il n’aura qu’a définir plusieurs bounding box, toutes suivies de la fonction render_tiles().

Dans les cas où les informations géographiques contenues dans la BDD (stockée dans postGIS) ne couvre pas la totalité de la bbox, on observera tout de même sur les zones non couvertes par cette BDD le dessin des continents correspondant à l'expression des shapefiles.

Le formalisme de la bbox est le suivant :

bbox = (gauche, bas, droite, haut)
bbox = (Longitude min, Latitude min, Longitude max, max Latitude)

La latitude est un nombre décimal compris entre -90.0 et 90.0.
La longitude est un nombre décimal compris entre -180.0 et 180.0.

La formalisme de la fonction render_tiles() est la suivante :

render_tiles(bbox, mapfile, tile_dir, <zoom min>, <zoom_max>, "nom_tuiles")

NB :

Le site geofabrik.de fournit un assistant graphique qui permet de déterminer à partir d’une délimitation géographique :

  • les valeurs de la bounding box
  • la plage de zoom nécessaire pour permettre l’observation de cette zone
  • l’espace mémoire des tuiles nécessaires pour chacun et pour l’ensemble des zooms
  • le nombre de tuiles pour chacun des niveaux de zoom et pour l’ensemble

Nous obtenons donc pour Paris la bounding box et la fonction render_tiles() suivante :

# Paris+
bbox = (2.11, 48.69, 2.59, 49.01)
render_tiles(bbox, mapfile, tile_dir, 9, 18, "Paris+")

Ces deux lignes seront à insérer à la fin du script genrate_tiles après avoir commenté les autres couples bbox/render_tiles().

Mapnik met à disposition un script permettant de générer une image à partir de la variable bounding box. Un premier test de réalisation d’image de 256 x 256 pixel au niveau de zoom le plus bas (cad le plus petit) peut être intéressant pour contrôler au préalable les frontières bbox et l’apparence avant d’effectuer le rendu de tuile final.
Les variables à rentrer pour la génération de l’image sont :

bounds = (2.11, 48.69, 2.59, 49.01)
z = 9
imgx = 256 * z
imgy = 256 * z

Après exécution du script generate_image.py, nous obtenons cette l’image :

Cette image nous confirme donc la bonne définition de notre bounding box. Nous pouvons maintenant générer l’ensemble de nos tuiles via la commande :

./generate_tiles.py

Voici un aperçu des tuiles générées dans un des dossiers correspondant au niveau de zoom :

A titre d'information, mon ordinateur i5 équipé de 16 Gio de RAM a passé un peu plus de 3 heures à générer les tuiles pour la précédente bounding box. L'espace occupé par l'ensemble des tuiles générées est de 1,5 Gio. Pour "tuiler" l'ensemble de la map monde, nous aurions généré un volume de tuile dont l'espace aurait été supérieur à 100 Gio.

Les manipulations manuelles sont ici nombreuses et il est possible de les automatiser (scripts ou outils d’exécution de plus haut niveau).

Note sur les stylesheets :

Les apparences sont présentes dans le dossier mapnik/inc/. Comme cité précédemment, l’ensemble des tuiles est obtenu par la combinaison des données géographiques et de feuilles de styles au travers de l’outil de rendu qu’est le script generate_tiles.py. Les feuilles de style sont aussi présentes dans le sous dossier manik/inc/. Elles permettent de définir l’apparence des cartes en fonction :

  • de la nature de l’information géographique
  • du niveau de zoom

 

NB : Ceux pour qui la modification des apparences via les feuilles de style est rédhibitoire, il existe des logiciels qui permettent l’édition de carte en mode graphique. Le wiki d’Open Street Map présente les différentes alternatives (lien).

Ces logiciels d’édition de carte contraignent le format des stylesheets et/ou la méthode de génération des cartes. Il est donc possible que certains logiciels soient incompatibles avec la méthode de génération des cartes avec Mapnik.

 

 

Exploitation de nos tuiles sur Raspberry Pi

Nos tuiles peuvent maintenant être visualisées sur système embarqué.

Nous pouvons exploiter nos tuiles de 2 manières différentes: via une API web ou locale. Nous avons choisi pour cette article l'utilisation d'une API web.

Parmi les API web de visualisation dynamique de cartes, il y en a 2 qui sont plus largement utilisées :

  • OpenLayer, mature et riche de nombreuses fonctions
  • Leaflet, plus rapide à mettre en place avec des bibliothèques beaucoup plus légères

Nous utiliserons ici l’API Leaflet.

Concernant les APIs locales, vous pouvez en utiliser une parmi celles citées sur le wiki OSM (lien).

L’API Leaflet étant une API Web, nous devons donc :

  • lancer un serveur HTTP
  • constituer un ficher index.html permettant :
    • de charger l’API Leaflet dans le cache de l'explorateur web
    • de pointer le dossier contenant les tuiles préalablement construites

Voici les étapes à suivre pour pouvoir visionner dynamiquement vos tuiles :

  • Créer un dossier www/ permettant d’accueillir l’environnement du serveur web.
  • Générer dans ce dossier un fichier index.html avec le code suivant (le code est issu d'un code exemple fourni par Leaflet (lien)) :
<!DOCTYPE html>

<html>
<head>
    <title>Quick Start - Leaflet</title>
    
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    
    <link rel="shortcut icon" type="image/x-icon" href="docs/images/favicon.ico" />
    <link rel="stylesheet" href="leaflet.css" />
    <style>
        body {
        padding: 0;
        margin: 0;
        }
    </style>
</head>
<body>
    <div id="mapid" style="width: 100%; height: 100vh;"></div>
    <script src="leaflet.js"></script>
    <script>
        var mymap = L.map('mapid').setView([48.69, 2.59], 9);
        L.tileLayer('http://localhost:8000/tiles/{z}/{x}/{y}.png', {maxZoom: 18}).addTo(mymap);
    </script>
</body>
</html>

Pour utiliser Leaflet offline, il faut télécharger la version stable de Leaflet (lien) et extraire l'archive dans le dossier www/ ou se trouve le fichier index.html. Cette archive contient 3 éléments principaux :

  • leaflet.js : Le code JavaScript de l'application Leaflet
  • leaflet.css : La feuille de style pour l'affichage de l'application
  • images/ : Le dossier contenant les images référencées par leaflet.css

Démarrage du serveur web :

$ cd www/
$ python -m SimpleHTTPServer 8000

Nous utilisons un serveur web python pour afficher rapidement nos API Web locale.

Dans notre explorateur web, nous entrons dans l’URL la ligne suivante :

http://localhost:8000/

Et nous obtenons l’affichage de nos tuiles préalablement générées sur notre Raspberry Pi avec le navigateur Chromium.

 

CONCLUSION

Cet article vous a montré une méthode pour créer et visualiser dynamiquement vos cartes sur une architecture embarquée en mode hors ligne.

Au travers des rendus obtenus, on peut se rendre compte de la richesse d’information que contient la base de données Open Street Map. Ce modèle coopératif est une solution pérenne pour maintenir la liberté que nous avons d'exploiter les informations géographiques du monde entier (éducation, services, commerces, …).

Le travail décrit dans cet article peut être le point de départ pour :

  • styliser vos cartes
  • rajouter des informations à votre carte en statique ou en dynamique
  • intégrer des informations de géocodage dans votre carte afin de pouvoir :
    • afficher des informations relatives à une adresse (ex : Nominatim)
    • intégrer cette solution de géocodage au sein d’un outil de création d’itinéraire (ex : OSRM ou pg_routing.org)

Le monde de l’Open Data est ici complémentaire à celui de l’Open Source. L'exemple d'Open Street Map est ici à suivre au regard des futures évolutions technologiques propriétaires que nous désirerons exploiter.

    • le 27 août 2018 à 00:31

      Merci pour cet article très complet.

      Certaines applications mobiles fonctionnent en mode non connectées.
      C'est le cas notamment de OsmAnd ( https://osmand.net/ ). Les cartes doivent être préalablement chargées. Ce sont des fichiers .obf ( https://wiki.openstreetmap.org/wiki/OsmAndMapCreator )
      Avez-vous une idée comment ces fichiers sont exploités ? Est ce que le calcul des tuiles est dynamique et fait en temps réel ?
      Merci pour vos réponses.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée.