Archive pour le mot-clef ‘WMS’

WMS 1.3 et gestion des coordonnées

Mercredi 8 juillet 2009

Comme tout un chacun féru de nouveautés, l’intégration d’une nouvelle version d’un standard international (le WMS de l’OGC) dans un quasi-standard des serveurs cartographiques (MapServer 5.4) me donne envie de l’essayer. Tout le problème fut de trouver un client compatible WMS 1.3. C’est le côté contraignant de l’inter-opérabilité, il faut trouver des agents capables d’utiliser la même norme, et ce n’est pas toujours le cas.

Autodesk proposant un téléchargement gratuit d’Autocad Map 2010 en version 30 jours, je me suis lancé (ou plutôt assis avec un café car le fichier à télécharger fait 2.1 Go !). Je n’avais pas vu Autocad Map depuis la version 2002, j’ai dû avoir la même sensation que le pilote de Caravelle qui se retrouve aux commandes d’un A 380… Rien que le nombre de barres d’outils vous donne l’envie de signer fissa pour une formation accélérée. C’est peut-être pour ça que c’est en téléchargement d’ailleurs.

Après quelques recherches je trouve la fonction d’ajout de couche WMS (il faut cliquer sur DATA dans les pratiques outils de gestion des cartes au dessus de la liste des couches…), avec dans la configuration du serveur un choix de version intégrant le 1.3.0. On touche au but donc. Je saisis ce qu’il faut, choisis une couche en projection Lambert (je ne dirais pas laquelle, pour ne pas raviver de querelle entre les anciens et les modernes, ce n’est pas mon propos). Résultat impeccable, bravo. Je refais un autre test avec une couche non projetée cette fois. Echec, rapport d’erreur un peu obscur… Après de longues recherches, je tombe sur le loup. La norme WMS 1.3.0 impose aux coordonnées de la bounding box d’être en lat,lon pour les systèmes de référence non projetés, et non plus en lon,lat comme pour la version 1.1.1 et comme c’est encore le cas pour les systèmes projetés en WMS 1.3.0. Donc mon AutoCad, qui n’a sans doute pas pris cette subtilité en considération, ou mal, a soumis à MapServer une requête incohérente quant à la BBOX utilisée dans le contexte EPSG:4326. Et l’inter-opérabilité pris fin.

Autre nouveauté du WMS 1.3.0 l’utilisation du paramètres CRS= plutôt que SRS= dans la désignation du système de coordonnées, bien que MapServer accepte encore les deux, avec priorité au SRS. Celui-ci peut d’ailleurs s’affranchir du registre EPSG, le WGS 84 pouvant être désigné par CRS:84 plutôt que EPSG:4326. Ces diverses subtilités n’ont pas manqué de provoquer quelques saines réactions sur la liste MapServer-users dès 2006 !

MapServer, substitution de variable et mise en cache.

Vendredi 12 juin 2009

Vous le savez sans doute, MapServer permet de réaliser du « runtime substitution », soit de la substitution dynamique de variable à l’exécution. En clair, votre requête, CGI ou WMS (ce qui revient peu ou prou au même), intègre un paramètre complémentaire dont la valeur va être interprétée au sein du fichier .map.

Pour être plus clair, imaginons que vous  cartographiez les trajets routiers effectués par des utilisateurs. Chaque utilisateur ne doit voir que ses propres trajets parce qu’on est pas chez Big Brother. En rajoutant un paramètre user_id à la requête envoyée à MapServer, on peut filtrer le contenu renvoyé par le fichier .map. La chaîne SQL de récupération des données devient alors :

DATA « the_geom from trajets WHERE user_id = %user_id% »

C’est tout simple donc. En intégrant entre pourcentages le même paramètre que celui envoyé dans la requête, MapServer lui substitue la valeur associée, et le contenu renvoyé est ainsi filtré. On peut aussi ajouter des expressions régulières pour valider les valeurs envoyées et éviter une bonne grosse SQL injection.

