Using a custom tile provider with the XtraMap control

I saw this post a few weeks ago in the DevExpress Support Center inquiring about how to connect the XtraMap control to the Nokia HERE Maps system. Nokia’s HERE system provides geocoding, routing, and for our purposes, a map tile provider.

HERE Maps in an XtraMap control
HERE Maps in an XtraMap control

Out of the box, the XtraMap control can be paired with the OpenMaps and Bing Map providers. If these don’t suit your needs, you do have the ability to supply your own map provider by writing a little bit of code.

For our example, we’re going to connect to the HERE map provider. If you want to do your own testing–or use it in a production environment–you will want to sign up for a developer license. HERE maps allows for a limited free developer account, so go ahead and register for that for access to the mapping, geocoding and routing functionality.

As I’ve mentioned in a previous blog, the #1 request I see with regards to the XtraMap control is for the ability to connect it to Google Maps. The Google Maps terms of service does not allow for it to be used in a desktop environment. That being said, you could probably use a little bit of creativity and adapt the techniques shown here to achieve it…

Luckily for us, most of what we need to do really involves some boilerplate code. The best starting place is this example in the DevExpress Support Center: How to load image tiles from another source by creating custom data provider. This example illustrates using a local tile store but we can easily adapt it to fetch map tiles from HERE.

The first step is creating a class that derives from the MapDataProviderClass. We really don’t need to change anything from the example code except for some class/member names to suit our needs.

    sealed public class HereMapTileProvider : MapDataProviderBase
    {

        #region Private members

        /// <summary>
        /// Map project
        /// </summary>
        private readonly SphericalMercatorProjection _Projection = new SphericalMercatorProjection();

        #endregion

        #region Public accessors

        /// <summary>
        /// Gets the Projection for this tile provider
        /// </summary>
        public override ProjectionBase Projection
        {
            get { return _Projection; }
        }

        /// <summary>
        /// Returns a size struct representing the base size of this provider, in pixels
        /// </summary>
        protected override Size BaseSizeInPixels
        {
            get { return new Size(Convert.ToInt32(HereMapTileSource._TileSize * 2), Convert.ToInt32(HereMapTileSource._TileSize * 2)); }
        }

        #endregion


        /// <summary>
        /// Initializes a new instance of the HereMapTileProvider class
        /// </summary>
        public HereMapTileProvider()
        {
            TileSource = new HereMapTileSource(this);
        }


        /// <summary>
        /// Returns the pixel size of this map for the provided zoom level
        /// </summary>
        /// <param name="zoomLevel">Current zoom level</param>
        /// <returns></returns>
        public override MapSize GetMapSizeInPixels(double zoomLevel)
        {
            double imageSize;
            imageSize = HereMapTileSource.CalculateTotalImageSize(zoomLevel);
            
            return new MapSize(imageSize, imageSize);

        }   //End the GetMapSizeInPixels() method




    }   //End the HereMapTileProvider class

The important stuff is in our tile source class, which must derive from the MapTileSourceBase class. Again, we can keep most everything standard with regards to the DevExpress example. The only real work we have to do is in the GetTileByZoomLevel method. This method is responsible for taking the map’s current position and zoom level and translating that into a tile source location from the provider. Internally, the MapControl will make a request to to that tile source, get the tiles and render them on the map.

The HERE tile api gives us the following prototype for a tile request:

http://{1-4}.base.maps.cit.api.here.com/maptile/2.1/maptile/{map id}/{scheme}/{zoom}/{column}/{row}/{size}/{format}
?app_id=DemoAppId01082013GAL
&app_code=AJKnXv84fjrb0KIHawS0Tg
&{param}={value}

We’ll fill in some of those parameters with values from the XtraMap control and others will be static values from the api documentation. You’re free to play around with the different options for  the {scheme} or {format} parameters, or even modify the Url to show a satellite or terrain view. For our purposes, I’ve implemented the GetTileByZoomLevel in the following manner:

/// <summary>
/// Returns a Uri used to fetch tiles for the provided zoom level and co-ordinates
/// </summary>
/// <param name="zoomLevel">Current zoom level</param>
/// <param name="tilePositionX">Current tile x co-ordinate</param>
/// <param name="tilePositionY">Current tile y co-ordinate</param>
/// <returns></returns>
public override Uri GetTileByZoomLevel(int zoomLevel, int tilePositionX, int tilePositionY)
{

    string Url = String.Format(@"http://1.base.maps.api.here.com/maptile/2.1/maptile/newest/normal.day/{0}/{1}/{2}/256/png?app_id={3}&app_code={4}",
                zoomLevel,              //{0}                            
                tilePositionX,          //{1}
                tilePositionY,          //{2}
                _ApplicationID,         //{3}
                _ApplicationCode);      //{4}

    if (zoomLevel <= _MaxZoomLevel)
        return new Uri(Url);
    else
        return null;

}   //End the GetTileByZoomLevel() method

And really, that’s all there is to it! Like I said above, the example provided by the DevExpress Support Center really does contain all of the boilerplate code you need to get started. Feel free to adapt that, or sign up for a HERE developer account, download the project I’ve built and modify it suit your own needs: CustomTileProvider.zip

Using a custom tile provider with the XtraMap control

2 thoughts on “Using a custom tile provider with the XtraMap control

  1. Another great post! Thanks again.
    I have a client that would prefer to use Google maps over Bing.
    They have purchased an enterprise API key to use google maps, but I cant see how to use it as a source of map info for devexpress map control.
    Seems to me that the actual issue is that Google Maps does not provide image tiles, whereas Bing does.
    Any ideas?

    Like

    1. It seems that the new version of Google Maps using WebGL doesn’t offer an easy way to find the map tiles. I’ve seen different web posts giving the Url format for Google map tiles, but I’ve also heard that they change the Url and tend to block IPs that are excessively accessing their system that way. Unfortunately Google seems to be hell-bent on preventing developers from directly accessing their map tile system. DevExpress used to have an example in their support center showing how to access Google maps with the XtraMap component, but this has since been removed.

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s