How To: Bing Maps Custom Tile Overlay - Google Maps
I got a question from a friend who wanted to replace Bing Maps Tiles with Google Maps Tiles.
You might ask yourself why? If you want Google Tiles just replace Bing Control and work with Google Maps….. In this case I want to work with Bing Map Control because the benefits I get in Metro Applications in Windows 8 for C#, C++, VB.NET and JavaScript.
And I also want Google Maps language support.
Download Demo Project
Currently Bing Maps doesn't support any language except English, and I want to display the map with the user natural language.
Google \ Bing Preview
| Google - Hebrew | Google - English | Bing – Only English |
 |  |  |
Before we jump to the solution let’s talk about the common ground between Bing and Google Maps.
- Each tile consists of 256 x 256 pixels
- Each succeeding zoom level divides the map into 4 N tiles, where N refers to the zoom level. For example:
- at zoom level 1,each map divides the world up into a 2x2 grid for a total of 4 tiles;
- at zoom level 2, each map divides up the world into a 4x4 grid for a total of 16 tiles, etc
- (From “Tile Coordinates” Google API) – Zoom Level 2 (4x4)
- (From “Tile Coordinates and Quadkeys” MSDN) – Zoom Level 3 (8x8)

I order to replace the tile we need to have Google map url that will return the specific tile based on the X, Y, and Zoom level – and we have it here:
Google Maps –> calling "https://mts0.google.com/vt/hl=he&src=api&x=2&s=&y=1&z=3” will return: (X = 2 , Y = 1 , Zoom = 3)

So what is the problem? The problem is that in order to replace Tiles in Bing Maps you need to pass the “QuadKey” value. - MapTileLayer Class
As you can see from the code example below the TileSource gets the url of the custom tile with a parameter called - {quadkey}
C#
MapTileLayer tileLayer = new MapTileLayer();
tileLayer.TileSource = "http://www.microsoft.com/maps/isdk/ajax/layers/lidar/{quadkey}.png";
map.TileLayers.Add(tileLayer);
JavaScript
function addTileOverlay() {
var options = { uriConstructor: "http://www.microsoft.com/maps/isdk/ajax/layers/lidar/{quadkey}.png"};
var tileSource = new Microsoft.Maps.TileSource(options);
var tilelayer = new Microsoft.Maps.TileLayer({ mercator: tileSource });
map.entities.push(tilelayer);
}
What is QuadKey? - A quadkey uniquely identifies single tiles at particular levels of detail
To optimize the indexing and storage of tiles, the two-dimensional tile XY coordinates are combined into one-dimensional strings called quadtree keys, or “quadkeys” for short. Each quadkey uniquely identifies a single tile at a particular level of detail, and it can be used as an key in common database B-tree indexes. To convert tile coordinates into a quadkey, the bits of the Y and X coordinates are interleaved, and the result is interpreted as a base-4 number (with leading zeros maintained) and converted into a string. For instance, given tile XY coordinates of (3, 5) at level 3, the quadkey is determined as follows:
- tileX = 3 = 011 2
- tileY = 5 = 101 2
- quadkey = 100111 2 = 213 4 = “213”
Quadkeys have several interesting properties. First, the length of a quadkey (the number of digits) equals the level of detail of the corresponding tile. Second, the quadkey of any tile starts with the quadkey of its parent tile (the containing tile at the previous level). As shown in the example below, tile 2 is the parent of tiles 20 through 23, and tile 13 is the parent of tiles 130 through 133:

So now that we understand what is QuadKey we understand that we need to translate this value into Google Map X,Y and Zoom, we can use the following method to convert the QuadKey into x,y and level values.
public static void QuadKeyToTileXY(string quadKey, out int tileX, out int tileY, out int levelOfDetail)
{
tileX = tileY = 0;
levelOfDetail = quadKey.Length;
for (int i = levelOfDetail; i > 0; i--)
{
int mask = 1 << (i - 1);
switch (quadKey[levelOfDetail - i])
{
case '0':
break;
case '1':
tileX |= mask;
break;
case '2':
tileY |= mask;
break;
case '3':
tileX |= mask;
tileY |= mask;
break;
default:
throw new ArgumentException("Invalid QuadKey digit sequence.");
}
}
}
But you don’t need to do that because the quadkey is automatically translated into those values, so instead of setting a static url for TileOverlay we will set a function called convert that received the quadkey object.
Solution:
function convert(quadkey) {
return "https://mts0.google.com/vt/hl=he&src=api&x=" + quadkey.x + "&s=&y=" + quadkey.y + "&z=" + quadkey.levelOfDetail;
}
function addTileOverlay() {
var options = { uriConstructor: convert };
var tileSource = new Microsoft.Maps.TileSource(options);
var tilelayer = new Microsoft.Maps.TileLayer({ mercator: tileSource });
map.entities.push(tilelayer);
}
Bing Map without Google Tiles:

Bing Maps with Google Tiles:

Download Demo Project