.. _tile_mode:

*****************************************************************************
 Tile Mode 
*****************************************************************************

:Author:        Paul Ramsey
:Contact:       pramsey at cleverelephant.ca
:Last Updated: 2008/04/30

.. contents:: Table of Contents
    :depth: 2
    :backlinks: top


Introduction
============

MapServer can feed tile-based map clients directly using the CGI
"tile mode".  Tile-based map clients work by dividing the map of the world up
into a discrete number of zoom levels, each partitioned into a number of 
identically sized "tiles".  Instead of accessing a map by requesting a 
bounding box, a tile client builds a map by accessing individual tiles.


Configuration
=============

Tile requests are handled by the 'mapserv' CGI program.  In order to 
return tiles in the correct projection, MapServer must be built with the 
--use-proj option turned on.  You can check if your version of 'mapserv' has 
projection support by running it with the '-v' option and looking 
for 'SUPPORTS=PROJ'.

Example 1. On Unix::

   $ ./mapserv -v
   MapServer version 4.6.1 OUTPUT=GIF OUTPUT=PNG OUTPUT=JPEG OUTPUT=WBMP OUTPUT=PDF
   OUTPUT=SWF OUTPUT=SVG SUPPORTS=PROJ SUPPORTS=FREETYPE SUPPORTS=WMS_SERVER 
   SUPPORTS=WMS_CLIENT SUPPORTS=WFS_SERVER SUPPORTS=WFS_CLIENT SUPPORTS=WCS_SERVER 
   INPUT=JPEG INPUT=POSTGIS INPUT=OGR INPUT=GDAL INPUT=SHAPEFILE DEBUG=MSDEBUG

Example 2. On Windows::

   C:\apache\cgi-bin> mapserv -v
   MapServer version 4.6.1 OUTPUT=GIF OUTPUT=PNG OUTPUT=JPEG OUTPUT=WBMP OUTPUT=PDF
   OUTPUT=SWF OUTPUT=SVG SUPPORTS=PROJ SUPPORTS=FREETYPE SUPPORTS=WMS_SERVER 
   SUPPORTS=WMS_CLIENT SUPPORTS=WFS_SERVER SUPPORTS=WFS_CLIENT SUPPORTS=WCS_SERVER 
   INPUT=JPEG INPUT=POSTGIS INPUT=OGR INPUT=GDAL INPUT=SHAPEFILE DEBUG=MSDEBUG
   
MapServer requires that each LAYER in your map file have a valid PROJECTION 
block to support reprojection.  Because the tile mode uses reprojection, 
you will have to ensure each LAYER has a valid PROJECTION block.

Configuration checklist:

 * MapServer compiled with PROJ support
 * Map file with a :ref:`PROJECTION` defined for every :ref:`LAYER`
 
As of MapServer 6.0, there are two extra parameters available for configuring tile mode. 

 * *tile_map_edge_buffer* renders the tile into a buffered rendering frame, then clips out the final tile. This will reduce edge effects when large symbols or wide lines are drawn. Recommended value: the size of the largest symbol or line width in your map file.
 * *tile_metatile_level* renders the tiles into a fixed metatile, then clips out the final tile. This will reduce label repetition, at the expense of much higher rendering cost.  Recommended value: 1 if you are doing labelling of large features in your layer. 0 otherwise.

If you use both *tile_map_edge_buffer* and *tile_metatile_level* at the same time, the buffer will be applied at the meta-tile level.

Utilization
===========

The MapServer tile support adds three new directives to the CGI interface:

* *mode=tile* tells the server to generate tiles based on the other tile mode
  parameters
* *tilemode=gmap* tells the server use the Google Maps tile 
  scheme for the tiles
* tile=x+y+z tells the server what tile you want to retrieve, using
  the Google Maps tile addressing system
* *tilemode=ve* tells the server use the Virtual Earth tile naming 
  scheme for the tiles
* tile=10231 tells the server what tile you want to retrieve, using
  the Virtual Earth tile addressing system
 
 
About Spherical Mercator
------------------------

:term:`Spherical Mercator` (also called "web mercator" by some) is a world projection. 
All the major tile-based map interfaces (Google Maps, Microsoft Virtual Earth, 
Yahoo Maps, OpenLayers) use the spherical mercator system to address tiles.

A spherical mercator set of tiles has the following properties:

 * The map has been reprojected to mercator using a spherical 
   mercator algorithm
 * There is one tile in the top zoom level, zoom level zero
 * Each successive zoom level (z) has 2^z tiles along each axis
 * Tiles are 256x256 in size
 
Google Maps and Virtual Earth both use spherical mercator as their underlying 
tile projection, but use different formats to address the individual tiles.

Google Maps uses an "x", "y", "zoom" format.  The zoom indicates which level 
to pull tiles from, and the "x" and "y" indicate while tile in that zoom 
level to pull.

