Routing
- 14 minutes to read
The Map control supports Microsoft’s Bing Route and Microsoft’s Azure Route services. These services provide the most optimal route, either from major roads in four directions, or calculated between two or more locations on a map.
Bing Maps Route
The Bing Route data provider provides the Map control’s routing functionality and is represented by the BingRouteDataProvider object. The sections below explain how to use the BingRouteDataProvider in the map control.
- Enable Routing
- Calculate a Route between Locations
- Calculate Routes from Major Roads
- Routing Result
- Examples
Important
Due to Bing canceled the SOAP service on July 30, 2017, the Map Control’s Bing Routing provider does not work properly in versions earlier than 16.1.
Enable Routing
Do the following to enable routing in the Map control:
Create an information layer and add it to the map.
The information provides vector elements that represent GIS data obtained from the Search service in the Map control. See Layers for more information.
- Create a BingRouteDataProvider instance and assign it to the InformationLayer.DataProvider property.
Specify the Bing Maps key using the BingMapDataProviderBase.BingKey property.
Note
Go to The Bing Maps Portal website to create a developer account.
Refer to How to: Get a Bing Maps Key to learn more about how to register a Bing Maps account and create a key for it.
The code snippet below shows how to do this.
private void Form1_Load(object sender, System.EventArgs e) {
// ...
BingRouteDataProvider routeDataProvider = new BingRouteDataProvider {
BingKey = yourBingKey
};
map.Layers.Add(new InformationLayer {
DataProvider = routeDataProvider
});
}
There are two ways to use the map routing feature in your application, depending on your task:
- Calculate a route between two or more locations on a map;
- Get a route from major roads to the specified destination.
The sections below describe each approach.
Calculate a Route between Locations
When the Map control is connected to the Bing Route service (see the section above for details), you can calculate a route between two or more locations on a map. To accomplish this, call the BingRouteDataProvider.CalculateRoute method and pass the list of locations (waypoints) as its argument, as shown below.
private void Form1_Load(object sender, System.EventArgs e) {
// ...
// Create three waypoints and add them to the route waypoints list.
List<RouteWaypoint> waypoints = new List<RouteWaypoint>();
waypoints.Add(new RouteWaypoint("NY", new GeoPoint(41.145556, -73.995)));
waypoints.Add(new RouteWaypoint("Oklahoma", new GeoPoint(36.131389, -95.937222)));
waypoints.Add(new RouteWaypoint("Las Vegas", new GeoPoint(36.175, -115.136389)));
// Call the BingRouteDataProvider.CalculateRoute method.
routeDataProvider.CalculateRoute(waypoints);
}
The image below shows the calculated route between the specified locations on the map.
Calculate Routes from Major Roads
The Map control allows you to obtain different routes to a specified location (latitude and longitude coordinates) using major roads from the north, east, south, and west. If it cannot find major roads coming from these directions, the response may contain more than one route from the same direction or fewer than four routes.
For instance, an application UI contains two text boxes named “tbLatitude” and “tbLongitude”, and a button named “calculateRoutes”.
To start a route calculation, click the Calculate Routes button. This calls the BingRouteDataProvider.CalculateRoutesFromMajorRoads method and a destination location (waypoint coordinates and description) and options are passed to its argument.
string description = "Route Waypoint";
double lat;
double lon;
private void bCalculateRoutes_Click(object sender, EventArgs e) {
RouteProvider.CalculateRoutesFromMajorRoads(
new RouteWaypoint( description, new GeoPoint(lat, lon) )
);
}
The results for San Francisco (Latitude - “37.783333” and Longitude - “-122.416667”) are shown in the image below.
Routing Result
The RouteCalculationResult object that is provided by the BingRouteDataProvider.RouteCalculated event handler arguments’ BingRouteCalculatedEventArgs.CalculationResult stores the route calculation results from the Bing Route service.
For instance, you can access a route path between locations calculated in the Calculate a Route between Locations section of this document.
To accomplish this, handle the BingRouteDataProvider.RouteCalculated event.
private void OnRouteCalculated(object sender, BingRouteCalculatedEventArgs e) {
RouteCalculationResult result = e.CalculationResult;
if((result.RouteResults == null) ||
(result.ResultCode == RequestResultCode.BadRequest)) {
rtbResults.Text = "The Bing Route service does not work for this location.";
return;
}
StringBuilder resultList = new StringBuilder("");
if(result.IntermediatePoints != null) {
resultList.Append(String.Format("_________________________\n"));
for(int i = 0; i < e.CalculationResult.IntermediatePoints.Count; i++)
resultList.Append(
String.Format("Starting point {0}: {1} ({2})\n",
i + 1,
e.CalculationResult.IntermediatePoints[i].Description,
e.CalculationResult.IntermediatePoints[i].Location)
);
}
if((result.RouteResults != null) & (result.ResultCode == RequestResultCode.Success)) {
for(int rnum = 0; rnum < e.CalculationResult.RouteResults.Count; rnum++) {
resultList.Append(String.Format("_________________________\n"));
resultList.Append(String.Format("Path {0}:\n", rnum + 1));
resultList.Append(String.Format(
"Distance: {0}\n",
e.CalculationResult.RouteResults[rnum].Distance
));
resultList.Append(String.Format(
"Time: {0}\n",
e.CalculationResult.RouteResults[0].Time
));
if(e.CalculationResult.RouteResults[rnum].Legs != null) {
int legNum = 1;
foreach(BingRouteLeg leg in e.CalculationResult.RouteResults[rnum].Legs) {
resultList.Append(String.Format("\tLeg {0}:\n", legNum++));
resultList.Append(String.Format("\tDistance: {0}\n", leg.Distance));
resultList.Append(String.Format("\tTime: {0}\n", leg.Time));
if(leg.Itinerary != null) {
foreach(BingItineraryItem itineraryItem in leg.Itinerary) {
resultList.Append(String.Format(itineraryItem.Maneuver + "\n"));
resultList.Append(String.Format(
"\t\tLocation: {0}\n",
itineraryItem.Location
));
}
}
}
}
}
}
rtbResults.Text = resultList.ToString();
}
The result is shown in the image below.
Azure Maps Route
The AzureRouteDataProvider
implements the Azure Maps Route service. Assign such an object to the InformationLayer.DataProvider property to enable the service and allow users to calculate a route on a map.
Note
To display an image on a map control, add image layers. Then you can implement routing functionality on the information layer.
Calculate a Route Between Locations
Call one of the AzureRouteDataProvider.CalculateRoute method overloads to calculate a route between the specified origin and destination, passing through the selected waypoints.
The AzureRouteOptions
parameter of the AzureRouteDataProvider.CalculateRoute method overload allows you to specify route options.
The following settings are available:
- AzureRouteOptions.TravelMode
- Specifies the transportation / commute mode.
- AzureRouteOptions.MaxAlternatives
- Specifies the number of alternative routes to be calculated.
- AzureRouteOptions.AvoidTypes
- Specifies items that
AzureRouteDataProvider
should try to avoid when calculating the route. - AzureRouteOptions.CustomParameters
- Specifies additional route definitions.
The following example calculates a car-optimized route through the specified waypoints:
using DevExpress.XtraMap;
// ...
const string key = "your key";
// ...
private void Form1_Load(object sender, EventArgs e) {
MapControl map = new MapControl();
// Specify the map position on the form.
map.Dock = DockStyle.Fill;
// Create a layer.
ImageLayer image = new ImageLayer();
image.DataProvider = new AzureMapDataProvider(){
AzureKey = key,
};
AzureRouteDataProvider routeProvider = new AzureRouteDataProvider();
routeProvider.AzureKey = key;
// Create three waypoints and add them to the route waypoints list.
List<RouteWaypoint> waypoints = new List<RouteWaypoint>();
waypoints.Add(new RouteWaypoint("NY", new GeoPoint(41.145556, -73.995)));
waypoints.Add(new RouteWaypoint("Oklahoma", new GeoPoint(36.131389, -95.937222)));
waypoints.Add(new RouteWaypoint("Las Vegas", new GeoPoint(36.175, -115.136389)));
// Call the AzureRouteDataProvider.CalculateRoute method.
azureRoute.CalculateRoute(waypoints, new AzureRouteOptions() {
TravelMode = AzureTravelMode.Car,
AvoidTypes = AzureRouteAvoidType.AlreadyUsedRoads
});
InformationLayer route = new InformationLayer();
route.DataProvider = routeProvider;
map.Layers.AddRange(new LayerBase[] { image, route});
this.Controls.Add(map);
}
Calculate Routes between GeoPoints Specified on a Map Surface
The following example calculates a route based on two or more RouteWaypoint
objects.
Right-click on a map surface to specify waypoints: origin, destination, and points between. ListBox
entries display geographical points (GeoPoint.Longitude
and GeoPoint.Latitude
). The “Calculate Route” button initiates the routing request by obtaining the waypoint information and passing it to the CalculateRoute
method. The ComboBoxEdit
and CheckedListBox
editors specify route options (AzureRouteOptions.AvoidTypes and AzureRouteOptions.TravelMode properties).
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using DevExpress.XtraMap;
namespace AzureRouting {
public partial class Form1 : Form {
const string azureKey = "your key";
ObservableCollection<GeoPoint> geoPoints = new ObservableCollection<GeoPoint>();
MapItemStorage itemData;
InformationLayer routeInfoLayer;
AzureRouteDataProvider azureRoute;
public Form1() {
InitializeComponent();
mapControl.Layers.AddRange(
new LayerBase[] {
new ImageLayer() {
DataProvider = new AzureMapDataProvider() {
AzureKey = azureKey,
Tileset = AzureTileset.Imagery,
},
},
new ImageLayer() {
DataProvider = new AzureMapDataProvider() {
AzureKey = azureKey,
Tileset = AzureTileset.BaseHybridRoad,
},
},
routeInfoLayer = new InformationLayer() {
DataProvider = azureRoute = new AzureRouteDataProvider() {
AzureKey = azureKey,
},
},
new VectorItemsLayer() {
Data = itemData = new MapItemStorage(),
}
}
);
routeInfoLayer.ItemStyle.StrokeWidth = 2;
routeInfoLayer.ItemStyle.Stroke = Color.DeepSkyBlue;
routeInfoLayer.Error += RouteInfoLayer_Error;
waypointsListBoxControl.DataSource = geoPoints;
mapControl.Zoom(6);
mapControl.SetCenterPoint(new GeoPoint(40.714627, -74.002863), false);
mapControl.EnableRotation = false;
}
private void RouteInfoLayer_Error(object sender, MapErrorEventArgs e) {
throw new System.NotImplementedException();
}
private void mapControl_Click(object sender, System.EventArgs e) {
MouseEventArgs mouseEventArgs = (MouseEventArgs)e;
if(mouseEventArgs.Button == MouseButtons.Right) {
GeoPoint mousePoint = mapControl.ScreenPointToCoordPoint(mouseEventArgs.Location) as GeoPoint;
geoPoints.Add(mousePoint);
itemData.Items.Add(new MapPushpin() {
Location = mousePoint,
});
}
}
private void calculateRouteButton_Click(object sender, System.EventArgs e) {
if (geoPoints.Count <= 1) {
MessageBox.Show("Specify at least two Waypoints to calculate a route.");
return;
}
azureRoute.CalculateRoute(geoPoints.Select(point => new RouteWaypoint("", point)).ToList(), new AzureRouteOptions() {
TravelMode = GetTravelMode(),
AvoidTypes = GetAvoidTypes()
});
geoPoints.Clear();
itemData.Items.Clear();
}
AzureTravelMode GetTravelMode() {
return (AzureTravelMode)Enum.Parse(typeof(AzureTravelMode), (string)travelModeComboBox.SelectedItem);
}
AzureRouteAvoidType GetAvoidTypes() {
var avoidTypes = AzureRouteAvoidType.None;
foreach (string item in avoidTypesCheckedListBox.CheckedItems) {
var avoidType = (AzureRouteAvoidType)Enum.Parse(typeof(AzureRouteAvoidType), item);
avoidTypes |= avoidType;
}
return avoidTypes;
}
}
}
Obtain Routing Result
The following example displays detailed information about the calculated route:
The button click initiates the routing request. The CalculateRoute
method is called in the button click event handler.
The RouteCalculated
event is handled to process the request result. e.CalculationResult
gets the AzureRouteCalculationResult object that contains the result of the route calculation and allow you to obtain the following information:
An AzureRouteCalculationResult.IntermediatePoints collection. You can obtain the Description and Location of each
RouteWaypoint
in the list.An AzureRouteCalculationResult.RouteResults collection. You can obtain summary information about the route, its legs and sections. For example, TravelLengthMeters, TravelTimeSeconds Arrival and Departure time.
using DevExpress.XtraMap;
using System.Text;
// ...
const string key = "your key";
// ...
routeProvider = new AzureRouteDataProvider { AzureKey = key };
routeProvider.RouteCalculated += OnRouteCalculated;
// ...
private void OnCalculateRoutesClick(object sender, EventArgs e) {
List<RouteWaypoint> waypoints = new List<RouteWaypoint>();
waypoints.Add(new RouteWaypoint("NY", new GeoPoint(41.145556, -73.995)));
waypoints.Add(new RouteWaypoint("Oklahoma", new GeoPoint(36.131389, -95.937222)));
waypoints.Add(new RouteWaypoint("Las Vegas", new GeoPoint(36.175, -115.136389)));
routeProvider.CalculateRoute(waypoints, new AzureRouteOptions() {
TravelMode = AzureTravelMode.Car
});
}
private void OnRouteCalculated(object sender, AzureRouteCalculatedEventArgs e) {
AzureRouteCalculationResult result = e.CalculationResult;
if ((result.RouteResults == null) ||
(result.ResultCode == RequestResultCode.BadRequest)) {
MessageBox.Show("The Azure Route service does not work for this location.");
return;
}
StringBuilder resultList = new StringBuilder("");
if (result.IntermediatePoints != null) {
resultList.Append(String.Format("_________________________\n"));
for (int i = 0; i < e.CalculationResult.IntermediatePoints.Count; i++)
resultList.Append(
String.Format("Waypoint {0}: {1} ({2})\n",
i + 1,
e.CalculationResult.IntermediatePoints[i].Description,
e.CalculationResult.IntermediatePoints[i].Location)
);
}
if (result.RouteResults != null) {
for (int rnum = 0; rnum < e.CalculationResult.RouteResults.Count; rnum++) {
var routeSummary = e.CalculationResult.RouteResults[rnum].Summary;
resultList.AppendLine("_________________________");
resultList.AppendLine($"Path {rnum + 1} summary:");
resultList.AppendLine($"Travel Distance: {GetDistanceString(routeSummary)}");
resultList.AppendLine($"Travel Time: {GetTravelTimeString(routeSummary)}");
if (e.CalculationResult.RouteResults[rnum].Legs != null){
int legNum = 1;
foreach (AzureRouteLeg leg in e.CalculationResult.RouteResults[rnum].Legs){
resultList.AppendLine($"\tLeg {legNum++}");
resultList.AppendLine($"\tDistance: {GetDistanceString(leg.Summary)}");
resultList.AppendLine($"\tTravel Time: {GetTravelTimeString(leg.Summary)}");
resultList.AppendLine($"\tDeparture Time: {leg.Summary.Departure}");
resultList.AppendLine($"\tArrival Time: {leg.Summary.Arrival}");
resultList.AppendLine($"\tDeviation Time: {leg.Summary.DeviationTime}");
}
}
}
}
MessageBox.Show(resultList.ToString());
}
static string GetTravelTimeString(AzureRouteSummary summary) {
var timeSpan = TimeSpan.FromSeconds(summary.TravelTimeSeconds);
return $"{timeSpan.Days}d, {timeSpan.Hours}hr, {timeSpan.Minutes}min";
}
static string GetDistanceString(AzureRouteSummary summary) {
return String.Format("{0:0.00}km", (double)summary.TravelLengthMeters / 1000);
}
Examples
The following examples demonstrate how to use the routing feature in the map control:
- How to: Calculate a Route between Waypoints Using the Bing Route Service
- How to: Calculate Routes from Major Roads Using the Bing Route Service
- How to: Calculate a Route by Addresses
- How to: Implement a Custom Route Provider
- How to: Use the Azure Maps Route Service to Calculate Routes between GeoPoints on a Map Surface