21 October 2010

Showing Open Source maps on Windows Phone 7 with the Bing Maps Control

My previous post, which caused a bit of a stirrup and got me over 1000 page hits on that one page alone in less than 46 hours, led to the question if I could provide an example of how to use data from Open Source map servers on the web in Bing Maps. This is more useful than Google Maps, since Google’s TOS most likely does not allow accessing their data they way I showed, and an application doing so violates section 3.1 of the Windows Phone 7 Application Certification Requirements, which clearly state that allowed content includes “Copyrighted content that is used with permission”, which I obviously do not have and most likely never will. Unless Google wants to code me a Windows Phone 7 app for them. Hello? Anyone reading along there at Mountain View? ;-)

So anyway, as long as my personal Google Maps for Windows Phone 7 is not going to hit the Marketplace, the Bing Maps MercatorMode can very well be used to show other tile maps, and by popular request I show you how to use data from Mapnik and Osmarender:

MapnikOsmarender

The possibility should come as no surprise, since I showed something like this earlier, only then with a plain ole’ MultiScaleImage. All you need to do is, once again, write a class again that descends from Microsoft.Phone.Controls.Maps.TileSource and overrides

Uri GetUri(int x, int y, int zoomLevel)

like I showed in my previous post. And these are even simpler than the Google Maps tilesource. First, Mapnik:

using System;

namespace LocalJoost.TileSource
{
  public class MapnikTileSource : Microsoft.Phone.Controls.Maps.TileSource
  {
    public MapnikTileSource()
    {
      UriFormat = "http://{0}.tile.openstreetmap.org/{1}/{2}/{3}.png";
      _rand = new Random();
    }

    private readonly Random _rand;
    private readonly static string[] TilePathPrefixes =
        new[] { "a", "b", "c" };

    private string Server
    {
      get
      {
        return TilePathPrefixes[_rand.Next(3)];
      }
    }
   
    public override Uri GetUri(int x, int y, int zoomLevel)
    {
      if (zoomLevel > 0)
      {
        var url = string.Format(UriFormat, Server, zoomLevel, x, y);
        return new Uri(url);
      }
      return null;
    }
  }
}

and second, Osmarender

using System;

namespace LocalJoost.TileSource
{
  public class OsmaRenderTileSource : Microsoft.Phone.Controls.Maps.TileSource
  {
    public OsmaRenderTileSource()
    {
      UriFormat = "http://{0}.tah.openstreetmap.org/Tiles/tile/{1}/{2}/{3}.png";
      _rand = new Random();
    }

    private readonly Random _rand;
    private readonly static string[] TilePathPrefixes =
        new[] { "a", "b", "c", "d", "e", "f" };

    private string Server
    {
      get
      {
        return TilePathPrefixes[_rand.Next(6)];
       }
    }

    public override Uri GetUri(int x, int y, int zoomLevel)
    {
      if (zoomLevel > 0)
      {
        var url = string.Format(UriFormat, Server, zoomLevel, x, y);
        return new Uri(url);
      }
      return null;
    }
  }
}

As you see, no rocket science. How to use this classes in XAML is explained in my previous post, and I am not going to repeat that here..

The odd thing is that the Bing Maps logo stays visible, although no Bing Maps data is being used. Notice that the open source maps are displayed in design mode too. So, use any tile server out there that you can legally access and have fun mapping…. although I must admit that is most likely interesting for hardcore GIS fans only, since both servers are considerably slower than Bing – especially OsmaRender, which does some odd things cutting the Netherlands in half, as you see. But still, if not anything else, it shows off the power and versatility of the Bing Maps control pretty well.

For the lazy people, a complete solution – including the Google stuff – can be downloaded here.

9 comments:

peSHIr said...

Tip: on the Bing Map control you can set the LogoVisibility property to System.Windows.Visibility.Collapsed to hide the Bing logo.

peSHIr said...

Thanks for the complete solutions BTW: I now have an OpenStreetMap based map viewer on my developer phone, where I can see my own edits. That is so cool!

Joost van Schaik said...

@peSHir I recalled settings LogoVisibility to Collapsed and seeing no result. I probably did something wrong there.

Unknown said...

Another useful feature would be the ability to use locally stored map tiles so that it can work offline.

Is that possible?

Joost van Schaik said...

@Tom Oh yeah. You could modify the tile source in a way that they would download tiles into isolated storage and show them from there next time. Trouble is, tiled maps tend to take HUGE amounts of storage

svenroed said...

Everything here works perfect, except that I really need to read from local storage and obviously GetUri of TileSource only accepts absolute uris. Any hint for me?

Joost van Schaik said...

@svenroed not yet. Is still on my list of 'things to research'. You have not been the first to ask this ;-)

altso said...

Is it legal to use google maps without api key? Is there any documentation on the url format? What parameters could be used and so on. I wasn't able to find anything on https://developers.google.com/

Joost van Schaik said...

@altso: as I explicitly state in my article, it is definitely notlegal. I am basically challenging Google to make a good Google Maps implementation for Windows Phone. They still haven't done that. Other people, including me, have done so. I would suggest you to have a look in either Deep Earth or SharpMap code to lift the code from there. There's more to lift from Google's data than I show. But of course I would not dare to encourage you to venture into illegal activities ;-)