Virtual Earth uses a single string to address each tile.  The top zoom level 
in Virtual Earth has four tiles (equivalent to Google's zoom level 1). The 
top left tile in the Virtual Earth top zoom level is addressed as "0", top 
right as "1", bottom left as "2" and bottom right as "3".  Each tile 
the next level is addressed by first referencing the top level tile that 
contains it, then its address relative to that tile.  So the top left tile 
in the second zoom level is "00" and the bottom right one is "33".  
See the Virtual Earth site for more details: http://msdn.microsoft.com/en-us/library/bb545006.aspx


Using Google Maps
-----------------

The `Google Maps API`_ includes support for using alternative tile sets 
as overlays, or as alternate base maps. Here is an example of an 
`GTileLayerOverlay`_

.. code-block:: guess
    :linenos:
    
    <!DOCTYPE html 
      PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
    <title>Google/MapServer Tile Example</title>
    <script src="http://maps.google.com/maps?file=api&v=2&key=[YOUR KEY HERE]"
            type="text/javascript"></script>
    <script type="text/javascript">

    function load() {
      if (GBrowserIsCompatible()) {
        var urlTemplate = 'http://localhost/cgi-bin/mapserv?';
            urlTemplate += 'map=/var/map.map&';
            urlTemplate += 'layers=layer1 layer2&';
            urlTemplate += 'mode=tile&';
            urlTemplate += 'tilemode=gmap&';
            urlTemplate += 'tile={X}+{Y}+{Z}';
        var myLayer = new GTileLayer(null,0,18,{                                      
                                     tileUrlTemplate:urlTemplate,
                                     isPng:true, 
                                     opacity:1.0 }); 
        var map = new GMap2(document.getElementById("map"));
        map.addControl(new GLargeMapControl());
        map.addControl(new GMapTypeControl());
        map.setCenter(new GLatLng(35.35, -80.55), 15); 
        map.addOverlay(new GTileLayerOverlay(myLayer)); 
      }
    }

    </script>
    </head>
    <body onload="load()" onunload="GUnload()">
      <div id="map" style="width: 500px; height: 500px"></div>
    </body>
    </html>

Note the format of the tileUrlTemplate: a valid URL, with {X}, {Y} and {Z} 
substitution tokens that Google Maps will replace with the tile coordinates 
and zoom level on the fly to retrieve tiles from your server.

You can also use a MapServer tile layer as an alternate base map:

.. code-block:: guess
    :linenos:

    <!DOCTYPE html 
      PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
    <title>Google/MapServer Tile Example</title>
    <script src="http://maps.google.com/maps?file=api&v=2&key=[YOUR KEY HERE]"
            type="text/javascript"></script>
    <script type="text/javascript">

    function load() {
      if (GBrowserIsCompatible()) {
        var urlTemplate = 'http://localhost/cgi-bin/mapserv?';
            urlTemplate += 'map=/var/map.map&';
            urlTemplate += 'layers=layer1 layer2&';
            urlTemplate += 'mode=tile&';
            urlTemplate += 'tilemode=gmap&';
            urlTemplate += 'tile={X}+{Y}+{Z}';
        var myLayer = new GTileLayer(null,0,18,{                                      
                                     tileUrlTemplate:urlTemplate,
                                     isPng:true, 
                                     opacity:0.3 }); 
        var map = new GMap2(document.getElementById("map"));
        map.addControl(new GLargeMapControl());
        map.addControl(new GMapTypeControl());
        map.setCenter(new GLatLng(35.35, -80.55), 15); 
        var myMapType = new GMapType([myLayer], new GMercatorProjection(18), 'MapServer');
        map.addMapType(myMapType); 
      }
    }

    </script>
    </head>
    <body onload="load()" onunload="GUnload()">
      <div id="map" style="width: 500px; height: 500px"></div>
    </body>
    </html>

The only change from the previous example is that we don't create a 
GTileLayerOverlay, we create a GMapType, and use addMapType(), instead of 
addOverlay().


Using Virtual Earth
-------------------

The `Virtual Earth API`_ also includes support for using alternative tile sets 
as overlays, or as alternate base maps. Here is an example:

.. code-block:: guess
    :linenos:
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
      <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
      <title>Virtual Earth Example</title>
      <script type="text/javascript" src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.1"></script>
      <script type="text/javascript">

        var map = null;

        function OnLoadMap () {
          map = new VEMap("myMap");
          map.LoadMap();

          var url = "http://localhost/cgi-bin/mapserv?";
          url += "map=/var/map.map&";
          url += "mode=tile&";
          url += "layers=layer1 layer2&";
          url += "tilemode=ve&";
          url += "tile=%4";

          var tileSourceSpec = new VETileSourceSpecification( "myLayer", url );
          tileSourceSpec.Opacity = 0.3;
          map.AddTileLayer(tileSourceSpec, true);
        }

      </script>
    </head>
    <body onload="OnLoadMap();">
      <div id="myMap" style="position:relative; width:500px; height:500px;"></div>
    </body>
    </html>



.. RST Link Section

.. _`GTileLayerOverlay`: http://code.google.com/apis/maps/documentation/reference.html#GTileLayer
.. _`Google Maps API`: http://code.google.com/apis/maps/
.. _`Virtual Earth API`: http://dev.live.com/virtualearth/sdk/
