Tuesday 3 June 2014

[Solved] Easiest way to Draw Route on Bing Map in Windows Store Application




INTRODUCTION



Hi everybody, 

Today I am going to show you the easiest way to draw route between two location points using Bing Maps Route API. It might be little bit lengthy for you but I am pretty sure that you will feel easy to implement it. 

But before starting let me explain the things which you need to have with you.

1- Visual Studio 2012 or later. (2013 Recommended)
2- Bing Map SDK for Windows 8 or Windows 8.1 

If you don't have download it from given link below

For Windows 8 Visual Studio 2012

For Windows 8.1 Visual Studio 2013
  

3- Bing Map Key (Credential Key)

To access Bing Map you need to create a Bing Map Credential Key. If you already have its good but if you don't have then click the given link below, login to Bing portal with your Microsoft, Hotmail or Outlook account and generate credential key by putting some information they required. 

Note: Don't tell your credential key to anybody as it is important to keep it private. 

If you have all above mentioned things you are easily able to implement Bing Maps in your windows store application. 

Now lets move toward implementing. 

1- Run the Bing Map SDK installer by doing double click on it. 
2- It will take couple of seconds to install. 
3- After installation restart your visual studio if it is already running otherwise run visual studio 2013.
4- Create new windows store (Blank App) Project and name it. 
5- In Solution Explorer right click to reference and add 

1- "Bing Maps for C#, C++ or Visual Basic"  
2- "Microsoft Visual C++ 2013 Runtime Package for windows" 

references as shown in picture below. 























6- After adding you will see a yellow warning sign on both references in solution explorer as shown in picture below. 




















7- Don't worry it is just due to addition of Visual C++ Runtime reference because some reference only allows to debug or build solution only for one architecture, either it is ARM, x86 or x64. 

So to eliminate this warning change platform from "AnyCPU" to "x86" from Build Configuration Manager and see references after closing it as shown in picture below.





















So we have added references successfully. 

8- Now open MainPage.xaml and add Map Control from toolbox and name it "map" or "myMap".





Note: The controls in Bing Map SDK will be automatically added in toolbox. So you can use them directly as explained. 

9- In above picture you see that I have left blank space at right side. It is just to add some additional controls like button to perform actions. So add button from tool box set its content to "Draw Route" and name to "drawroute" 
and create its "Click Event"

10- Now copy your Bing Map Credential Key as its the time to provide it to Bing Map control. 

So open MainPage.xaml.cs and paste the code below in its constructor

// Replace your key with it. 

map.Credentials = "<Your-Bing-Map-Key>";

Now your constructor will look like this.

 public MainPage()
 {
   
     this.InitializeComponent();

     // Replace your key with it.

     map.Credentials = "samplekeyforblog123123123";


 }

11- Build the solution and run it. You will see maps with a button on right side. 

12- Now its time to use Bing Map Route API to draw route between two points. Below is the given link of Bing Map Restful API which takes the latitude,longitude of both locations and credential key as parameter and return data in form of XML or JSON at end point. 

http://dev.virtualearth.net/REST/V1/Routes?wp.0=latitude1,longitude1&wp.1=latitude2,longitude2&key=Your_Bing_Maps_Key

13 - Now we have send request to above URL using HttpClient and get response from it.

So for that purpose I am going to create a method or function in which I will write code and at the end will call it on Button Click Event which we have created already. It is your choice to make function or not. 


First to make request we need points of two different locations so I am taking points of two different location in New York 

Paste the code given below in your MainPage.xaml.cs class and resolve HttpClient object by right clicking on it. 


string point1 = "40.782946,-73.965369";
string point2 = "40.727586,-73.992433";


public async void TraceRoute()
{

   try
   {
        string reqURL = "http://dev.virtualearth.net/REST/V1/Routes?wp.0=" + point1   + "&wp.1=" + point2 +"&key=Your_Bing_Maps_Key";


        HttpClient client = new HttpClient( );

        HttpResponseMessage response = await client.GetAsync(reqURL);

        var jsonResponse = await response.Content.ReadAsStringAsync( );
   }
   catch(Exception ex) 
   {
        Debug.WriteLine(ex.ToString());
   }
  
   finally
   {


   }


}



