neogeo fait son show…

20 avril 2008

Entre le 22 et le 25 avril, à l’occasion de la “Semaine Internationale des Applications Spatiales“, ou Toulouse Space Show pour les intimes, une application réalisée par Neogeo pour le compte du Grand Toulouse va être présentée au public sur le stand du Grand Toulouse. Cette application est une maquette opérationnelle de ce qui deviendra la plate-forme Toulouse Open de mutualisation et de partage de données.

Vue de l’interface

Pour la réaliser, dans un délai très serré, j’ai mis en oeuvre ce que j’estime être le meilleur des technologies OpenSource : un back-office en python, s’appuyant sur le framework Django couplé à une (petite) base de données PostgreSQL, un serveur WMS/WFS avec MapServer, une pincée de GDAL/OGR pour la manipulation des données, un serveur de cache avec TileCache, et bien sûr côté client la dernière version d’OpenLayers et quelques composants MooTools pour les menus. L’intérêt principal de cette architecture est le faible couplage des éléments entre eux. En utilisant des standard d’échange (WMS, XML, JSON…) chaque élément peut être remplacé facilement par un équivalent pour peu qu’il propose les mêmes entrées et sorties. Les données cartographiques sont directement exploitées dans leur format originel, en MapInfo .TAB ou en ECW, afin de faciliter les tâches de mise à jour, qui se font ainsi par simple remplacement des fichiers.

Au niveau fonctionnel, l’application propose visualisation, téléchargement, reprojection, changement de format sur une cinquantaine de couches de données différentes, dont une orthophotographie à 12.5 cm, le parcellaire cadastral, un Modèle Numérique d’Elévation (avec export 3D vers GoogleEarth !) le tout filtré selon le profil de l’utilisateur et les territoires qui lui sont ouverts. Quelqu’un peut ainsi avoir le droit de “voir” une couche sur l’ensemble de l’agglomération, mais ne pouvoir en télécharger qu’une partie. Les utilisateurs peuvent aussi intégrer des ressources WMS externes, ou uploader leurs propres données vers la plateforme. Après validation par l’administrateur, celles-ci deviennent alors visibles par tous.

Le principal défi a été de proposer quelque chose de parfaitement opérationnel en un délai très bref (moins de 30 jours). Pour le relever, le recours à Django s’est révélé être un choix particulièrement judicieux tant la rapidité de développement dans cet environnement et la stabilité du résultat sont impressionnantes. J’en ai par contre peu utilisé les templates, afin de privilégier l’évolutivité et l’autonomie du client. Ainsi la plupart des échanges se font en JSON, notamment l’initialisation de la liste des couches à intégrer dans OpenLayer.
Autre gros avantages de l’utilisation de Django, c’est la constitution quasi-automatique d’un module d’administration très complet. A partir de quelques formulaires, l’administrateur peut ajouter des couches, tout en spécifiant leurs conditions d’accès (droits utilisateurs en visualisation/export), d’affichage (AGG ou PNG, tuilage ou pas, niveau de transparence par défaut…) ou encore le contenu des métadonnées (qui se basent sur template ISO-19139 minimaliste).

Le but à moyen terme, après avoir décontextualisé certains aspects liés aux demandes spécifiques du Grand Toulouse, est aussi de placer cette solution en OpenSource, afin de pouvoir en faire profiter le plus grand nombre. A suivre donc. Si vous passez par Toulouse cette semaine, venez faire un tour du côté du centre des congrès Pierre Baudis, ou n’hésitez pas à me contacter directement pour toute information complémentaire.

MapServer vs Mapnik

9 mars 2008

La récente adoption du format AGG par MapServer (depuis la version 5) l’a doté d’une qualité de rendu qui lui a longtemps fait défaut.

Image MapServer avec rendu AGG

Côté rendu, MapServer a ainsi rejoint une solution plus récente, encore mal documentée, mais prometteuse : Mapnik. Bibliothèque C++ avec une API en python, celle-ci a fait de la qualité graphique une de ses priorités. Elle intègre donc également la bibliothèque AGG (AntiGrainGraphics) permettant de lisser les PNG.

