Deconstructing the map cache tiling scheme (Part II): Working with map caches programmatically

This post explains ways to access cached map service tiles programmatically. This is useful if you don’t have access to a Web ADF Map control but you still want to quickly retrieve map images for a certain area. Another reason to retrieve tiles programmatically is if you want to overlay them on other services, such as Google Maps…but that’s a topic for another post. Today we’ll be focusing on how to get a tile of interest.

Before you continue, you should be familiar with how the tiling scheme works. See the archived post Deconstructing the map cache tiling scheme (Part I) if you need a review.

There are lots of ways to retrieve tiles from an ArcGIS Server map cache. The way that you use is affected by several factors which are listed here. This post shows two of the fastest ways to retrieve tiles:

  1. Using a simple HTTP Get request to the virtual cache directory of the Web server
  2. Requesting a tile from the ArcGIS Server map service tile handler

First let’s look at an example of each URL.

Virtual cache directory

If the virtual directory is exposed, you can request a tile from the Web server via the public cache directory. Here’s an example of a URL for a tile retrieved from the virtual cache directory:

http://serverx.esri.com/arcgiscache/dgaerials/Layers/_alllayers/L00/R0000029f/C00000280.jpg

Let’s break this URL down.

  • http://serverx.esri.com/arcgiscache: Root URL of one of your virtual cache directories
  • dgaerials: Map service name
  • Layers: The name of the data frame of interest in the map service
  • _alllayers: All layers in the map. This is always the case for single fused caches, if you have a multi-layer cache it will correspond to the specific group layer that was cached in the multi-layer cache
  • L00: Level ID
  • R0000029f: Cache tile row in padded hexadecimal format
  • C00000280.jpg: Cache tile column in padded hexadecimal format

To programmatically discover the virtual cache directory you can call:

MapServer.GetVirtualCacheDirectory(defaultMapName,layerNumber);

Where defaultMapName is the data frame name and layerNumber is -1 for fused caches or the index of the layer of interest for multilayer caches.

Map service tile handler

If the virtual directory is not exposed, you can still request a tile from the web server, but in this case you need to use the map service tile handler. Here’s an example of a URL for a tile retrieved by the map service tile handler:

http://serverx.esri.com/arcgis/services/dgaerials/MapServer?mapName=Layers&format=JPEG&level=0&row=671&column=640

Here is the breakdown of this URL:

  • http://serverx.esri.com/arcgis/services/dgaerials/MapServer: URL to the map service of the cache
  • mapName=Layers: Map name of the cached map service
  • format=JPEG: Image type of the cache
  • level=0: Level ID
  • row=671: Cache tile row in decimal format
  • column=640: Cache tile column in decimal format

The SOAP API and cached tiles

The accompanying code example shows how to use the ArcGIS Server SOAP API to get information about a cache and create a URL to retrieve a specific tile. You don’t need any ESRI software installed to program with the SOAP API. You just need a running ArcGIS Server whose services are enabled for Web access. In Microsoft Visual Studio, you can add a Web reference to one of these services and access a number of methods.

If you’re not familiar with adding a Web reference to your project or working with SOAP, you should definitely read the ArcGIS SOAP API Overview. It also explains how the SOAP API uses proxy classes and value objects to expose GIS functionality through Web services. Some of the most important value objects to know about when working with cached map services in the SOAP API are:

  • TileCacheInfo: Contains spatial reference information, as well as the width and height of the tile in pixels.
  • LODInfo: Contains information about the resolution and scale for a level of detail in the cache. You can access an array of LODInfos from TileCacheInfo.
  • TileImageInfo: Contains information about the cache image format

Getting a tile

When using the SOAP API, you might be tempted to get a tile by calling MapServerProxy.GetMapTile( ). It’s actually faster to construct the URL and get the tile directly, as we show in the code example.

Finding the specific tile that covers your point of interest requires a little bit of math. These are some important things to know:

  • The tiling origin

    Remember that the tiling origin is the upper-left point of the tiling scheme grid. You can get it using TileCacheInfo.TileOrigin.

  • The width and height of a tile in ground units

    You can get this by multiplying the tile width (TileCacheInfo.TileCols) or height (TileCacheInfo.TileRows) by the resolution (LODInfo.Resolution)

  • The row and column of your point of interest on the tiling grid

    Columns are zero-based and increase as you move to the right from the tiling origin. Rows are also zero-based and increase as you move down from the tiling origin.

    For example, in the map below, if you were traveling from the tiling origin to Salt Lake City, you would have to move five tiles to the right and four tiles down. This puts Salt Lake City in Column 4, Row 3.

Tiling grid 

Here’s some math you can use to find any tile:

Column = Floor((Point of interest X – Tile origin X) / Ground width of a tile)

and

Row = Floor((Tile origin Y – Point of interest Y) / Ground height of a tile)

Example

This example application does the following things using the ArcGIS Server SOAP API:

  1. Connects to a map service and discovers whether it has a cache
  2. Computes the number of tiles needed to cover the map horizontally and vertically. This is useful if you have an empty tiling scheme and you want to find out how many tiles will need to be created as part of the caching process.
  3. Creates a URL to get the center tile directly from the virtual cache directory
  4. Creates a URL to get the center tile using the tile handler

See the example application

Download the code (See authors’ comments in Default.aspx.cs)

-Jeremy Bartley and Sterling Quinn

This entry was posted in Services and tagged , , , , . Bookmark the permalink.

Leave a Reply

3 Comments

  1. sterlingdq says:

    @Stephan- My understanding is that for the Mercator projection the scales would be accurate at the Equator only.

  2. sterlingdq says:

    @Chris- The workflow for updating tiles is to use the Update Map Server Cache tool. You can pass a rectangular extent to this tool, so if you knew the area in which the edits occurred, you could conceivably update the area of one tile. If you had to do this frequently it would not be efficient (the Update tool requires a restart of the service) and you might need to go with a non-cached service or call ExportMapImage which forces the map to be drawn dynamically.

  3. TomLUX says:

    I have problems getting the VirtualCache of an non-FUSED cached mapservice.

    I’m well detecting that the layer is cached, but I’m always getting an empty “getVirtualCacheDirectory”.

    See below.

    I’m using the java WebADF. Tested on versions 92 and 93rc1.

    Thanks,
    Tom

    boolean layerCache = mapServerPort.hasLayerCache(mapName, mapLayerInfo.getLayerID());
    String virtualPath = mapServerPort.getVirtualCacheDirectory(mapName, mapLayerInfo.getLayerID());

    This returns:
    layerCache = true;
    virtualpath = “”;