Tout cela est connu et très pratique. Ca tord un peu le coup à l’aspect normalisé quand c’est utilisé en WMS, mais les normes ça sert aussi à être dépassé. Néanmoins, il reste un obstacle à la mise en cache des résultats. TileCache par exemple, qui joue un rôle de proxy, ne fait suivre au serveur WMS que les attributs de la norme WMS, et génère alors une erreur car %user_id% sans rien y subsitituer n’est pas utilisable en SQL. C’est pourtant pratique de mettre aussi ce type de résultat en cache.

Mais il y a une solution ! L’Alaska Ocean Observation System publie un patch qui permet de faire suivre au travers de TileCache n’importe quel attribut complémentaire pour peu qu’il soit déclaré dans le tilecache.cfg (fichier de configuration du cache). Ils l’ont fait pour faire du WMS-T (WMS temporel, enrichi d’une variable temporelle pour récupérer des observations par exemple), et étendu à tout attribut complémentaire, ce qui mérite d’être salué.

Une des complications impliquée par ce genre de techique est la multiplication des arborescence, puisqu’un cache spécifique sera créé pour chaque valeur du paramètre. Avec des milliers d’utilisateurs dans mon exemple, ça peut rapidement poser problème. Mais pourquoi alors ne pas utiliser un cache mémoire (Tilecache avec MemCache), d’une taille pré-définie ? Avec quelques giga-octets, on pourra y stocker un bon nombre de tuiles, sans jamais surcharger le système. Les plus récemment créées remplaceront les plus anciennes quand le cache sera plein. Cette méthode s’adapte aussi assez bien au temps (presque) réel, puisqu’on peut paramétrer le durée de vie des données stockées par MemCache. Pour un suivi de conditions de circulation (bouchons…), on peut ainsi quand-même profiter d’un cache qui dure le temps de la validité de la donnée. Mais même 10 minutes, si de nombreux utilisateurs se connectent, c’est un considérable allégement de la charge système.

Petit résumé :

Dans OpenLayers :

layer = new OpenLayers.Layer.WMS("Couche dynamique en cache",
"http://serveur.com/tilecache/",
{layers: 'layer_test',format:'PNG',user_id:myUserId},
{isBaseLayer:true,visibility:true});

on a donc surchargé la définition de la couche avec un paramètre user_id qui prend la valeur de la variable javascript myUserId.

Dans Tilecache.cfg :

on ajoute à la définition du layer WMS : extra_params=user_id

Dans le MapFile :

On intègre le paramètre à la chaîne DATA (ou FILTER, ou EXPRESSION, ou CONNECTION selon les besoins) : DATA « the_geom FROM trajets WHERE user_id = %user_id% »

on ajoute une ligne dans le bloc METADATA de la couche pour valider le user_id:

‘user_id_validation_string’ ‘^[0-9]{1,2}$’ qui impose un entier fait de deux chiffres au maximum.

Optimisation de TileCache

Samedi 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. Pour MapServer, il faut ajouter un FORMATOPTION « INTERLACE=OFF » dans la définition de l’outputformat PNG.

  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.

Ô mon Vélô

Lundi 26 novembre 2007

C’est bien connu, à Toulouse nous ne sommes jamais en retard d’une mode parisienne. Le Vélô, version locale du Vélib’ a donc fait son apparition mi-novembre dans les rues de la Ville Rose, le ô étant là pour rappeler l’inoubliable Ô Toulouse du regretté Claude Nougaro.

Pour permettre aux toulousains de repérer facilement la station la plus proche de chez eux, j’ai réalisé une petite application avec OpenLayers. Les fonds de plan sont issus du service WMS de Geosignal. Les emplacements des stations de Vélô sont issus de la mairie de Toulouse. Pour les exploiter sur le serveur de ce site, dépourvu de serveur cartographique, je les ai transformées au format GeoJSON (au passage, merci à Pierre Giraud pour ses lumières), dans un fichier texte donc, qu’OpenLayers exploite directement depuis une requête XMLHttpRequest. Il y a aussi un fichier KML pour visualiser tout ça dans vous savez quoi.