FR:User:Petrovsk/Mapnik server
Construire son serveur cartographique sous Mac OS X.
Cela fait un moment que j'ai envie de monter mon serveur cartographique, mais la tâche est ardue et j'ai dû renoncer après plusieurs tentatives infructueuses. Cela ressemble à un grand jeu de construction dont les pièces sont nombreuses, et il faut employer des techniques absconses pour les assembler.
Comme il n'y a pas de guide spécifiquement conçu pour Mac OS X, j'ai décidé d'en faire un en regroupant les éléments m'ayant permis d'atteindre mon but.
Préambule
Vue d'ensemble
Nous allons partir d'un fichier de données OSM et aboutir à une carte affichée dans un navigateur internet. Entre les deux, une base de données stockera les données, un moteur de rendu (mapnik) créera les tuiles (images) de la cartes qui seront distribuées au navigateur par un serveur web.
En rentrant plus dans le détail, nous découvrons le nom des divers programmes et scripts nécessaires pour faire tourner tout cela :
Ces programmes sont très spécifiques et se basent pour certains sur des dépendances. En bon macintoshien je vais m'efforcer d'utiliser un maximum de packages pré-compilés, en essayant d'aller au plus simple. Les didacticiels concernant la mise en place d'un serveur mapnik concernent surtout Linux et particulièrement Ubuntu. Mac OS X a beau être un UNIX, il va falloir adapter pas mal de choses.
Je me suis surtout basé sur ce didacticiel du FOSS4G 2010 à Barcelone (Free and Open Source Software for Geomatics Conference), contenant de précieuses informations pour Mac OS, aussi celui-là, celui-ci et la page mapnik du wiki OpenStreetMap.
Faisons la liste des courses :
- Mapnik se trouve sous forme de framework chez dbsgeo, il nécessite le framework GDAL complete, disponible chez KyngChaos.
- PostgreSQL se télécharge sur KyngChaos.
- PostGIS, extension géographique de postgreSQL, se trouve aussi sur KyngChaos. Elle aussi nécessite GDAL complete.
- osm2pgsql, disponible aussi chez dbsgeo.
- tilelite permet de piloter mapnik et de servir les dalles créées au navigateur. Son source sera téléchargé à partir de son dépôt à l'aide de mercurial.
- OpenLayers est la librairie javascript demandant les dalles au serveur et les affichant.
Commençons par télécharger les éléments ci-dessus disponibles en packages.
Installation des outils
Dans l'ordre, nous installons :
- GDAL complete
- PostgreSQL
- PostGIS
- Mapnik puis Mapnik Python System
Cela se fait le temps de le dire, nous ajoutons nik2img (qui fait sortir des images de mapnik plutôt que des dalles) et mercurial (système de gestion de version qui nous servira pour installer tilelite) à l'aide de easy_install, gestionnaire de paquets python :
sudo easy_install nik2img mercurial
Dans la foulée, et optionnellement, nous pouvons installer QGis, logiciel système d'information géographique qui permettra de fouiller dans les données OSM une fois qu'elles seront dans la base de données postgres. On le trouve aussi sur KyngChaos.
Configuration de la base de données
Configuration de PostgreSQL
Nous allons éditer le fichier de configuration directement dans le terminal avec l'éditeur nano.
sudo nano /usr/local/pgsql/data/postgresql.conf
Décommenter et modifier les lignes suivantes :
shared_buffers = 128MB checkpoint_segments = 20 maintenance_work_mem = 256MB autovacuum = off
ctrl-O
pour écrire dans le fichier, entrée pour sauver, ctrl-X
pour quitter nano.
Nous devons indiquer au système de nouveaux paramètres pour la mémoire partagée. Créer le fichier /etc/sysctl.conf
et y ajouter les lignes suivantes :
kern.sysv.shmmax=268435456 kern.sysv.shmmin=1 kern.sysv.shmmni=32 kern.sysv.shmseg=8 kern.sysv.shmall=65536
Redémarrer.
Pour vérifier que le serveur PostgreSQL est bien reparti, demander son statut, une fois loggé sous l'utilisateur postgres :
sudo su - postgres /usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data status
Il est censé répondre :
pg_ctl : le serveur est en cours d'ex'ecution (PID : 201) /usr/local/pgsql/bin/postgres "-D" "/usr/local/pgsql/data"
Si ce n'était pas le cas, essayer de le relancer avec la commande suivante, toujours en tant qu'utilisateur postgres :
/usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data restart
En cas de refus, le message d'erreur précisera la cause.
Revenir à l'utilisateur normal :
exit
Le module intarray
Osmosis est utilisé pour récupérer les fichiers différentiels planétaires (voir l'article Base locale) qui seront appliqués à la base PostGIS par osm2pgsql. Pour cela, osm2pgsl se sert du module intarray de PostgreSQL, qui n'est pas fourni dans les packages de KyngChaos.
Si vous prévoyez de ne pas mettre à jour votre base, vous n'en avez pas besoin. Dans le cas contraire, il va falloir le compiler à partir des sources de PostgreSQL.
Aller dans le répertoire devant recevoir les sources :
cd /usr/local/src
Télécharger le source de la version installée de PostgreSQL sur cette page et la décompresser dans le répertoire des sources. Se placer dans le dossier postgresql-x.x.x
(8.4.5 dans le cas précédent) et lancer configure :
cd postgresql-8.4.5 ./configure
Aller dans le dossier contrib/intarray
et le compiler :
cd contrib/intarray export PATH=/usr/local/pgsql/bin:$PATH export USE_PGXS=1 make sudo make install
Créer un modèle de base de données
Plutôt que de créer une simple base de données puis la paramétrer, pour éviter de recommencer tout ce paramétrage à chaque création de nouvelle base, nous allons paramétrer un modèle de bases de données que nous pourrons réutiliser pour créer les futures bases de données OSM.
Se logger comme utilisateur postgres puis autoriser l'utilisateur normal (le nom du dossier utilisateur) à utiliser la base :
sudo su - postgres /usr/local/pgsql/bin/createuser nom_de_votre_dossier_utilisateur
Accorder le rôle de super-utilisateur en tapant o
.
Créer le modèle template_postgis :
POSTGIS_SQL_PATH=`/usr/local/pgsql/bin/pg_config --sharedir`/contrib/postgis-1.5
Créer le modèle et ajouter le support du langage PLPGSQL :
/usr/local/pgsql/bin/createdb -E UTF8 template_postgis /usr/local/pgsql/bin/createlang -d template_postgis plpgsql
Autoriser les utilisateurs normaux à créer des bases d'après ce modèle :
/usr/local/pgsql/bin/psql -q -d postgres -c "UPDATE pg_database SET datistemplate='true' WHERE datname='template_postgis';"
Chargement des routines SQL PostGIS :
/usr/local/pgsql/bin/psql -q -d template_postgis -f $POSTGIS_SQL_PATH/postgis.sql /usr/local/pgsql/bin/psql -q -d template_postgis -f $POSTGIS_SQL_PATH/spatial_ref_sys.sql /usr/local/pgsql/bin/psql -q -d template_postgis -f /usr/local/pgsql/share/contrib/_int.sql
Autoriser les utilisateurs à modifier les tables spatiales :
/usr/local/pgsql/bin/psql -d template_postgis -c "GRANT ALL ON geometry_columns TO PUBLIC;" /usr/local/pgsql/bin/psql -d template_postgis -c "GRANT ALL ON spatial_ref_sys TO PUBLIC;" /usr/local/pgsql/bin/psql -d template_postgis -c "GRANT ALL ON geography_columns TO PUBLIC;"
Revenir à l'utilisateur normal :
exit
Des données d'OSM à PostGIS
Récupérer des données OpenStreetMap
Je détaille sur cette page plusieurs méthodes de récupération, faites votre choix selon la quantité de données à récupérer.
Je reprends la même zone que l'atelier du FOSS4G pour faciliter la suite. Téléchargeons les données des environs de Barcelone par la XAPI :
cd /Users/Petrovsk/OSM/Datasets curl -g -L http://www.informationfreeway.org/api/0.6/*[bbox=1.998653,41.307213,2.343693,41.495207] -o barcelona.osm
Cela représente environ 25 Mo au 26 novembre 2010, selon l'humeur du serveur envoyant les données cela peut-être lent ou très lent.
Nous allons profiter du temps de téléchargement pour créer une base de données appelée barcelona
.
sudo su - postgres /usr/local/pgsql/bin/createdb barcelona -T template_postgis exit
Importer les données dans PostGIS
Allons-y directement :
cd /Users/Petrovsk/OSM/Datasets osm2pgsql --merc -d barcelona barcelona.osm
Le --merc
demande la projection de Mercator (c'est le défaut mais je préfère le laisser).
Pour les grande zones, passer en mode slim (pour économiser la RAM) et préciser la quantité de mémoire à utiliser :
osm2pgsql --merc -s -d barcelona -C 1024 barcelona.osm
Visualiser les données dans QGis
Suivre les menus suivants : Couches>Ajouter une couche PostGIS...
, cliquer sur "Nouveau". Choisir le nom que vous voulez pour la couche puis tapez barcelona
dans la case "Base de données". Cliquer sur le bouton "Tester la connexion" puis "OK". Dans la fenêtre d'ajout de couche PostGIS sélectionner "barcelona" dans le menu déroulant et cliquer sur "Connecter".
Apparaissent alors les tables de la base de données, (line, point, polygon, roads
), cliquer sur celles qui vous souhaitez afficher et cliquer sur "ajouter" en bas de la fenêtre. Les données s'affichent.
Il est maintenant possible d'utiliser QGis pour faire des requêtes SQL et obtenir l'affichage d'un type particulier de données, faire de l'analyse…
Configurer mapnik
Fichier de style et données annexes
Le style mapnik est l'ensemble des fichiers définissant le rendu selon les niveaux de zoom, quels éléments doivent être rendus, le tout accompagné des différentes icônes, des fichiers de configuration et des scripts de rendu. Le style mapnik d'OpenStreetMap est disponible sur le svn, téléchargeons-le dans le dossier serveur_carto
:
cd ~/OSM svn co http://svn.openstreetmap.org/applications/rendering/mapnik serveur_carto
Pour plus de rapidité, certaines données à grande échelle sont de source extérieure à OSM, c'est le cas des grandes villes, des zones bâties, des frontières visibles aux premiers niveaux de zoom. Une exception notable est la ligne de côte, récupérée manuellement (comprendre irrégulièrement) depuis OSM et fournie à mapnik sous forme de shapefile qu'il faudra mettre à jour de temps en temps. Ces données sont hébergées par OpenStreetMap et Natural Earth.
cd serveur_carto curl -O http://tile.openstreetmap.org/world_boundaries-spherical.tgz # (50M) curl -O http://tile.openstreetmap.org/processed_p.tar.bz2 # (227M) curl -O http://tile.openstreetmap.org/shoreline_300.tar.bz2 # (46M) curl -O http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/10m-populated-places.zip # (1.5 MB) curl -O http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/110m/cultural/110m-admin-0-boundary-lines.zip # (38 KB)
Décompresser les archives :
tar xzf world_boundaries-spherical.tgz # Crée le dossier 'world_boundaries' nécessaire aux styles tar xjf processed_p.tar.bz2 -C world_boundaries tar xjf shoreline_300.tar.bz2 -C world_boundaries unzip -q 10m-populated-places.zip -d world_boundaries unzip -q 110m-admin-0-boundary-lines.zip -d world_boundaries
Nous devons maintenant indiquer la base de données à mapnik :
./generate_xml.py --dbname barcelona --user postgres --accept-none
Nous allons vérifier que mapnik fonctionne en créant une image avec nik2img, installé précédemment. Je lui demande une image de 500x300 pixels, centrée sur 41.38N et 2.18E, au zoom 14 :
nik2img.py osm.xml barcelona.png -c 2.18 41.38 -d 500 300 -z 14
Tilelite
Installer tilelite
Nous avons installé mercurial à la première étape, nous nous en servons pour installer tilelite depuis son dépôt :
hg clone http://bitbucket.org/springmeyer/tilelite cd tilelite sudo python setup.py install
Utiliser tilelite
Pour servir les dalles, tilelite a besoin de connaitre le chemin du style mapnik. Comme j'ai installé les styles dans le dossier suivant : /Users/Petrovsk/OSM/serveur_carto
, la commande pour lancer le serveur de dalles est la suivante :
liteserv.py ~/OSM/serveur_carto/osm.xml
Ouvrir un navigateur et taper dans la barre d'adresse :
http://localhost:8000/
La page d'accueil de tilelite doit s'afficher, le lien url: /1/0/0.png
affiche la dalle d'Amérique du Nord générée en temps réel par mapnik.
Pour arrêter le serveur de tilelite, simplement fermer le terminal ou l'onglet de terminal l'exécutant.
Tilelite accepte normalement d'utiliser un fichier de configuration pour choisir son comportement, mais il s'est montré particulièrement récalcitrant. Heureusement, il est possible de passer les paramètres dans la ligne de commande, du moins pour faire ce dont j'ai besoin, c'est-à-dire activer le cache (argument -c
) et indiquer son chemin (voir plus loin).
Méthodes d'affichage des dalles
Les dalles peuvent être pré-générés, générées en temps réel à l'aide du serveur de tilelite, en temps réel avec un cache stockant les dalles pour affichage ultérieur, ou bien en combinant pré-génération, cache et temps réel.
Dans ce dernier cas, certains niveaux de zoom sont pré-générés (de 0 à 12 par exemple) dans le dossier qui servira de cache pour les zooms plus élevés, générés en temps réel et ajoutés au cache. La pré-génération permet d'avoir un affichage très rapide, au prix d'une grande utilisation d'espace disque. Pour information, la zone de Barcelone que nous utilisons, une fois rendue jusqu'au niveau 18 occupe environ 567 Mo pour 127856 éléments.
Temps réel
C'est la méthode la plus simple, il suffit de lancer tilelite, rappel :
liteserv.py ~/OSM/serveur_carto/osm.xml
Les dalles sont générées au fur-et-à-mesure des besoins, sans stockage, c'est du coup aussi la méthode la plus lente, dépendant directement de la puissance de la machine. Sur mon Macbook de 2006, l'affichage des dalles n'est pas aussi rapide (et de loin) que le site web d'OpenStreetMap.
Temps réel avec cache
Les dalles sont stockées pour accélérer l'affichage d'une zone déjà visitée et soulager la machine. Il faut lancer tilelite en activant le cache et en lui indiquant le dossier de stockage :
liteserv.py ~/OSM/serveur_carto/osm.xml -c --cache-path=/Users/Petrovsk/OSM/serveur_carto/tiles-osm
Pré-génération des dalles
La pré-génération des dalles a pour avantage de ne pas nécessiter le serveur de dalles ni mapnik pour afficher la carte. Mais si la zone visitée n'a pas été générée au zoom voulu, il n'y a pas de recours.
Mapnik utilise le script python generate_tiles.py
pour, comme son nom l'indique, générer les dalles. Il faut lui préciser le dossier des dalles, le chemin d'accès au style mapnik, l'étendue de la zone à rendre et les niveaux de zoom concernés.
Aller dans le répertoire de generate_tiles.py
et créer un dossier pour les dalles :
cd /Users/Petrovsk/OSM/serveur_carto mkdir tiles-osm
Ouvrir generate_tiles.py
dans un éditeur de texte et modifier quelques lignes :
Ligne 13 : indiquer le nombre de processeurs ou de cœurs disponibles. Pour mon CoreDuo ce sera :
NUM_THREADS = 2
Ligne 199 : indiquer l'étendue de la zone à rendre. Il faut la demander à postgres :
psql barcelona -c "select ST_Extent(ST_Transform(way,4326)) from planet_osm_roads;"
La réponse est :
st_extent -------------------------------------------------------------------------- BOX(1.94459513295834 41.2706895358557,2.39693272129235 41.5663815729642)
Nous plaçons donc à la ligne 199 :
bbox = (1.94459513295834,41.2706895358557,2.39687271383137,41.5663815729642)
Ligne 201 : indiquer l'étendue de zoom à pré-générer. Ici, de 0 à 12 :
render_tiles(bbox, mapfile, tile_dir, 0, 12, "World")
Effacer les lignes au-delà de la ligne 201.
Une fois le fichier enregistré, indiquer les chemins d'accès dans le terminal et lancer la génération :
export MAPNIK_MAP_FILE=osm.xml export MAPNIK_TILE_DIR=tiles-osm ./generate_tiles.py
La pré-génération est combinable avec le temps réel et le cache, en indicant à tilelite le dossier des dalles comme cache. Cela permet de pré-générer les premiers niveaux de zoom, les vues plus rapprochées sont créées à la demande et stockées pour les prochaines visites.
OpenLayers
Récupérer OpenLayers
En temps normal, la carte glissante étant un site web, on peut se contenter d'utiliser la bibliothèque OpenLayers en lien depuis OpenLayers.org. C'est la garantie d'utiliser la version la plus récente.
Mais comme notre serveur est autonome, utiliser une bibliothèque locale permet de s'affranchir totalement du réseau. Téléchargez l'archive sur OpenLayers.org, (version 2.10 en ce début décembre 2010) et décompressez-la où vous voulez.
Le wiki d'OpenStreetMap fournit quelques exemples basiques de code pour faire une première carte, nous allons voir comment mettre en place les différents scénarios d'affichage des dalles évoqués dans la section précédente.
Rendu en temps réel
Dans cette version, c'est la bibliothèque OpenLayers en ligne et tilelite qui sont utilisés. Rappel pour lancer tilelite :
liteserv.py ~/OSM/serveur_carto/osm.xml
Créer une page html vierge et y copier le code ci-dessous :
<html> <head> <title>OpenLayers Demo</title> <style type="text/css"> html, body, #basicMap { width: 100%; height: 100%; margin: 0; } </style> <script src="http://www.openlayers.org/api/OpenLayers.js"></script> <script> function init() { map = new OpenLayers.Map("basicMap"); var newLayer = new OpenLayers.Layer.OSM("New Layer", "http://localhost:8000/${z}/${x}/${y}.png", {numZoomLevels: 18}); map.addLayer(newLayer); map.setCenter(new OpenLayers.LonLat(2.17,41.38) // Center of the map .transform( new OpenLayers.Projection("EPSG:4326"), // transform from WGS 1984 new OpenLayers.Projection("EPSG:900913") // to Spherical Mercator Projection ), 12 // Zoom level ); } </script> </head> <body onload="init();"> <div id="basicMap"></div> </body> </html>
Pour utiliser la version locale d'OpenLayers, remplacer la ligne :
<script src="http://www.openlayers.org/api/OpenLayers.js"></script>
par la ligne suivante, en adaptant le chemin évidemment :
<script src="/Users/Petrovsk/OSM/OpenLayers-2.10/OpenLayers.js"></script>
À chaque déplacement de carte ou zoom, tilelite demande à mapnik de générer les dalles avant de les fournir à OpenLayers.
Rendu pré-généré
Les dalles existant déjà, il n'y a plus besoin de faire tourner tilelite ni mapnik, il faut juste indiquer à OpenLayers le dossier de stockage. Dans la ligne :
var newLayer = new OpenLayers.Layer.OSM("New Layer", "http://localhost:8000/${z}/${x}/${y}.png", {numZoomLevels: 18});
Remplacer http://localhost:8000/
par le dossier des dalles pré-générées : /Users/Petrovsk/OSM/serveur_carto/tiles-osm/
Rendu mixte
Par mixte j'entends temps réel + cache ou pré-génération + temps réel + cache.
Le code de la page web est le même que pour la version en temps réel, il faut juste lancer tilelite en activant le cache et en lui précisant son chemin, qui sera le même que celui du dossier de pré-génération :
liteserv.py ~/OSM/serveur_carto/osm.xml -c --cache-path=/Users/Petrovsk/OSM/serveur_carto/tiles-osm
Fin du didacticiel
Il ne reste maintenant qu'à importer de nouvelles données dans la base PostGIS et éventuellement modifier le style mapnik.