Tutoriel tilecache

From OSGeo
Revision as of 08:13, 3 September 2008 by Wiki-MartinO (talk | contribs) (→‎Produir un caching)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Roadmap TileCache pour OpenLayers

TileCache est une solution ultra simple, efficace et performante … et surtout de l'avis de plusieurs, une solution d’avenir pour la cartographie sur le Web! Malheureusement, on trouve peu de documentation sur sur ce produit encore peu utilisé. Outre les informations contenues dans le package d’installation, quelques forums et ce blog on est face a soit-même et parfois bien seul! Voici donc quelques notes pour aider ceux qui veulent se lancer.

Il existe plusieurs exemple concret sur le Web de l’efficacité de TileCache. Les exemples au Québec sont peu nombreux mais on peut consulter l’exemple de la BDGA Base de données géographique administrative construit par le Ministère de la sécurité publique du Québec sur lequel est basé ce tutoriel.

Petite note importante, TileCache ne fonctionne QU’AVEC le viewer OpenLayers qui n’est pas vraiment traité ici. Par contre, les exemples avec OpenLayers sont nombreux et en plus il est très simple à installer. De plus, on tient pour acquis que le lecteur maîtrise Mapserver.

Objectif de TileCache

TileCache permet de sauvegarder à l’avance sur un serveur la couverture entière d’un layer ou d’une combinaison de layers, en tuile(fichier gif ou png) pour un nombre déterminé de zoom. L’idée est de préparer à l’avance TOUTES les images qui peuvent être consultées par un utilisateur dans le seul but d’être utra rapide. On a rien inventé de nouveau ici, on ne fait que reprendre le principe de Google maps qui fonctionne déjà très bien et que tout le monde connaît.

Les sources de données de TileCache