Now we need to add JSON parser to parse the JSON in response. You can use any parser but I would suggest you to use Newtonsoft JSON library. 

So open Nuget Package manager by right clicking on project in solution explorer and selecting Manage Nuget Packages... 

Select JSON and install it. You will see reference of Netwonsoft.Json will be added to reference automatically. as show in picture below



Now you can parse JSON using Parser but we need classes of C# against the classes of JSON so we can convert them and store them in C# classes.

So instead of writing code for classes manually we will use JSON to C# classes generator. Below is the link of online generator. 

http://www.json2csharp.com 

Just paste the link with proper parameters and click generate as shown in picture below. 


 As I already told you that credential key is private so I have erased it using blue ink. So enter the proper link and click generate. It will generate classes of C# with respect to JSON classes coming in response. But it will be uneditable .

So here is the picture of generated classes. 



Now click copy button and you will see that you will be able to copy all code. 








Now add new class named "RootObject.cs" by right clicking on project in solution explorer and add new class. 

After creating class paste all the code in it.

Now your RootObject Class will look like the code below. 


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BingMapRouteSample
{
    public class ActualEnd
    {
        public string type { get; set; }
        public List<double> coordinates { get; set; }
    }

    public class ActualStart
    {
        public string type { get; set; }
        public List<double> coordinates { get; set; }
    }

    public class Detail
    {
        public int compassDegrees { get; set; }
        public List<int> endPathIndices { get; set; }
        public List<string> locationCodes { get; set; }
        public string maneuverType { get; set; }
        public string mode { get; set; }
        public List<string> names { get; set; }
        public string roadType { get; set; }
        public List<int> startPathIndices { get; set; }
    }

    public class Instruction
    {
        public object formattedText { get; set; }
        public string maneuverType { get; set; }
        public string text { get; set; }
    }

    public class ManeuverPoint
    {
        public string type { get; set; }
        public List<double> coordinates { get; set; }
    }

    public class Warning
    {
        public string origin { get; set; }
        public string severity { get; set; }
        public string text { get; set; }
        public string to { get; set; }
        public string warningType { get; set; }
    }

    public class Hint
    {
        public object hintType { get; set; }
        public string text { get; set; }
    }

    public class ItineraryItem
    {
        public string compassDirection { get; set; }
        public List<Detail> details { get; set; }
        public string exit { get; set; }
        public string iconType { get; set; }
        public Instruction instruction { get; set; }
        public ManeuverPoint maneuverPoint { get; set; }
        public string sideOfStreet { get; set; }
        public string tollZone { get; set; }
        public string towardsRoadName { get; set; }
        public string transitTerminus { get; set; }
        public double travelDistance { get; set; }
        public int travelDuration { get; set; }
        public string travelMode { get; set; }
        public List<string> signs { get; set; }
        public List<Warning> warnings { get; set; }
        public List<Hint> hints { get; set; }
    }

    public class EndWaypoint
    {
        public string type { get; set; }
        public List<double> coordinates { get; set; }
        public string description { get; set; }
        public bool isVia { get; set; }
        public string locationIdentifier { get; set; }
        public int routePathIndex { get; set; }
    }

    public class StartWaypoint
    {
        public string type { get; set; }
        public List<double> coordinates { get; set; }
        public string description { get; set; }
        public bool isVia { get; set; }
        public string locationIdentifier { get; set; }
        public int routePathIndex { get; set; }
    }

    public class RouteSubLeg
    {
        public EndWaypoint endWaypoint { get; set; }
        public StartWaypoint startWaypoint { get; set; }
        public double travelDistance { get; set; }
        public int travelDuration { get; set; }
    }

    public class RouteLeg
    {
        public ActualEnd actualEnd { get; set; }
        public ActualStart actualStart { get; set; }
        public List<object> alternateVias { get; set; }
        public int cost { get; set; }
        public string description { get; set; }
        public List<ItineraryItem> itineraryItems { get; set; }
        public string routeRegion { get; set; }
        public List<RouteSubLeg> routeSubLegs { get; set; }
        public double travelDistance { get; set; }
        public int travelDuration { get; set; }
    }

    public class Resource
    {
        public string __type { get; set; }
        public List<double> bbox { get; set; }
        public string id { get; set; }
        public string distanceUnit { get; set; }
        public string durationUnit { get; set; }
        public List<RouteLeg> routeLegs { get; set; }
        public double travelDistance { get; set; }
        public int travelDuration { get; set; }
        public int travelDurationTraffic { get; set; }
    }

    public class ResourceSet
    {
        public int estimatedTotal { get; set; }
        public List<Resource> resources { get; set; }
    }

    public class RootObject
    {
        public string authenticationResultCode { get; set; }
        public string brandLogoUri { get; set; }
        public string copyright { get; set; }
        public List<ResourceSet> resourceSets { get; set; }
        public int statusCode { get; set; }
        public string statusDescription { get; set; }
        public string traceId { get; set; }
    }

}





















