Prash's Blog

How to use Routing Service in Virtual Earth / Bing May 3, 2010

Filed under: Bing — prazjain @ 8:19 pm
Tags: , , , ,

In my previous article on using Geocoding service in Virtual Earth I gave an introduction on how to geo code the address. See here.

In this article I will show how to use that geocoded data and calculate route information using Bing. In this article we would use the Bing Maps keys to authenticate rather than the client token that we used in last article as that if for staging environment. But if you are using the staging environment then I suggest that you use the staging url for the service wsdl and use the VEStagingToken webservice for authenticate (as shown in geocoding service article).

1) Add a service in your VS solution pointing to : http://dev.virtualearth.net/webservices/v1/routeservice/routeservice.svc?wsdl and name it VERouterServiceReference.

2) Create a class RouteFetcher which would hold code to get route information for the locations passed by you.

3) Brief description of what the code does : It uses the Bing Maps key for authentication. It creates a WayPoint object for every location passed by you and send it to the webservice for calculating the route. In the end returning a string representation of instructions for the multi leg journey.

PS : Does anyone know how to paste code without losing indenting ! I have a real bad time pasting my codes here.

/// <summary>
 /// Plans a route through the locations passed in argument in the order specified.
 /// </summary>
 /// <param name="locations">array of string location formatted as (latitude,longitude)</param>
 /// <returns></returns>
 public string Route(string[] locations)
 {
 try
 {
 string results = "";
 RouteRequest routeRequest = new RouteRequest();
 routeRequest.Credentials = new Credentials();
 //routeRequest.Credentials.Token = _clientToken;
 routeRequest.Credentials.ApplicationId = _key;

 Waypoint[] wayPoints = new Waypoint[locations.Length];

 int pointIndex = -1;
 foreach (string point in locations)
 {
 pointIndex++;
 wayPoints[pointIndex] = new Waypoint();
 string[] digits = point.Split(',');
 // ignore the location if the string is not correctly formatted
 if (digits.Length!=2) continue;
 wayPoints[pointIndex].Location = new Location() { Latitude = double.Parse(digits[0].Trim()), Longitude = double.Parse(digits[1].Trim()) };
 if (pointIndex == 0)
 wayPoints[pointIndex].Description = "Start";
 else if (pointIndex == locations.Length)
 wayPoints[pointIndex].Description = "End";
 else
 wayPoints[pointIndex].Description = string.Format("Stop #{0}", pointIndex);

 }

 routeRequest.Waypoints = wayPoints;

 RouteServiceClient routeServiceClient = new RouteServiceClient();
 RouteResponse routeResponse = routeServiceClient.CalculateRoute(routeRequest);

 StringBuilder directions = new StringBuilder("");
 if (routeResponse.Result.Legs.Length > 0)
 {
 int instructionIndex = 0;
 int legIndex = 0;
 foreach (var leg in routeResponse.Result.Legs)
 {
 directions.Append(string.Format("Leg #{0}\n", ++legIndex));
 foreach (var itineraryItem in leg.Itinerary)
 {
 directions.Append(string.Format("{0}. {1}\n", ++instructionIndex, itineraryItem.Text));
 }
 Regex regex = new Regex("<[a-z/:]*>",RegexOptions.IgnoreCase);
 results = regex.Replace(directions.ToString(),string.Empty);
 }
 }
 else
 results = "No routes found";

 return results;

 }
 catch (Exception ex)
 {
 Console.WriteLine(ex.Message);
 return "Exception occurred";
 }

 }
Advertisements
 

Using Virtual Earth / Bing Geocoding Webservice July 24, 2009

Filed under: Bing — prazjain @ 4:10 pm
Tags: , , , ,

Me being new in London, I took it upon myself to find pubs close to me. I created a database with location of pubs, now I had to do display them on map to find their proximity. As I just had the address of these pubs and not their geographic coordinates, I needed to convert address to geographic coordinates. And then I can use them on any of the various mapping platforms to display location on map.

I wrote a tool which would enrich the existing database of pubs with their respective geocodes. I am giving an overview of what / how I went ahead with doing that:

  1. Get a windows live id, if you do not already have one. You can get one here : https://accountservices.passport.net
  2. Get a license for using the Geocoding Webservice. You would need to register for Bing Maps Developer account. You can sign up here : https://mappoint-css.live.com/mwssignup/
  3. Now, I am assuming you already have a Visual Studio solution and project created where you are going to use this functionality, add a reference to this web service :

    https://staging.common.virtualearth.net/find-30/common.asmx, use this as URL for service and name it as ‘VEStagingToken’.

  4. Create a class GeoCodeFetcher that would hold all the logic for interacting with geocoding webservices.
  5. In your project create a reference to webservice VEGeocodingService pointing to this url: http://staging.dev.virtualearth.net/webservices/v1/geocodeservice/geocodeservice.svc?wsdl