Autant le dire tout de suite, les images produites sont strictement identiques, au pixel près ! Cependant, côté performances, Mapnik est un peu plus intéressant, comme en témoigne ce petit test réalisé sur une machine tout ce qu’il y a de standard pour générer l’image des communes de la pointe du Finistère ci-dessus :

  • MapServer :
    real 0m0.382s
    user 0m0.310s
    sys 0m0.070s
  • Mapnik :
    real 0m0.244s
    user 0m0.200s
    sys 0m0.050s

Mapnik s’acquitte donc de la tâche en 1/3 de temps en moins, pour un résultat, rappelons-le, strictement identique. On retrouve un écart d’autant plus significatif que le jeu de données est important. Sur la France entière, communes BDCarto(c) :

  • Mapserver :
    real 0m25.415s
    user 0m25.330s
    sys 0m0.080s
  • Mapnik :
    real 0m13.673s
    user 0m13.630s
    sys 0m0.040s

C’est preque un facteur 2 qui sépare les deux applications. Alors, MapServer K.O. debout ? Pas si sûr, car le rendu AGG étant souvent utilisé dans un contexte de tuilage et de cache disque (voir par exemple OpenStreetMap) le temps de génération a certes une importance mais pas de manière aussi critique que sur du rendu “live”. L’AGG est un peu trop lent pour être utilisé dans un tel contexte, et il faut souvent se contenter dans ce cas d’une simple rendu PNG standard. Mais les performances sont alors exceptionnelles :

  • MapServer, format PNG 256, communes BDCarto(c) France entière :
    real 0m0.638s
    user 0m0.560s
    sys 0m0.070s

6 dixièmes de seconde pour dessiner les 36500+ communes de France en 600 x 600, c’est remarquable, et peut tenir la dragée haute à bien des SIG desktop (faites vos tests…). Mapnik ne fonctionnant qu’en mode AGG, il ne peut atteindre de tels résultats. De sorte que son rayon d’action se trouve fortement réduit, à la différence d’un MapServer avec lequel on peut jouer avec les différents formats de sortie pour optimiser le rendu ou la rapidité selon les besoins, l’échelle, la couche, le contexte (visualisation / impression) etc.

Optimisation de TileCache

16 février 2008

TileCache est un logiciel qui permet de créer un cache local d’une ressource WMS locale ou distante (du point de vue d’un serveur), afin d’en optimiser l’accès. Il est d’une simplicité déconcertante et d’une efficacité redoutable. Si l’installation et la mise en route sont faciles, il faut quand-même faire quelques réglages pour obtenir des performances optimales. Je vous propose donc un petit résumé de ces étapes, inspiré d’un tutoriel en anglais et de mon expérience personnelle.

  1. L’installation