So now your RootObject Class is ready to get data coming in the form of JSON from Bing Maps Route API.

Now come again in MainPage.xaml.cs and after this line declare and Initialize the List of ResourceSet  and ItineraryItem Class present in RootObject.cs before the constructor of MainPage

List<ResourceSet> resourceSet = new List<ResourceSet>( );

List<ItineraryItem> items = new List<ItineraryItem>( );
       
Declare List of Location Class which will hold the location points 

List<Location> loc = new List<Location>( );

Reslove "Location" it by right clicking on it. 

Declare the Object or Resource class

Resource resource;

Now come to TraceRoute Method/Function and paste given code below 

// Parsing JSON Response


 var rootObject = JsonConvert.DeserializeObject<RootObject>(jsonResponse);


 foreach (ResourceSet set in rootObject.resourceSets)
 {
        resourceSet.Add(set);

                
 }

loc.Clear();
            
resource = resourceSet[0].resources[0];
            
items = resource.routeLegs[0].itineraryItems;
            
// Colleting location points to draw route got in response. 

 foreach(ItineraryItem item in items)
            
 {

     loc.Add(new Location() { Latitude = item.maneuverPoint.coordinates[0],        Longitude = item.maneuverPoint.coordinates[1] });
                
            
 }

// Declaring Object of MapPolyline to Draw Route

            MapPolyline line;
            line = new MapPolyline();

// Defining color to Polyline that is Red you can give any color to it. 


            line.Color = Colors.Red;

// Defining width of Polyline so it can easily be visible to naked eye. 
            
            line.Width = 5;

// Giving Collection of location points to Map Polyline     

            foreach(Location l in loc)

            {
                line.Locations.Add(l);
            }
            
// Defining Map Shape layer Object to add Polyline shape to it. 

            MapShapeLayer shapeLayer = new MapShapeLayer();

// Adding line to Shape Layer 

            shapeLayer.Shapes.Add(line);

// Adding Shape Layer to Map

            map.ShapeLayers.Add(shapeLayer);

// Calculating Mid between both location to set center of Map
            int mid;
            
            if(loc.Count%2==0)
            {
                mid = loc.Count / 2;
            }
            else
            {
                mid = (loc.Count + 1) / 2; 
            }

            map.Center = loc[mid];

            map.ZoomLevel = 14;

//------------------------------------------------------------------------------------------------------

Now your MainPage.xaml Class will look like this.  

using Bing.Maps;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238

