Une version 2.12 du guide d’implémentation des services de visualisation d’INSPIRE (datée du 16 juin 2010) est disponible ici. Ce document intéressera ceux qui s’interrogent sur la manière dont un service WMS peut être utilisé pour diffuser des données en respectant les attentes d’INSPIRE. Les aspects les plus pointus de ce document résident dans la manière de gérer le multilinguisme ainsi que les métadonnées associées aux services et aux couches de données.
Archive pour le mot-clef ‘WMS’
Technical Guidance to implement INSPIRE View Services
Dimanche 1 août 2010Mapserver et GDAL, duo magique
Mardi 20 avril 2010La dernière version de GDAL, la 1.7.1, améliore encore l’utilisation de sources de données distantes de type WMS. La documentation reste toutefois succinte et ne dévoile pas les possibilités offertes par les « minidrivers ». Rappelons le principe de base : il s’agit de pouvoir considérer une ressource distante (WMS, TMS) comme une source de données GDAL standard et de pouvoir la manipuler comme s’il s’agissait d’un raster en local. Ca peut déjà rendre service avec le WMS. Mais l’intérêt principal réside en sa capacité à exploiter des ressources tuilées. Qui n’a jamais été frustré de ne pas pouvoir exploiter un service WMS-C ou TMS car la projection proposée ne correspondait pas à son besoin ? Les « minidrivers » permettent de contourner cet obstacle. Comment ? Assez simplement en fait. GDAL va considérer le résultat que vous lui demandez (étendue géographique, projection…), récupérer les tuiles correspondantes, en découper le superflu, les assembler en une seule image et reprojeter le tout dans ce que vous aurez demandé. La configuration de l’accès au service se fait via un petit fichier XML simple à renseigner :
<GDAL_WMS>
<Service name="WMS"> --> Description du type de service (WMS, TMS...)
<Version>1.1.1</Version> --> Version du service
<ServerUrl>http://labs.metacarta.com/wms-c/Basic.py?</ServerUrl>
--> Url d'accès au service
<Layers>basic</Layers> --> Couches à récupérer
</Service>
<DataWindow> --> Configuration plus générale de la données distante
<UpperLeftX>-180.0</UpperLeftX> --> Sur ces quatres lignes, la bbox
<UpperLeftY>90.0</UpperLeftY>
<LowerRightX>180.0</LowerRightX>
<LowerRightY>-90.0</LowerRightY>
<TileLevel>19</TileLevel> --> Le nombre de niveaux dans le cache
<TileCountX>2</TileCountX> --> Le nombre de tuiles en X à la plus
faible résolution (niveau 0)
<TileCountY>1</TileCountY> --> Le nombre de tuiles en Y à la plus
faible résolution (niveau 0)
</DataWindow>
<Projection>EPSG:4326</Projection> --> Projection de la source de données
<BlockSizeX>256</BlockSizeX> --> Largeur des tuiles
<BlockSizeY>256</BlockSizeY> --> Hauteur des tuiles
<BandsCount>3</BandsCount> --> Canaux de couleur dans l'image
(ici, 3 pour RGB)
</GDAL_WMS>
Avec ces informations, GDAL se retrouve capable de traiter la ressource distante comme une donnée locale. Mais ce n’est pas tout. MapServer pouvant utiliser un tel fichier de configuration XML comme source de données d’un LAYER, on peut connecter le service distant à un contexte MapServer particulier, et créer un service WMS non tuilé exploitant des données distantes tuilées. Pratique pour les outils SIG bureautiques par exemple, qui restent incapables d’exploiter le WMS-C !
La configuration d’un tel LAYER dans MapServer est assez basique :
LAYER
NAME test_wms_c
DATA "wms_c.xml"
METADATA
"ows_title" "Couche WMS-C réassemblée"
END
TYPE raster
PROCESSING "OVERSAMPLE_RATIO=1" --> Ne pas récupérer
plus de tuiles que
nécessaire (directive pour GDAL)
PROCESSING "RESAMPLE=BILINEAR" --> rééchantillonner l'image
STATUS ON
PROJECTION
"init=epsg:4326"
END
END
On peut alors reprojeter la ressource initiale, ainsi que l’exploiter sur des échelles intermédiaires non prévues dans le tuilage. Attention quand-même à ne pas trop en faire, car les tuiles reprojetées et rééchantillonnées ne seront pas forcément très belles à voir. L’idéal reste quand-même de conserver au moins la projection initiale.
En résumé nous avons donc :
ressource distante tuilée, définie sur certaines échelles
et une projection spécifique
|
|
GDAL : calcule les requêtes à effectuer,
récupère les tuiles, les assemble,
reprojette si demandé,
découpe si nécessaire
|
|
MapServer : publie la nouvelle ressource pseudo-locale
en toute liberté (projection, échelles...) mais
avec une qualité du rendu potentiellement
dégradée (en fonction des transformations effectuées).
Pour les obsessionnels, oui, on peut aussi mettre en cache la ressource MapServer locale. Mais pas besoin de TileCache pour cela. Les « minidrivers » intègrent un mécanisme de cache qui permet à GDAL de stocker localement les tuiles récupèrées et ainsi de pouvoir les réutiliser plus tard. Pour ce faire, il suffit de rajouter un bloc « cache » dans le fichier XML (voir la doc pour cela).
Mais je sens déjà la question venir chez tous les habitués des caches… Comment GDAL fait-il pour déterminer les résolutions et la grille à utiliser ? Ah, bonne question. Pour les résolutions, autant le dire tout de suite, il suppose unilatéralement que chaque niveau vaut la moitié du précédent, ou que chaque tuile se subdivise en quatre si vous préférez. C’est l’approche standard, mais si on vous demande du 25k, 20k,15k,10k,5k, ça ne va pas être possible.
Pour les limites de la grille, l’exemple plus haut se base sur une grille standard WGS sur le monde entier, et le TileCount permet de calculer l’emprise des tuiles du premier niveau, puis des niveaux suivants. Pour des emprises plus spécifiques, on peut aussi utiliser TileX et TileY, qui représentent des valeurs à ajouter pour gérer un décalage de la grille sans toucher à l’extent globale.
Les domaines d’application sont nombreux. On peut citer d’emblée :
- L’intégration de données tuilées dans des clients non prévus pour cela
- La reprojection de données tuilées
- L’utilisation de données tuilées à des zooms spécifiques non disponibles
- L’alignement des grilles de deux ressources tuilées configurées différemment
- L’exploitation en pur WMS de données lourdes à générer (Open Street Map par exemple)
- Et sans doute bien d’autres problèmes d’exploitation que l’on rencontre.
Ainsi, ce petit exemple illustre bien, une fois de plus, les étonnantes possiblités offertes par MapServer et GDAL quand ils sont utilisés de concert. Plus que le strict respect des normes, c’est la liberté qu’ils donnent aux utilisateurs pour résoudre leurs problèmes qui est précieuse.
WMS 1.3 et gestion des coordonnées
Mercredi 8 juillet 2009Comme 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 2009Vous 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 2008TileCache 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.
-
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.
-
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.
-
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.
-
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.
-
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é !
-
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 !