Load custom tiles in Bing maps on WPF

I am trying to use a custom tileset for Bing maps. What I am trying to do is similar to the question here, but I'm trying to understand how a URI is formatted so that I can host the tiles within the application. The reason I am trying to host this locally is because I want to limit network traffic out from my application as much as possible.

Are there any tutorials on hosting the map tiles locally or a more in depth tutorial on how to have the URI point to a local storage path?

Thanks in advance for any advice.

Answers


The central point in the Bing Maps (or Google Maps or OpenStreetMap) tiled map scheme is that each map tile is identified by three parameters. These are the zoom level (that typically ranges from 0 or 1 to about 20) and the x and y index of a tile within a zoom level. In a given zoom level z the x and y index range from 0 to 2^z-1. In zoom level 0 there is one tile, in level 1 there are 2x2 tile, in level 2 there are 4x4 tiles and so on.

Most map tile providers like OpenStreetMap or Google Maps directly reflect these three parameters in their tile URIs. OpenStreetMap for example provides map tiles by the URI http://tile.openstreetmap.org/z/x/y.png.

In a derived TileSource class you override the GetUri method to provide an URI for the three tile parameters. For OpenStreetMap alike tiles such a derived TileSource might look like this:

public class MyTileSource : Microsoft.Maps.MapControl.WPF.TileSource
{
    public override Uri GetUri(int x, int y, int zoomLevel)
    {
        return new Uri(UriFormat.
                       Replace("{x}", x.ToString()).
                       Replace("{y}", y.ToString()).
                       Replace("{z}", zoomLevel.ToString()));
    }
}

For some stupid technical detail in the Bing Maps WPF Control TileLayer class you would also have to derive your own TileLayer class to enable usage in XAML:

public class MyTileLayer : Microsoft.Maps.MapControl.WPF.MapTileLayer
{
    public MyTileLayer()
    {
        TileSource = new MyTileSource();
    }

    public string UriFormat
    {
        get { return TileSource.UriFormat; }
        set { TileSource.UriFormat = value; }
    }
}

You would then use it in the Map Control like below where the XAML namespace m references Microsoft.Maps.MapControl.WPF and local references the namespace that contains the derived TileLayer.

<m:Map>
    <m:Map.Mode>
        <!-- set empty map mode, i.e. remove default map layer -->
        <m:MercatorMode/>
    </m:Map.Mode>
    <local:MyTileLayer UriFormat="http://tile.openstreetmap.org/{z}/{x}/{y}.png"/>
</m:Map>

Instead of creating a http URI you might now also create an URI for a local file. You could for example organize the map tiles in a directory structure with a directory for the zoom level, a subdirectory for the x index and a file name for the y index. You could set the UriFormat property in a way that specifies a local path:

<local:MyTileLayer UriFormat="file:///C:/Tiles/{z}/{x}/{y}.png"/>

The overridden GetUri method might also directly create an appropriate local file URI, without using the UriFormat property:

public override Uri GetUri(int x, int y, int zoomLevel)
{
    string rootDir = ...
    string path = Path.Combine(rootDir, zoomLevel.ToString(), x.ToString(), y.ToString());
    return new Uri(path);
}

You may want to read more about how OpenStreetMap handles map tile names.


Need Your Help

What is a database closure?

sql database closures

I came across this term called database closure.