Archive pour le mot-clef ‘TileCache’

Mapserver et GDAL, duo magique

Mardi 20 avril 2010

La 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.

TileCache : attention aux MetaTiles !

Jeudi 21 janvier 2010

Il est bien commode lors de la génération d’un cache tuilé avec TileCache d’utiliser le mode MetaTile permettant d’envoyer des requêtes correspondant à quelques centaines de tuiles d’un coup, qui sont ensuite redécoupées par TileCache. Cette opération est effectuée par le module PIL. Malheureusement, celui-ci et son implémentation dans TileCache ont quelques défauts qui peuvent aboutir à la dégradation des images faites en MetaTile comparativement à celles générées individuellement.

Le premier défaut concerne de JPEG. La valeur de compression à utiliser n’est pas précisée dans le code et PIL prend donc sa valeur par défaut de 75 %. L’image finale via MetaTile est donc  différente de celle issue de la source de données. Si le serveur WMS lui-même effectue une compression de 75 %, celle effectuée par PIL est vraiment de trop pour la qualité. Ce problème se règle néanmoins facilement, en changeant le code de Layer.py,en ajoutant ces deux lignes après la ligne 406 :

elif self.extension == ‘jpeg’:

subimage.save(

buffer,
self.extension,
quality=95,
optimize=True

)

Le niveau de qualité de 95 % correspond en effet à « pas de compression ». A 100 % il n’y a pas non plus de quantization des couleurs, et l’image est alors plus grosse que l’originale.
Le deuxième problème est plus embêtant. Il s’agit du format PNG-8bits, dont les palettes ne sont pas correctement restituées par PIL quand l’image a été générée en mode QUANTIZE ON. Pas de solution pour l’instant dans TileCache, malgré des tests faits avec PythonMagick plutôt que PIL. L’idée est donc d’utiliser du PNG 24bits, et de faire la quantization en post-traitement, avec pngnq par exemple et une tâche cron traitant nuitamment les fichiers créés dans la journée.

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.

Des tuiles en PHP

Dimanche 11 janvier 2009

Un nouvel outil OpenSource est disponible pour générer un tuilage d’une ressource WMS. Après TileCache, en Python, et GeoWebCache, en Java, voici PHPGeoTiles, pour les adeptes du PHP.

L’originalité, outre le fait qu’il soit écrit en PHP, vient de sa capacité à stocker le tuilage dans Google App Engine, ce qui rendra vos tuiles beaucoup plus disponibles que sur votre propre serveur puisqu’elles bénéficieront de l’infrastructure Google.

via James Fee GIS Blog

Mieux comprendre les tuilages

Mercredi 10 décembre 2008

Voir c’est comprendre, ou du moins mieux comprendre. Cette page réalisée par Klokan Pietr Pridal permet de bien visualiser les grilles de tuilage utilisées en Spherical Mercator, que ce soit en TMS, Google ou QuadTree de Microsoft VirtualEarth.

Chaque pyramide découpe le monde Spherical Mercator selon la même grille, seule change la manière de nommer les tuiles. On remarquera donc l’inversion de l’axe des Y entre le système Google et le TMS (il faut bien faire travailler les développeurs), et le fait que seul le système quadtree puisse s’affranchir de l’information « niveau de zoom » puisqu’il l’intègre naturellement : c’est le nombre de chiffres du numéro de la dalle.