namespace BingMapRouteSample
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {

        List<ResourceSet> resourceSet = new List<ResourceSet>();
        Resource resource;
        List<ItineraryItem> items = new List<ItineraryItem>();
        List<Location> loc = new List<Location>();
        public MainPage()
        {
            this.InitializeComponent();
            map.Credentials = "Your_Bing_Maps_Key";
            progress.Visibility = Visibility.Collapsed;
            
        }

        string point1 = "40.782946,-73.965369";
        string point2 = "40.727586,-73.992433";
       

        public async void TraceRoute()
        {
            try
            {

           
            string reqURL = "http://dev.virtualearth.net/REST/V1/Routes?wp.0=" + point1 + "&wp.1=" + point2 + "&key=Your_Bing_Maps_Key";


            HttpClient client = new HttpClient();

            HttpResponseMessage response = await client.GetAsync(reqURL);

            var jsonResponse = await response.Content.ReadAsStringAsync();

            // Parsing JSON Response

            var rootObject = JsonConvert.DeserializeObject<RootObject>(jsonResponse);


            foreach (ResourceSet set in rootObject.resourceSets)
           {
                   resourceSet.Add(set);

                
           }

            loc.Clear();

            resource = resourceSet[0].resources[0];

            items = resource.routeLegs[0].itineraryItems;

            // Colleting location points to draw route got in response. 

            foreach (ItineraryItem item in items)
            {

                loc.Add(new Location() { Latitude = item.maneuverPoint.coordinates[0], Longitude = item.maneuverPoint.coordinates[1] });


            }

            // Declaring Object of MapPolyline to Draw Route

            MapPolyline line;
            line = new MapPolyline();

            // Defining color to Polyline that is Red you can give any color to it. 


            line.Color = Colors.Red;

            // Defining width of Polyline so it can easily be visible to naked eye. 

            line.Width = 5;

            // Giving Collection of location points to Map Polyline     

            foreach (Location l in loc)
            {
                line.Locations.Add(l);
            }

            // Defining Map Shape layer Object to add Polyline shape to it. 

            MapShapeLayer shapeLayer = new MapShapeLayer();

            // Adding line to Shape Layer 

            shapeLayer.Shapes.Add(line);

            // Adding Shape Layer to Map

            map.ShapeLayers.Add(shapeLayer);

            // Calculating Mid between both location to set center of Map
            int mid;

            if (loc.Count % 2 == 0)
            {
                mid = loc.Count / 2;
            }
            else
            {
                mid = (loc.Count + 1) / 2;
            }

            map.Center = loc[mid];
            map.ZoomLevel = 14;


            }
            catch (Exception)
            {

                Debug.WriteLine(ex.ToString( ));
               
            }
            finally
            {

                drawroute.isEnabled = true;
                progress.Visibility = Visibility.Collapsed;

            }
        }


        private void drawroute_Click(object sender, RoutedEventArgs e)
        {

                drawroute.isEnabled = false;
                progress.Visibility = Visibility.Visible;

               TraceRoute( );

        }
    }
}

Now there is only one thing remaining. You need to add progress ring to check response (Its Optional) and call TraceRoute method/function in drawroute button click event.

Now rebuild the solution and run it. 

You will see the screen like this. 























Click the Draw Route button it will take couple of seconds and draw route between two location points which you we have assigned to it. 

The location points in this sample are of New York Central Park and Merchant House Museum respectively.

After getting response from ROUTE API you will see the result like this. 























So now you are done with drawing driving route path on Bing Maps from one location to another. 

There are many other things which can easily be done via Bing Map ROUTE API, Location API, and etc etc. 

Some of the key features are below 

1- You can easily put your current location by using GeoLocation Class.
2- You can easily add push pins to starting and ending points. 
3- You can easily find the alternative route if there is traffic on suggested route. 
4- You can easily find the distance and estimated time to reach between two location points.

All above mentioned features will be covered in depth from beginner to advance level in future.

If there is any query you can simply email me or write comment I will follow up with you. 

Download sample from here  

Thanks

BR, 
Mudassir






Windows Mobile Professional

No comments:

Post a Comment