PS : Bing limits you 30,000 transactions per day in the free developer account, which should be enough for any sample developer application. [Confirmed through offical sources and true as of July 2009]

For the rest, I have written commented code for your reading, this should be fairly self-explanatory.

Note: I could have refactored AddressToGeocode method a little bit to reduce the number of if/else conditions, but the aim of this post is to be make it more understandable for any new programmer who is using this service for the first time.

This Code sample is in C#, you can as well port this code to Java with minor syntax changes.


///<summary>
/// Responsible for getting geocodes for a pub address. This class also holds logic
///for connecting to databases and saving data back to databases.
///</summary>
public class GeoCodeFetcher
{
#region [ Private Variables ]
///<summary>
/// Token that is to be sent everytime a GeocodeService call is made to VE to get geocodes for
/// a pub address.
///</summary>
private string _clientToken;

#endregion

#region [ Constructors ]
///<summary>
/// Gets a token from VE webserice for making Geocode service calls.
///</summary>

public GeoCodeFetcher()
{
string veAccountId = "VEAccountId";
string veAccountPwd = "VEAccountPwd";
// create the token once for all calls
CreateToken(veAccountId, veAccountPwd);
}

#endregion

#region [ Private Methods ]

///<summary>
/// Get a token for invoking VE services with max validity of 60 mins.
///</summary>
///<param></param>
///<param></param>
private void CreateToken(string username, string pwd)
{

CommonService commonService = new CommonService();
commonService.Url = "https://staging.common.virtualearth.net/find-30/common.asmx";
commonService.Credentials = new System.Net.NetworkCredential(username, pwd);
// create token specification
TokenSpecification tokenSpec = new TokenSpecification();
// some ip, this is used for tracking by VE services. Ideally should be IP of machine that is
// making service calls. But it would not fail the call if its any valid ip.
// putting in some value as the service call should not fail because of this

tokenSpec.ClientIPAddress = "x.x.x.x";
tokenSpec.TokenValidityDurationMinutes = 60; // 8 hrs is max limit.
_clientToken = commonService.GetClientToken(tokenSpec);

}

#endregion

#region [ Public Methods ]
///<summary>
/// This gets the address as argument and returns the latitude and longitude geocode for it.
///</summary>
///<param></param>
///<param></param>
///<param></param>
public void AddressToGeocode(string address, out decimal latitude, out decimal longitude)
{
string results = string.Empty;
// create a geocode request
GeocodeRequest geocodeRequest = new GeocodeRequest();
//Set the token received from VE service as credential token
geocodeRequest.Credentials = new VEGeocodingService.Credentials();
geocodeRequest.Credentials.Token = _clientToken;
// set the address as query
geocodeRequest.Query = address;
// we want only the top result so min confidence is high

ConfidenceFilter[] filters = new ConfidenceFilter[1];

filters[0] = new ConfidenceFilter();
filters[0].MinimumConfidence = VEGeocodingService.Confidence.High;
//set the geocode options
GeocodeOptions geocodeOptions = new GeocodeOptions();
geocodeOptions.Filters = filters;
geocodeRequest.Options = geocodeOptions;
GeocodeServiceClient geocodeServiceClient = new GeocodeServiceClient();
GeocodeResponse geocodeResponse = geocodeServiceClient.Geocode(geocodeRequest);

// if more than one result available then take the top result
if (geocodeResponse.Results.Length > 0)
{
latitude = (decimal)geocodeResponse.Results[0].Locations[0].Latitude;
longitude = (decimal)geocodeResponse.Results[0].Locations[0].Longitude;
}
else
{
// try search with medium confidence
filters[0].MinimumConfidence = VEGeocodingService.Confidence.Medium;
GeocodeResponse gcrMedium = geocodeServiceClient.Geocode(geocodeRequest);
 if (gcrMedium.Results.Length > 0)
{
latitude = (decimal)gcrMedium.Results[0].Locations[0].Latitude;
longitude = (decimal)gcrMedium.Results[0].Locations[0].Longitude;
}
else
{
filters[0].MinimumConfidence = VEGeocodingService.Confidence.Low;
GeocodeResponse gcrLow = geocodeServiceClient.Geocode(geocodeRequest);
if (gcrLow.Results.Length > 0)
{
latitude = (decimal)gcrLow.Results[0].Locations[0].Latitude;
longitude = (decimal)gcrLow.Results[0].Locations[0].Longitude;
}
 else
{
// throw an exception that geocodes could not be found for this pub
throw new Exception();
}
}
}
}
#endregion
}

These are all the helper methods you would need to actually interact with the services, and use them in your code whereever you need to geocode data.

Check the article on how to use the geocoded values to calculate route from point A to point B and more. How to use Routing Service.