FR:User:Petrovsk/Mapnik server

From OpenStreetMap Wiki
Jump to navigation Jump to search

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.

Mapnik synoptique.png

En rentrant plus dans le détail, nous découvrons le nom des divers programmes et scripts nécessaires pour faire tourner tout cela :

Mapnik synoptique2.png

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…

Le centre de Barcelone dans QGis

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
La première image mapnik !!!

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.