Les sources de données pour alimenter TileCache sont principalement les WMS. TileCache permet par exemple de « feeder » (préparer a l'avance et sauvegarder localement) un WMS sur votre serveur pour le rendre très très performant. On ne peut pas penser à OGR ou un simple Shapefile pour produire un Cache, on a besoin d’un WMS.

Installation Windows

  • On considère ici avoir déjà installé MS4W. On trouve dans ce package tout les outils essentiels(Apache dans cet exemple) pour faire rouler TileCache.
  • Ensuite on doit installer python (python-2.5.2.msi) avec une variable d’environnement qui pointe sur le répertoire « bin » de python(PYTHON c:\python25).
  • Si on veut avoir plus de performance(composante non obligatoire mais on le recommande fortement pour accélérer la génération du cache) installer Python Imaging librairy (PIL-1.1.6.win32-py2.5.exe). Cette librairie permet de spécifier une option de metaTile(voir plus bas).
  • Enfin, encore une fois pour la performance (composante non obligatoire), il est possible d’installer le mod_python (mod_python-3.3.1.win32-py2.5-Apache2.2.exe) pour inclure dans la mémoire cache d’Apache les paramètres TileCache et une exécution directe de python par Apache(pour ma part je n’ai pas testé?).
  • Décompresser une application TileCache dans un répertoire visible du web. On peut par exemple le placer dans le répertoire /ms4w/apps/tilecache. Pour le rendre visible sur le Web en mode CGI, on peut simplement placer un nouveau fichier de configuration Apache dans le répertoire /ms4w/httpd.d/ portant une nom de fichier débutant par « httpd_ »
#-----------------------------------
#Fichier \ms4w\httpd.d\httpd_tilecache.conf
#-----------------------------------
#Cet Alias permet d'exposer le répertoire
#de tuile des layers TileCache. Notons
#que le listage Web est interdit dans ce
#config
#-----------------------------------
Alias /tilecach/ "F:/Data/tilecach/"
<Directory "F:/Data/tilecach/">
  AllowOverride None
  Options Indexes FollowSymLinks Multiviews 
  Order allow,deny
  Allow from all
  Options -Indexes
</Directory>

#-----------------------------------
#exposer Tilecache en mode CGI
#-----------------------------------
<Directory "/ms4w/apps/tilecache">
        AddHandler cgi-script .cgi
        Options +ExecCGI       
</Directory>

#-----------------------------------
#Pour mod_python, mais pas testé
#-----------------------------------
#    <Directory "/ms4w/Apache/apps/tilecach/">
#       AddHandler python-program .py
#       PythonHandler TileCache.Service 
#       PythonOption TileCacheConfig /ms4w/apps/tilecache/tilecache.cfg
#    </Directory>


  • On doit éditer l’entête des fichiers pythons qui référence l’exécutable python(tout dépendant de son installation)… Dans le cas de tilecache simplement changer la première ligne du fichier tilecache.cgi
#!C:/Python25/python.exe -u


  • Sur la version dans ce tutoriel et selon ce post on doit faire une modification dans le script python layer.py. Dans les environs de la ligne 115, changer cette ligne
def getCell (self, (minx, miny, maxx, maxy), exact = True):

Pour

def getCell (self, (minx, miny, maxx, maxy), exact = False):
  • On doit aussi, si ce n’est pas déjà fait installer OpenLayers et exposer ce répertoire sur le Web. Pour l’instant TileCache ne fonctionne qu’avec OpenLayer. Voici un fichier configue Apache pour OpenLayers :
#-----------------------------------
#Fichier \ms4w\httpd.d\httpd_openlayers.conf
#-----------------------------------
#Cet Alias permet d'exposer le répertoire
#openlayers
#-----------------------------------
Alias /cartesimple/ "/ms4w/apps/OpenLayers/"
<Directory "/ms4w/apps/OpenLayers/">
    AllowOverride None
    Options Indexes FollowSymLinks Multiviews 
    Order allow,deny
    Allow from all
    Options -Indexes
</Directory>


Installation Linux

TODO ...

Configuration de TileCache

La configuration de tilecache se fait dans un seul fichier tilecache.cfg. On doit dans un premier temps, spécifier le répertoire de caching qui sera utilisé par TileCache. Sous windows avec MS4W, il est simple de spécifier un répertoire dans l’arborescence MS4W(/ms4w/apps/tilecach/). Mais on peut aussi simplement spécifier un path complet si on pointe sur un disque de stockage plus volumineux(F:\data\tilecach\). TileCache utilisera ensuite ce répertoire pour enregistrer les images pré-générées dans chacun des layers configuré. Il faut donc prévoir assez d’espace dans ce répertoire.

[cache]
type=DiskCache
#base=/ms4w/Apache/apps/tilecach
ou
base=f:/Data/tilecach 

Ensuite, on doit spécifier des layers qui seront diffusés par TileCache via OpenLayers. Pour chacun des layers on doit ajouter certains paramètres :

[myLayer]
type=WMSLayer
url=http://geomsp.msp.gouv.qc.ca/cgi-wms/orthos?
extent_type=loose
levels=5
layers=Orthophotos
extension=gif
srs=EPSG:32198
metaTile=true
metaBuffer=30
metaSize=10,10
maxResolution=18 
bbox=-204608,323000,-200000,327608

[myLayer]

Le nom du layer est en premier lieu placé entre crochet et ce sera le nom du répertoire ou sera stocké les images.

type

Bien qu’il existe deux types de layer, on peut se concentrer uniquement sur le WMSLayer. L’autre type de layer(MapServerLayer) demande l’utilisation du du Python mapScript et n’est pas traité ici.

resolution

La résolution et le bbox(qui suit) sont les éléments déterminant pour l’utilisation d’un layer avec TileCache. Si on s’en tient à la base, il faut voir TileCache comme une pyramide inversée. À petite échelle on a une tuille qui montre la couverture complète d’un layer et inversement à grande échelle. Pour chacun des niveaux de zoom, on doit déterminer une échelle de cartographie ou une résolution qu’on veut supporter. Donc si on spécifie dans les paramètres de configuration de TileCache qu’un layer aura 15 niveaux( levels=15), alors on devra calculer 15 niveaux de résolution pour cartographier le layer en fonction de son étendu. On terme simple, la résolution sera l'échelle de chacun de ces niveaux.

Dans TileCache les tuiles 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(1 pouce = 25,4 millimètres) = 6.773333333 cm ou 0.06773333333m. 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. Source. Partant de cet énoncé, on pourrait illustrer que par exemple, si je détermine que le niveau 15 sera 1/5000 et que la couverture complète du layer s’affiche bien a 1/15000000, on aurait donc les résolutions suivante :

Level 15 = (0.06773333333m X 5000)/256 = 338.66666665
Level 14 = 0.06773333333m X 10000 = 677.3333333
Level 13 = 0.06773333333m X 15000 = 1015.99999995
Level 12 = 0.06773333333m X 20000 = 1354.6666666
Level 11 = 0.06773333333m X 25000 = 1693.33333325
Level 10 = 0.06773333333m X 30000 = 2031.9999999
Level 9 = 0.06773333333m X 35000 = 2370.66666655
Level 8 = 0.06773333333m X 50000 = 3386.6666665
Level 7 = 0.06773333333m X 200000 = 13546.666666
Level 6 = 0.06773333333m X 700000 = 47413.333331
Level 5 = 0.06773333333m X 2000000 = 135466.66666
Level 4 = 0.06773333333m X 6000000 = 406399.99998
Level 3 = 0.06773333333m X 9000000 = 609599.99997
Level 2 = 0.06773333333m X 12000000 = 812799.99996
Level 1 = 0.06773333333m X 15000000 = 1015999.99995

Et dans le fichier de configuration de tilecache on l’exprimerait ainsi

resolutions=1015999.99995,812799.99996,609599.99997,406399.99998,135466.66666,47413.333331,13546.666666,3386.6666665,2370.66666655,2031.9999999,1693.33333325,1354.6666666,1015.99999995,677.3333333,338.66666665

bbox

Le bbox est aussi très important dans la définition de la résolution, et il vient en quelque sorte simplifier un peut beaucoup les calcules de résolution. On conviendra que pour tuiller la couverture d’un layer, on doit en connaître son étendu. Parce que c’est toujours plus simple de travailler avec des nombres entiers, on a simplement à ajuster le périmètre de l’étendu du layer en fonction du 256 pixels de l’image. Pour ce faire on a qu’a ajuster le delta de la couverture de notre layer à chacun des axes pour égaler un nombre entier :

DX = ( 204608-200000 ) / 256 = 18
DY = ( 327608-323000 ) / 256 = 18

Bbox = -204608,323000,-200000,327608

Ici 18 pixel par mètre sera la résolution maximum de mon layer et sera cartographié dans le Tilecache par une seule image. Les résolutions suivantes seront simplement divisées par 2 pour ne pas déborder dans l’étendu du layer.

maxResolution

Il est possible de ne spécifier QUE la plus petite résolution et laisser TileCache calculer les résolutions suivantes qui seront a chaque niveau de zoom, divisées par 2.

maxResolution=18 

extension

Toujours pratique d’utiliser le format gif pour générer les images de Tilecache parce qu'elles ont une plus petite taille, mais il faut s’assurer que les gif générées par le service WMS supporte la transparence si le cache n’est pas un carte de base. Si on utilise mapserver, on doit écraser la spécification par défaut du driver GIF par ceci dans le mapfile du service.

OUTPUTFORMAT
        NAME "gif"
        DRIVER "GD/GIF"
        MIMETYPE "image/gif"
        IMAGEMODE PC256
        EXTENSION "gif"
        TRANSPARENT ON
END

metatile, metaBuffer et metaSize

Parce que TileCache découpe la carte en millier de tuiles et que chacune d’elle est construite par une requête WMS, on doit prévoir éviter les dédoublements dans les labels sur la carte. Comme par exemple, sur cette image voir le nom de rivière en double et en triple. Pour ce faire, il est préférable d’utiliser l’option « metaTile ». Cette option utilise le « Python Imaging Library »(PIL) et permet de générer un plus grande image par le service WMS qui est ensuite découpée en tuiles.

En fait, il faut utiliser cette option pour ne pas avoir de mauvaise surprise après avoir générer plusieurs milliers d’images… après quelques jours... Il suffit d’installer ce module(PIL) sur le serveur et de spécifier dans le fichier tilecache.cfg ceci :

metaTile=true

Par contre, cette librairie ne supporter pas les images avec INTERLACE. Si on utilise mapserver, on doit le spécifier dans le format de sortie du PNG si on l’utilise. Dans le GIF il ny a pas d’INTERLACE.

OUTPUTFORMAT
	. . . 	
	FORMATOPTION          "INTERLACE=OFF"
	FORMATOPTION          "TRANSPARENT=ON"
	. . . 
END

Il est possible d'ajouter une option sur le nombre de tuiles à générer et aussi un buffer. Avec l’utilisation de plus grand image a tuiler, c’est plus rapide pour produire le tilecache avec le seed. On remarquera que pour générer le cache, le CPU sera plus sollicité… Plus de python et moins de Mapserver…

metaBuffer=30
metaSize=10,10

Si on utilise Mapserver comme WMS, il serait bon de permettre à Mapserver de produire de plus grand image en taille(KB). Parce que les images demandées au WMS seront plus grandes, il faut augmenter la taille maximal des images de sorties. Par défaut, cette option est a 1024 KB. Donc dans le tag "MAP" du mapfile, on peut ajouter ceci

...
MAXSIZE 5120
...

autres options

voir le fichier README de TileCache...

Produire un caching

La ligne de commande pour générer le cache par une simple ligne de commande. On a besoin de spécifier l’url, le nom du layer(du tilecache,cfg), les niveau de zoom à générer, et le bbox(du tilecache,cfg)

E:\ms4w\apps\tilecache\tilecache_seed.py "http://spssoww5d.sso.msp.gouv.qc.ca /apps/tilecache/tilecache.cgi?" orthophotos 0 4 "-204608,323000,-200000,327608"

Utiliser des serveurs virtuels

Pour augmenter encore plus la vitesse de téléchargement des images, (et si vous êtes en mesure de convaincre votre administrateur réseau:-( , vous pouvez inscrire dans le serveur DNS plusieurs adresses qui pointes sur le même serveur. Cette astuce est drôlement intéressantes et pas mal performente... Ensuite avec OpenLayers on peut identifier toutes les adresses du serveur pour un layers... les images seront téléchargées en cascade via Javascript... comme Google!

var urlArray = ["http://g1.geomsp.msp.gouv.qc.ca/tilecach/",
                "http://g2.geomsp.msp.gouv.qc.ca/tilecach/",
                "http://g3.geomsp.msp.gouv.qc.ca/tilecach/",
                "http://g4.geomsp.msp.gouv.qc.ca/tilecach/",
                "http://g5.geomsp.msp.gouv.qc.ca/tilecach/"]; 
var l_boost = new OpenLayers.Layer.TileCache( "Carte de Base MSP multiURL", urlArray ,"base_msp_tile",{format: 'image/gif', maxResolution: 5060 }); 


Tester TileCache avec OpenLayers

Pour tester votre TileCache simplement placer ce fichier dans un répertoire OpenLayers exposé sur le Web et l'éditer pour votre besoin. L'exemple montre les 4 façons de visualiser la même carte, mais pas avec la même rapidité.

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <link rel="stylesheet" href="../theme/default/style.css" type="text/css" />
    <style type="text/css">
        #map {
            width: 512px;
            height: 512px;
            border: 1px solid black;
        }
    </style>
    <script src="./lib/OpenLayers.js"></script>
    <script type="text/javascript">
        //valeur permettant de zoomer a ces coord. et
        //au niveau de zoom 1
        var lat = 986800; 
        var lon = 1420000;
        var zoom = 1;
        
        //La fonction init() est exécutée au chargement de la page
        function init(){
            
            //Cette instruction permet de corriger un bug irrégulier dans OpenLayers.  Parfois, certaine tuiles ne sont pas chargées
            OpenLayers.IMAGE_RELOAD_ATTEMPTS = 3;

            //Par défaut, les images qui ne sont pas disponibles sont en rose nanane ... donc ici on peut les avoir en transparent ... c plus mieux comme ca!
            OpenLayers.Util.onImageLoadErrorColor = "transparent";

            //ici un layer en Mode TileCache
            var l1 = new OpenLayers.Layer.TileCache( "Carte de Base MSP", "http://geomsp.msp.gouv.qc.ca/tilecach/","base_msp_tile",
                                                {format: 'image/gif', maxResolution: 4440 }); 

            //Autre exemple en TileCache MAIS avec multiple URL
            var urlArray = ["http://g1.geomsp.msp.gouv.qc.ca/tilecach/",
                           "http://g2.geomsp.msp.gouv.qc.ca/tilecach/",
                           "http://g3.geomsp.msp.gouv.qc.ca/tilecach/",
                           "http://g4.geomsp.msp.gouv.qc.ca/tilecach/",
                           "http://g5.geomsp.msp.gouv.qc.ca/tilecach/"]; 
            var l_boost = new OpenLayers.Layer.TileCache( "Carte de Base MSP multiURL", urlArray ,"base_msp_tile",{format: 'image/gif', maxResolution: 5060 }); 

            //Ici le même layer en format WMS, tuilé... Une tuile, une requête WMS ... c pas rapide...
            var l2 = new OpenLayers.Layer.WMS( "Carte de base MSP sans Tilecache",
                            "http://geomsp.msp.gouv.qc.ca/cgi-wms/base_msp?", {layers: 'base_msp', isBaseLayer: true} );   

            //Aussi on peut montrer un layer WMS pas tuilé... c la forme plus traditionnelles des viewers Web
            var l3 = new OpenLayers.Layer.WMS( "BDGA WMS sans tuile",
                            "http://geomsp.msp.gouv.qc.ca/cgi-wms/base_msp?", {layers: 'base_msp', isBaseLayer: true, singleTile: true, ratio: 1.5,transparent: true, format: "image/png" } );                                                                


            //Dans cette exemple on présente une carte en projection Lamber Québec
            var options={    maxExtent: new OpenLayers.Bounds(-1124890,-23500 ,1124890, 2249780),
                            //maxResolution: 5060,
                            numZoomLevels: 10,
                            projection: "EPSG:32198",
                            units: 'm',
                            maxResolution: 'auto',
                            controls: [new OpenLayers.Control.MouseDefaults()] 
                            };
            
            //on va créer la carte et ajouter les layers
            var map = new OpenLayers.Map( 'map',options);
            map.addLayers([l1,l2,l3,l_boost]);
            
            //et ensuite simplement ajouter des contrôles
            map.addControl(new OpenLayers.Control.PanZoomBar());
            map.addControl(new OpenLayers.Control.MousePosition());
            map.addControl(new OpenLayers.Control.LayerSwitcher());

            //enfin centrer la carte... et l'affaire est ketchup!
            map.setCenter(new OpenLayers.LonLat(lon, lat), zoom);
        }
    </script>
  </head>
  <body onload="init()">
    <div id="map"></div>
  </body>
</html>