Accessing a WMS Tile Server from Bing Maps Silverlight

In my previous post, I described how to add a tile layer from a WMS server using the Bing Maps v7 AJAX control. You can use a similar logic to add a WMS server as a tile source for the Silverlight control, with a few differences:

When using the Bing Maps AJAX control, the UriConstructor of the Microsoft.Maps.TileSource object uses a single {quadkey} argument to determine the tile image to be retrieved. (see http://msdn.microsoft.com/en-us/library/gg427599.aspx).

However, the equivalent GetUri() method of the Silverlight Microsoft.Maps.MapControl.TileSource object instead uses x, y, and zoomLevel parameters (http://msdn.microsoft.com/en-us/library/microsoft.maps.mapcontrol.tilesource.geturi.aspx).

Therefore, to convert from a Silverlight tile request to a WMS request, you can reuse much of the same logic as for the AJAX control, except omitting the intermediate step of calculating x, y, and zoom from the quadkey. The necessary conversion can be included directly in a tile source as follows:

public class WMSTileSource : Microsoft.Maps.MapControl.TileSource
 {
 public WMSTileSource()
 : base("http://wms1.ccgis.de/cgi-bin/mapserv?map=/data/umn/germany/germany.map&&VERSION=1.1.1&REQUEST=GetMap&SERVICE=WMS&SRS=EPSG%3A4326&BBOX={0}&WIDTH=256&HEIGHT=256&LAYERS=Bundeslaender")
 {}

 public override Uri GetUri(int x, int y, int zoomLevel)
 {
 return new Uri(String.Format(this.UriFormat, XYZoomToBBox(x, y, zoomLevel)));
 }

 public string XYZoomToBBox(int x, int y, int zoom)
 {
 int TILE_HEIGHT = 256, TILE_WIDTH = 256;
 // From the grid position and zoom, work out the min and max Latitude / Longitude values of this tile
 double W = (float)(x * TILE_WIDTH) * 360 / (float)(TILE_WIDTH * Math.Pow(2, zoom)) - 180;
 double N = (float)Math.Asin((Math.Exp((0.5 - (y * TILE_HEIGHT) / (TILE_HEIGHT) / Math.Pow(2, zoom)) * 4 * Math.PI) - 1) / (Math.Exp((0.5 - (y * TILE_HEIGHT) / 256 / Math.Pow(2, zoom)) * 4 * Math.PI) + 1)) * 180 / (float)Math.PI;
 double E = (float)((x + 1) * TILE_WIDTH) * 360 / (float)(TILE_WIDTH * Math.Pow(2, zoom)) - 180;
 double S = (float)Math.Asin((Math.Exp((0.5 - ((y + 1) * TILE_HEIGHT) / (TILE_HEIGHT) / Math.Pow(2, zoom)) * 4 * Math.PI) - 1) / (Math.Exp((0.5 - ((y + 1) * TILE_HEIGHT) / 256 / Math.Pow(2, zoom)) * 4 * Math.PI) + 1)) * 180 / (float)Math.PI;
 string[] bounds = new string[] { W.ToString(), S.ToString(), E.ToString(), N.ToString() };
 // Return a comma-separated string of the bounding coordinates
 return string.Join(",", bounds);
 }
 }
  • the base of the class defines the url template for the WMS Server. I’m using a layer  that displays federal states of Germany. The {0} placeholder will be replaced with the bounding box coordinates calculated from the GetUri() method.
  • The XYZoomToBBox() method converts from Bing Maps’ native x, y, and zoom tile numbering to the W, S, E, N coordinates of a bounding box to be passed to the WMS server.
  • Since I’m doing this all within the .cs file itself, no intermediate handler is needed.

The tilelayer can be added to the map in the XAML declaration, as follows:

<m:Map x:Name="Map1" Grid.Row="1" Center="50,8" ZoomLevel="7" Mode="Aerial" CredentialsProvider="{StaticResource MyCredentials}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
 <m:Map.Children>
 <m:MapTileLayer>
 <m:MapTileLayer.TileSources>
 <local:WMSTileSource></local:WMSTileSource>
 </m:MapTileLayer.TileSources>
 </m:MapTileLayer>
 </m:Map.Children>
 </m:Map>

And here’s the resulting map:

image

This entry was posted in Bing Maps and tagged , , , . Bookmark the permalink.

18 Responses to Accessing a WMS Tile Server from Bing Maps Silverlight

  1. Pingback: Accessing a WMS Tile Server from Bing Maps v7 | Alastair Aitchison

  2. Ajish says:

    Great article. It helped me a lot. It I also posted the comment in bing map forum

  3. Hi,

    If you change the URL of the WMS base, do you have somehow to re-calculate the W,N,E,S parameters in the XYZoomToBBox() method?
    I try to put a different wms map (with URL=http://195.251.137.25:81/cgi-bin/mapserv.exe?map=C:/ms4w/apps/gmap/htdocs/gmap75_wms.map&VERSION=1.1.1&LAYERS=Drainage&REQUEST=GetMap&SERVICE=WMS&SRS=EPSG:3978&REQUEST=GetMap&BBOX={0}&WIDTH=256&HEIGHT=256) and I get nothing.
    If I put a ‘&FORMAT=image/png&’ parameter as well, all my map becomes white.

    Any idea please?

  4. Saso says:

    Hi,
    I have this base map from geoserver : base(“http://localhost:8080/geoserver/wms?service=WMS&version=1.1.0&request=GetMap&layers=ku:Kumanovo&styles=&bbox={0}&width=256&height=256&srs=EPSG:28421&format=image/png”)
    how to calculate diferent parametera in EPSG 28421

  5. Great article. I bypassed this one and went searching because my problem at hand involved a simple WMS served out by ArcGIS server. After reading your Bing Maps V7 link, it was clear to me that I had to ‘massage’ a bounding box output from WMS to look like a tiled service to be easily accepted by bing silverlight map control.

    How did you get to work in your XAML – on the object browser (VS 2010), i see declarations for TileSource. Appreciate your help.

    Thanks a lot for building all the ST functions – some of them are well thought of and well designed. I was very pleased by the MakeValid function that sorted out polygons and holes in a neat fashion.

    regards, Ravi.

  6. David says:

    I tried this solution and it works, however I notice that the location changes at different zoom level. It seems to be more correct when the map view is zoomed in. Is it because the conversion method is not accurate at higher zoom level?

    Regards

    • alastaira says:

      It should work fine irrespective of zoom level. Are you sure the WMS server you’re using is serving tiles in Web Mercator projection?

    • Pat says:

      David, this is happening when using EPSG:4326, which is an elliptical definition of the earth, while Bing, Google etc maps are using a Spherical definition of the earth.

      • David says:

        Hi Pat

        Sorry, didn’t quite understand that. My understanding is that both Bing and EPSG:4326 are based on WGS84. Isn’t WGS84 projection based on the assumption that Earth is an spheroid? My initial thought was that I didn’t need any conversion at all 🙂

        Thanks

      • alastaira says:

        David:- Spherical != Spheroidal.
        WGS84 uses an spheroid model. Bing/Google etc. project that model as if it where spherical.

      • Pat says:

        David, Bing/Google use a perfect, non flattened sphere. But the earth is not a perfect sphere, the radius on the equator is larger than going from the center of the earth to the north/south pole. WGS84 is flattened. See http://en.wikipedia.org/wiki/Figure_of_the_Earth for more information on various Ellipsoid definition, see the different values for Equatorial radius and Polar radius.

        Cheers,

        Pat

  7. David says:

    Hi Alastair, thanks for the quick reply. Sorry I’m not quite familiar with the subject, just started a Silverlight project using Bing maps.

    The WMS services that I used for testing are the followings:
    1. http://nowcoast.noaa.gov/wms/com.esri.wms.Esrimap/obs?service=wms&version=1.1.1&request=GetMap&format=png&BBOX={0}&SRS=EPSG:4326&width=256&height=256&transparent=true&Layers=RAS_RIDGE_NEXRAD”);
    2. http://wms.lizardtech.com/lizardtech/iserv/ows?service=wms&version=1.1.1&request=GetMap&format=png&BBOX={0}&SRS=EPSG:4326&width=256&height=256&transparent=true&Layers=Florida

    and curiously the WMS server you provided on this article for Germany doesn’t show up on my Bing map.
    Am I using the wrong projections?

    Thanks

  8. David says:

    Update: After going through other layers available from http://nowcoast.noaa.gov, I found out that layer placements for other items seems to be correct at different zoom levels, including World Lakes, Lakes, and US Cities. Maybe http://wms.lizardtech.com doesn’t provide correct layers?

    Cheers

  9. Danny says:

    Is there any other wms about weather that we can use for this class? Thanks.

Leave a comment