Simplissime ! Récupérez une archive des sources sur le site de tilecache (http://www.tilecache.org/), et décompressez-la dans un répertoire publié sur le web (/tilecache dans ce qui suit).

Autorisez l’exécution des cgi pour ce répertoire :

<Directory /usr/local/apache2/htdocs/tilecache>
AddHandler cgi-script .cgi
Options +ExecCGI
</Directory>

 

Editez le fichier tilecache.cfg et spécifiez un répertoire de stockage des dalles, par exemple :

base=/usr/local/apache2/htdocs/tileFolder

(NB : ce répertoire doit exister et être accessible en écriture à l’utilisateur apache).

Vous pouvez déjà tester en chargeant la page http://nom_du_serveur/tilecache/. Vous devriez voir apparaître une interface OpenLayers avec une carte du monde. Vérifiez le contenu de votre répertoire de stockage, vous devriez y voir un sous-répertoire « basic », nom de la couche WMS chargée par défaut, contenant des sous-répertoires numérotés.

Arrivé là, vous êtes déjà en train de mettre en cache les couches WMS que vous exploitez. Le reste n’est donc plus qu’une question d’optimisation.

 

  1. La configuration des ressources WMS.

Vous avez sans doute d’autres données à exploiter que les données proposées par défaut. Pour cela, il faut rajouter ces entrées dans le fichier tilecache.cfg, en commençant par le nom de la ressource (layername) entre crochets. A noter que le nom que vous donnez à la ressource est complètement libre, mais que c’est lui que vous devrez utiliser lors des appels à TileCache, depuis OpenLayers par exemple. Voici un exemple complet de configuration d’une ressource :

[geosignal]
type=WMS
url=http://www.geosignal.org/cgi-bin/wmsmap
bbox=-50000,1200000,1400000,2700000
extent_type=loose
extension=png
layers=RASTER4000K,RASTER1000K,RASTER500K,RASTER250K,\
RASTER100K,RASTER50K,RASTER25K,RASTER5K
resolutions=2116.666666667,1058.333333333,529.166666667,\
264.583333333,132.291666667,66.145833333,26.458333333,\
13.229166668,6.614583334,2.645833334,1.322916667
levels=11
srs=EPSG:27572

La pluplart des paramètres sont facilement compréhensibles. Après la bbox cependant, on trouve un extent_type=loose. Il sert à autoriser la création de dalles en dehors de la bbox. Pratique pour éviter les dalles roses dans OpenLayers, quand l’étendue de la carte est plus grande que celle de votre ressource. L’omettre pour forcer les requêtes à se situer dans la bbox. Quant aux résolutions, c’est une manière d’exprimer les échelles. On peut les calculer assez facilement (hmmm…) : les dalles par défaut font 256×256 px. Si les images issues du serveur WMS sont en 96 dpi, chaque dalle fera donc (256/96) = 2,666666667 pouces, soit 2,666666667 x 2.54 = 6,773333333 cm. Au 100000e, cela représente donc 6773,333333 mètres, ce qui ramène à (6773,333333/256) = 26,458333333 m/pixel. La résolution pour le 100000e est donc de 26,45833333, et on peut alors facilement calculer les autres par simple péréquation.

Une autre option peut s’avérer utile, c’est metaTile=true. Elle permet d’envoyer des requêtes sur de larges extents, qui sont ensuite redécoupées en 256 x 256. C’est pratique à plus d’un titre. D’une part c’est souvent plus rapide de faire une requête que 25 (la metaTile fait 5 x 5 dalles de base par défaut), même si l’image est plus grosse. D’autre part ça diminue le problème du chevauchement des labels entre dalles contigües, puisque cet effet de bord n’apparaît plus désormais qu’en frontières des grandes tuiles, donc 5 fois moins souvent (20 faces externes au lieu de 100). Elle nécessite cependant l’installation (si ce n’est pas déjà le cas) de la librairie Image de Python (http://www.pythonware.com/products/pil/) qui fait le travail de découpe. Malheureusement, elle ne gère pas les PNG entrelacés, et cette option ne pourra donc pas fonctionner si la ressource WMS diffuse ses images dans ce format.

  1. Optimisation 1, utiliser mod_python.

TileCache est un programme en python, configuré par défaut pour être exécuté en mode cgi, c’est-à-dire qu’Apache charge à chaque requête l’exécutable python qui traite le fichier tilecache.cgi. C’est un peu lent. Il vaut mieux charger python dans Apache avec mod_python (à activer dans la liste des modules du httpd.conf, ou à compiler et installer directement) car le fichier est alors directement interprété par l’extension python d’Apache, résidente en mémoire.

Donc ajoutez à votre fichier httpd.conf :

LoadModule python_module modules/mod_python.so

Pas de tilecache.py dans votre répertoire tilecache ? Il suffit en fait de renommer le fichier tilecache.cgi en .py . Il faut par contre aussi adapter votre httpd.conf. La configuration du répertoire tilecache devient :

<Directory /usr/local/apache2/htdocs/tilecache>
AddHandler python-program .py
PythonHandler TileCache.Service
PythonOption TileCacheConfig /usr/local/apache2/htdocs/tilecache/tilecache.cfg
</Directory>

Petite précaution : maintenant que python et tilecache.py sont résidents en mémoire, il vous faudra redémarrer Apache à chaque modification du fichier de configuration de TileCache, qui est devenu une sorte de prolongement d’Apache… Il vaut donc mieux avoir bien configuré toutes ses ressources avant cette étape.

Comparez à présent le fonctionnement de votre TileCache, les performances devraient être sensiblement supérieures.

 

  1. Optimisation 2, pré-remplir le cache.

L’intérêt de cette étape dépend du nombre d’échelles de vos données WMS, ainsi que de leur utilisation. Inutile de pré-générer la France au 5000e si peu d’utilisateurs s’en servent. Mais il est souvent agréable d’avoir les 2-3 premiers niveaux pré-générés. Pour ce faire, utilisez le petit programme tilecache_seed.py ainsi :

python tilecache_seed.py ‘url_du_serveur_WMS’ nom_de_la_ressource niveau_de_depart niveau_de_fin

ce qui donne pour notre ressource définie plus haut :

python tilecache_seed.py ‘http://www.geosignal.org/cgi-bin/wmsmap’ geosignal 0 2

Cela générera toutes les dalles pour les niveaux 0,1 et 2 de la ressource « geosignal », soit les trois premières résolutions décrites dans le fichier tilecache.cfg. Il faut bien veiller à utliser le même nom de ressource que dans le tilecache.cfg.

Une fois la pré-génération réalisée, l’affichage sur ces premiers niveaux devrait être beaucoup plus fluide.

 

  1. Optimisation 3, forcer le cache client.

Vous remarquerez toutefois qu’en revenant sur un niveau de zoom déjà consulté, les images sont le plus souvent rechargées depuis le serveur. Dommage puisqu’elles sont déjà dans le cache client. Mais celui-ci (le navigateur) ne sait pas qu’elles sont encore valides. Il faut donc l’aider à le savoir. Pour ce faire, il faut utiliser le module Apache mod_expires. Il n’est pas chargé par défaut, mais peut l’être facilement en dé-commentant ou ajoutant un LoadModule mod_expires dans le httpd.conf si vous avez un version packagée. Par contre, si vous avez compilé Apache vous-même, il faudra le recompiler avec les options –enable-headers –enable-expires. Oui, j’aurais pu le dire avant… Mais Apache est votre ami, lors d’une réinstallation, le make install n’écrase que les exécutables et préserve le fichier de configuration, les modules et le contenu de cgi-bin. Donc tout va bien.

Une fois l’installation réalisée, il faut régler la durée de mise en cache dans la configuration Apache du répertoire tilecache. Rééditez donc à nouveau le httpd.conf et ajoutez dans la section Directory concernant tilecache :

ExpiresActive on
ExpiresDefault “access plus 6 months”

La durée de mise en cache peut se régler finement. Voir la documentation du module Expires pour cela. Tout dépend de la durée de vie des données sources. Si elles sont soumises à une mise à jour quotidienne, on pourra se contenter d’un ExpiresDefault “access plus 6 hours” . A noter que ceci n’a aucune incidence sur le contenu du cache serveur. Donc si les données sont mises à jour quotidiennement, il faut également purger le cache serveur tous les jours !

A l’issue de cette dernière étape, comment dire, après quelques allers-retours entre niveaux de zooms différents, l’affichage devient quasi-instantané !

  1. Optimisation 4, simuler plusieurs serveurs.

La plupart des navigateurs n’effectuent pas plus de deux requêtes simultanées sur un même serveur, mais peuvent par contre en effectuer beaucoup plus vers plusieurs serveurs. En déclarant auprès de votre hébergeur de nouveaux noms de domaines (data1.myserveur.com, data2.myserveur.com, data3.myserveur.com…) pointant tous vers la même IP, les navigateurs pourront alors charger les dalles beaucoup plus vite, pour peu que l’application web que vous utilisez prenne en charge ce genre de requête. Avec OpenLayers il suffit de déclarer non plus une URL, mais un tableau d’URL :

wms_sigma = new OpenLayers.Layer.WMS( "TIGER",
["http://sigma4.openplans.org/tilecache-1.3/tilecache.py?",
"http://sigma3.openplans.org/tilecache-1.3/tilecache.py?",
"http://sigma2.openplans.org/tilecache-1.3/tilecache.py?",
"http://sigma1.openplans.org/tilecache-1.3/tilecache.py?"],
{layers: 'sigma' }, {numZoomLevels: 17});

Si avec tout ça vous allez encore moins vite que GoogleMaps, il ne vous reste plus qu’à acheter un serveur avec 36 Go de RAM et charger votre cache directement dedans. Car TileCache en est également capable !

Version PDF.

Compilation de QGis 0.9

10 décembre 2007

J’ai eu dernièrement quelques difficultés à réaliser une compilation de QGis à partir des sources sous Ubuntu. Comme il se peut que ça vous arrive aussi, voici une petite description des problèmes rencontrés et de leur solution :

Retour du cmake : la non détection de certains modules pourtant installés sur le système se règle soit en vérifiant que les versions de dév des packages sont bien installées (pour Grass par exemple), soit en allant faire un tour dans les fichiers du répertoire cmake et en changeant les chemins par défaut. Ce n’est pas le plus compliqué. Bien vérifier que la version de QT utilisée est la 4.

Compilation : la compilation avec l’option “python-bindings”, qui permet d’intégrer la prise en charge du python, et le fonctionnement du plug-in Grass entre autres, m’a posé problème. Une erreur et son message un peu ténébreux bloquaient le processus :

Error: Unable to open “/opt/qgis/python/core/core.sbf”: [Errno 2] No
such file or directory: ‘/opt/qgis/python/core/core.sbf’

Malgré quelques recherches sur le net, je ne trouvais rien si ce n’est une autre personne ayant eu ce problème, resté alors sans réponse. Voyant que l’erreur en question se produisait lors de la compilation avec QT et SIP, j’ai fait quelques recherches de ce côté-là. SIP est le module qui permet de créer une interface Python vers des bibliothèques C++, un peu comme SWIG donc. Le wiki de QGis a un article là-dessus. Il est indiqué que la version doit être au moins la 4.5, ce qui n’était pas le cas sur mon système (mais d’où venait ce paquetage ?).

J’ai donc compilé les versions indiquées en lien par le wiki, pour SIP et pour PyQT. La compilation est alors allée jusqu’à son terme, et QGis fonctionne correctement avec le module Grass et la console Python.

WorldMill, pour donner des ailes à OGR

20 novembre 2007

Sean Gillies n’est pas un plaisantin. Quand il s’attaque à un sujet, ce n’est pas pour faire un truc qui clignote en vous donnant l’heure. Alors quand il s’est penché sur l’implémentation d’OGR en Python, qu’il trouvait médiocre dans sa version native, il a déjà réfléchi plusieurs jours, savoir s’il vallait mieux utiliser CTypes ou Cython pour lier la librairie C native. Le genre de sujet qu’on lui laisse avec soulagement. Mais quand il teste l’ami Sean, il ne se contente pas de dire “Ctypes sucks dude…”, il sort des statistiques :

Refinery (with ctypes): 4972288.61 usec/pass
Ogre (Cython/Pyrex) : 682301.81 usec/pass
ogr.py (old-school bindings) : 9183181.72 usec/pass

Le coup du old-school bindings en a énervé quelques-uns, qui ont fait remarquer qu’il avait utilisé une vieille version d’OGR. Trop facile ! Mais avec la nouvelle, même si celle-ci est 15 fois plus rapide que la précédente (bravo Howard), Cython garde le dessus :

Refinery (with ctypes)
4994133.40 usec/pass

Ogre (Cython/Pyrex)
593522.91 usec/pass

ogr.py (next generation bindings)
594103.50 usec/pass

De cette implémentation efficace avec Cython, Sean a fait un premier prototype, WordMill. Quelques exemples permettent de se rendre compte de la souplesse du programme. La définition d’un workspace (répertoire de données) suffit à permettre l’accès à toutes les sources de données supportées par OGR qui s’y trouvent, et de parcourir ainsi les fichiers et leur contenu de manière transparente quant à leur format, sans appel à un driver particulier et à travers des structures simples. On peut ainsi accéder aux données, les interroger, les filtrer très efficacement. De la belle ouvrage, doublée d’une installation simplissime. Chapeau Sean !