How to Convert Tile Coordinates

In addition to referencing tiles by quadkey, Bing Maps also refers to tiles by x, y, and z coordinates. This is the way you reference tiles when overriding the GetUri() method of the Silverlight Microsoft.Maps.MapControl.TileSource class, for example, and the x, y, z properties of a tile are passed to the uriConstructor function specified in the options for an AJAX v7 Microsoft.Maps.TileSource.

In the x, y, z tile identification system:

  • z is the zoom level of the grid
  • x and y are the column and row number at which this tile should be placed, measured from an origin at the top left of the map.

Thus, at zoom level 1, you can describe the four tiles required to make a complete Bing Map using x, y, z coordinates as follows:

image

Bing Maps is not entirely unusual in this respect – this exact same referencing system is used by Google Maps, Open Street Maps, ESRI, and many others. You’d therefore be forgiven for thinking that it was some sort of standard.

In fact, this tile numbering sounds a lot like (and is often incorrectly described as) a  TMS index. The Tile Map Service (TMS) Specification defined by the Open Source Geospatial Foundation is a standard for serving map tiles that, like the system described above, places tiles on a grid and refers to their position using x, y, and z coordinates, where z is the zoom level, and x and y refer to column and row positions. However, according to the TMS specifications, “The x-coordinate of the tile numbers increases with the x-coordinate of the spatial reference system, and the y-coordinate of the tile numbers also increases with the y-coordinate of the spatial reference system.”. In other words, tile (0, 0), at any zoom level should always be placed at the bottom left of the map, not the top left.

Using the TMS system, the tile indexes at zoom level 1 become as follows:

image

The problem is that, since these systems are identical in almost every other respect, people tend to assume that the system used by Google/Bing/OSM et al. is the standard and systems that output tiles using it sometimes mistakenly refer to it as the TMS format. Then,  every now and again, you come across a piece of software or service that genuinely outputs tiles numbered according to the TMS standard and, if you don’t correct the tile origin, your tiles all end upside-down on the wrong side of the world :(

Fortunately, it’s a very simple correction to make. At any given map zoom level, zoom, you can invert the y index of a tile from TMS to Google/Bing as follows:

[php]
var ymax = 1 << zoom;
var y = ymax – y – 1;

[/php]

Assuming that you have a set of TMS tiles stored in a subdirectory structure that follows the pattern /z/y/x.png (as described in the Tile Resources section of the OSGeo TMS standard), then here’s a full example showing how to add a tilelayer of TMS tiles to Bing Maps v7:

[php]
<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
<script type="text/javascript">
var map = null;
function GetMap() {
// Create a basic map
map = new Microsoft.Maps.Map(document.getElementById("mapDiv"),
{ credentials: "ENTERYOURBINGMAPSKEY",
center: new Microsoft.Maps.Location(52.6, 1.26),
zoom: 12
});

// Create the tile source
var tileSource = new Microsoft.Maps.TileSource({ uriConstructor: getTMSTilePath });

// Construct the layer using the tile source
var tilelayer = new Microsoft.Maps.TileLayer({ mercator: tileSource, opacity: 1 });

// Push the tile layer to the map
map.entities.push(tilelayer);
}

function getTMSTilePath(tile) {

var x = tile.x;
var z = tile.levelOfDetail;
// Invert tile y origin from top to bottom of map
var ymax = 1 << z;
var y = ymax – tile.y – 1;

return location.href.substring(0, location.href.lastIndexOf(‘/’)) + "/" + z + "/" + x + "/" + y + ".png";
}
</script>
</head>
<body onload="GetMap();">
<div id=’mapDiv’ style="position:relative; width:1024px; height:768px;"></div>
</body>
</html>

[/php]

As a final note, just to add to the confusion, the Web Map Tile Service (WMTS) recently published by the OGC provides an alternative standard to TMS, but, like Google/Bing, uses an origin at the top-left hand corner.