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.

The Changes in Bing Maps

 

Microsoft have made some changes to the look and feel of the http://www.bing.com.maps site. So, it’s out with the old:

image

And in with the new:

image

The compass and zoom buttons are now overlaid as buttons on the map image rather than being in the toolbar header, and have been placed on the right hand side and made more prominent.

The breadcrumb trail has also been moved onto the map display itself, with a prominent target icon (displaying “World” in the screenshot above).

The streetside guy is still in the header although still doesn’t do anything yet (not if you’re in Europe, anyway).

However, the most interesting change for me is that the map styles themselves have been split into two separate dropdown categories – “road style” maps (Road, Ordnance Survey, Collins Bartholomew) and “aerial style” maps (Birds’ eye, Aerial). What’s more, the “show angled view” checkbox is gone, and the aerial map styles have reverted to their old names of aerial (for the top down imagery) and bird’s eye (for the oblique imagery).

This I think is a major improvement, and one which I hope feeds through into the Bing Maps AJAX v7 control soon. The problems with the old naming used on bing.com/maps (and still used the API) are many:

Firstly, there is terminology – when users say “birdseye” what they mean is the oblique, low level photographic imagery. They don’t say “birdseye angled” and “birdseye not angled” to refer to top down aerial imagery. This makes it hard to establish exactly what mode is being referred to.

Then, there are legal issues. In Microsoft’s own terms of use, there are specific restrictions placed on the use of “bird’s eye imagery” – http://www.microsoft.com/maps/product/terms.html – but what they really mean is “birdseye angled view” (i.e. true birdseye), not what you get when you just click the “birdseye” button, which gives you aerial view unless you checked the angled view button.

There are also technical differences – you can’t display custom tile layers over birdseye angled views, whereas you can display them over birdseye non-angled views (i.e. aerial) for example.

Birdseye and Aerial are two different map styles so it’s good to see they are being treated, and named as such on bing.com (as they always used to be!). So, when are these changes coming to the AJAX API?

OGR2OGR Importing Spatial Data to SQL Server

A few months back, I posted an article explaining how to import spatial data into SQL Server 2008 from any format supported by the OGR library (including ESRI shapefiles, GML, and TIGER data), using OGR2OGR. That article was written using OGR2OGR from v1.7 of the GDAL 1.7 library, which doesn’t support SQL Server 2008 directly, so I instead used OGR2OGR to create a CSV file containing spatial data in Well-Known Text format and then parsed that data in SQL Server using the STGeomFromText() method.

The good news is that things have become a bit easier since then, and version 1.8 of the GDAL library now has a MSSQLSpatial driver that can interface directly with geometry and geography data in SQL Server 2008.

The bad news is that most of the places that offer pre-compiled GDAL binaries for Windows have yet to update to the new version. FWTools, for example, still comes packaged only with v1.7. Likewise, the osgeo download site at http://download.osgeo.org/gdal/win32/ also lists GDAL versions up to v1.7.

So, if you want to get hold of the latest GDAL to import directly into SQL Server you’ll have to build it yourself from source, which can be downloaded from http://download.osgeo.org/gdal/gdal180.zip

Fortunately, the source has been very considerately packaged, and includes solution files that will build GDAL out-of-the-box in VS2005, 2008, and 2010. Simply load the .sln file, click build, and wait a few minutes:

Building GDAL 1.8 in VS2010

Then, if you look in the output directory (warmerdabldbin, by default) you should see a lovely collection of utilities for working with spatial data – GDAL (for working with raster data), and OGR (for its vector sibling).

Here’s the output of calling ogr2ogr –formats, which retrieves the list of supported vector spatial formats – note the MSSQLSpatial format supported for both read/write:

image

Example usage to load a shapefile to SQL Server as follows:

[php]
ogr2ogr -overwrite -f MSSQLSpatial "MSSQL:server=.\MSSQLSERVER2008;database=spatial;trusted_connection=yes" "TG20.shp"
[/php]