Like Find Service, Route Service is one of the four core components of the MapPoint Web Service, allowing you to calculate routes, driving directions, and itineraries between places or addresses. In this chapter, we’ll take an in-depth look at the MapPoint Web Service Route APIs.
The Route Service end point is located at RouteService.asmx
, and the APIs available
for Route service are exposed via the RouteServiceSoap
class in the Web Service
proxy (Reference.cs or Reference.vb).
RouteServiceSoap
class
contains methods related to route functionality, namely CalculateRoute
and CalculateSimpleRoute
. Either of these two
methods can be used to calculate routes between places, addresses, or
latitude/longitude coordinates; however, there are some differences
that you need to be aware of when using these methods, which we will
get to later in this chapter. Table 7-1 shows the methods
offered by the RouteServiceSoap
class.
Method | Notes |
| Calculates and returns a route
( |
| Calculates and returns a route
( |
Before I get into the details of using the route-related methods, let’s look at how a route is represented in MapPoint Web Service APIs.
In MapPoint Web Service, a route is made up of two or more waypoints, each of which indicates a starting point, ending point, or stopping point along the route. Each waypoint is associated with a route segment, which connects two waypoints but contains information about only one of them. To understand this better, see Figure 7-1.
Figure 7-1 shows with five waypoints and five associated segments. The starting point (waypoint A) and other stopping points (waypoints B, C, and D) in this route are connected via four route segments (1, 2, 3, and 4); the last segment represents the finish point, waypoint E, with its own route segment, 5. In MapPoint Web Service APIs, each segment contains information about the beginning waypoint, the segment distance, and directions for the segment.
Next, let’s see how the route in Figure 7-1 morphs into programmatic types.
In MapPoint Web Service APIs, a valid route is always
represented by a Route
object. A
Route
object contains the
following instances:
A RouteItinerary
class
that represents the textual driving directions
A RouteSpecification
class that represents the specifications such as starting point,
ending point, stopping points, and driver’s profile
A CalculatedRouteRepresentation
class
that contains a cached version of the route for rendering
purposes
When a route is calculated using RouteServiceSoap
.
CalculateRoute
with an instance of the
RouteSpecification
class, both
RouteItinerary
and CalculatedRouteRepresentation
are returned
by default. However, you can change this behavior and mask the
unnecessary information depending on your needs using RouteResultMask
enumeration.
A valid RouteItinerary
object contains information about the route itinerary and map view
representations. The itinerary information is represented as an
array of Segment
objects. Each
Segment
object contains a
Waypoint
object that denotes the
starting point for that segment in the route, and an array of
Direction
objects that indicate
driving directions for the current segments. Each Direction
object contains detailed textual
driving directions, as well as other information such as bearing,
latitude/longitude of the directions’ starting point, and formatted
text instruction. Finally, each Waypoint
object contains the location
information for the starting point of the corresponding Segment
object.
A valid RouteSpecification
object defines a route in terms of a segment collection using an
array of SegmentSpecification
objects in conjunction with a DriverProfile
that sets the driving time
preferences. Each SegmentSpecification
object contains
specifications for an individual route segment by setting the
waypoint (the starting point for the segment) and other segment
preferences indicating what type of segment the current segment
needs to be—such as a shortest segment or a quickest segment. Table 7-2 shows the fields
exposed on the RouteSpecification
class.
Field | Notes |
| Name of the data source as a string. |
| The time to start and end driving
each day ( |
| Indicates, as a |
| The specification of each segment
that makes up the route as an array of |
Table 7-3 shows
the fields of the SegmentSpecification
object:
Field | Notes |
| The route preference and map view
options ( |
| The waypoint ( |
When you are calculating a route, a RouteSpecification
object is passed to the
RouteServiceSoap.CalculateRoute
,
and the resulting Route
object
automatically inherits these route specifications as an instance of
the RouteSpecification
object, so
you never actually assign a RouteSpecification
instance to a Route
object.
Finally, the CalculatedRouteRepresentation
object is a
cached representation of a calculated route; this object is useful
only in rendering a route on top of a map, so a valid instance of
this object contains an array of bytes that represents the
calculated route, which can later be used in rendering a map using
the MapPoint Web Service route service.
This discussion is summarized in Figure 7-2.
With this introduction, let’s look at how to create Route
objects using the RouteServiceSoap
APIs.
A valid route consists of a starting point and an ending
point; sometimes a route can also have one or more stops between its
starting and stopping points. To calculate a route, you need to have
at least two waypoints expressed in terms of LatLong
objects. Depending on how much
control you need in calculating a route, MapPoint Web Service offers two methods:
RouteServiceSoap.CalculateSimpleRoute
and
RouteServiceSoap.CalculateRoute
.
The RoutServiceSoap.CalculateSimpleRoute
method calculates a route using latitude/longitude coordinates. This
method uses an array of latitude/longitude coordinates, a map data
source name (such as MapPoint.NA
), and a SegmentPreference
enumeration to indicate
whether the route should be calculated using the SegmentPreference.Quickest
option
(yielding the route with minimal travel time) or the SegmentPreference.Shortest
option
(yielding the route with minimal travel distance). The following
example shows how to use the RouteServiceSoap.CalculateSimpleRoute
method with latitude/longitude pairs:
//Define waypoints LatLong[] latLongs = new LatLong[2]; //Seattle, WA latLongs[0] = new LatLong(); latLongs[0].Latitude = 47.6034; latLongs[0].Longitude = -122.3295; //Redmond, WA latLongs[1] = new LatLong(); latLongs[1].Latitude = 47.6785; latLongs[1].Longitude = -122.1308; //Now create a route service proxy RouteServiceSoap routeService = new RouteServiceSoap(); //Assign credentials routeService.Credentials = new System.Net.NetworkCredential(userid, password); //Calcuate Route Route route = routeService.CalculateSimpleRoute(latLongs, "MapPoint.NA", SegmentPreference.Quickest);
Keep in mind that if your route exceeds 50,000 kilometers, an
error is thrown, but you can pass a maximum of 50 latitude/longitude
pairs to this method. Despite this apparent flexibility, it does not
offer much control over the route service behavior, such as setting
the driving starting time and ending time, requesting only route
itinerary without a calculated route representation cache, and so
on. This method tends to be inefficient when you just want to
calculate route itinerary without returning a calculated route
representation; however, that’s exactly the level of control that
the RouteServiceSoap.CalculateRoute
method
offers.
The RouteServiceSoap.CalculateRoute
method
takes a valid RouteSpecification
object as an input parameter and returns a Route
object. The RouteSpecification
object allows you to
specify your route using Waypoint
objects and Segment
objects. One
of the advantages of this approach is better control over the route
calculation process; using a RouteSpecification
object, you can control
the segment level routing settings, such as shortest versus quickest
and driving times.
A Waypoint
object is a
wrapper around a location that is part of a route. To define a
Waypoint
object, you need to have
an associated latitude/longitude pair (or a LatLong
object). Once you have the
Waypoint
s outlined for a route,
you can assign them to Segment
objects to create an array of route segment specification. This
route segment specification array is used in calculating the route
when the RouteServiceSoap.CalculateRoute
method is
called.
The following example shows how to call this method using a
RouteSpecification
object:
//Now create a route service proxy RouteServiceSoap routeService = new RouteServiceSoap(); //Assign credentials routeService.Credentials = new System.Net.NetworkCredential(userid, password); //Now define RouteSpecifications //Define segments SegmentSpecification[] routeSegmentsSpec = new SegmentSpecification[3]; //Define start segment routeSegmentsSpec[0] = new SegmentSpecification(); routeSegmentsSpec[0].Waypoint = new Waypoint(); routeSegmentsSpec[0].Waypoint.Name = "Start"; //Seattle, WA routeSegmentsSpec[0].Waypoint.Location = new Location(); routeSegmentsSpec[0].Waypoint.Location.LatLong = new LatLong(); routeSegmentsSpec[0].Waypoint.Location.LatLong.Latitude = 47.6034; routeSegmentsSpec[0].Waypoint.Location.LatLong.Longitude = -122.3295; //Set this segment to be the quickest routeSegmentsSpec[0].Options = new SegmentOptions(); routeSegmentsSpec[0].Options.Preference = SegmentPreference.Quickest; //Define stop segment routeSegmentsSpec[1] = new SegmentSpecification(); routeSegmentsSpec[1].Waypoint = new Waypoint(); routeSegmentsSpec[1].Waypoint.Name = "Stop"; //Redmond, WA routeSegmentsSpec[1].Waypoint.Location = new Location(); routeSegmentsSpec[1].Waypoint.Location.LatLong = new LatLong(); routeSegmentsSpec[1].Waypoint.Location.LatLong.Latitude = 47.6785; routeSegmentsSpec[1].Waypoint.Location.LatLong.Longitude = -122.1308; //Set this segment to be the shortest routeSegmentsSpec[1].Options = new SegmentOptions(); routeSegmentsSpec[1].Options.Preference = SegmentPreference.Shortest; //Define to segment routeSegmentsSpec[2] = new SegmentSpecification(); routeSegmentsSpec[2].Waypoint = new Waypoint(); routeSegmentsSpec[2].Waypoint.Name = "Finish"; //Portland, OR routeSegmentsSpec[2].Waypoint.Location = new Location(); routeSegmentsSpec[2].Waypoint.Location.LatLong = new LatLong(); routeSegmentsSpec[2].Waypoint.Location.LatLong.Latitude = 45.5118; routeSegmentsSpec[2].Waypoint.Location.LatLong.Longitude = -122.6755; //Now create a Route Specification and assign segments //and data source to be used RouteSpecification routeSpec = new RouteSpecification(); routeSpec.DataSourceName = "MapPoint.NA"; routeSpec.Segments = routeSegmentsSpec; //Set the itinerary only mask routeSpec.ResultMask = RouteResultMask.Itinerary; //Calculate Route Route route = routeService.CalculateRoute(routeSpec);
In this example, I define three segments from Seattle, WA to
Portland, OR with a stop at Redmond, WA. The real advantage to using
the CalculateRoute
method can be
seen in how I set the segment preferences; I have set the first
segment of my route from Seattle to Redmond as the quickest
segment:
//Set this segment to be the quickest routeSegmentsSpec[0].Options = new SegmentOptions(); routeSegmentsSpec[0].Options.Preference = SegmentPreference.Quickest;
This guarantees that when my route is calculated, I get the directions that can take me from Seattle to Redmond in the minimal amount of time; then, I set the second segment as the shortest segment:
//Set this segment to be the shortest routeSegmentsSpec[1].Options = new SegmentOptions(); routeSegmentsSpec[1].Options.Preference = SegmentPreference.Shortest;
This setting guarantees that the route contains the directions
that travel the minimal distance to go from Redmond, WA to Portland,
OR. Finally, you can also reduce the SOAP payload by requesting the
“itinerary only” route object by setting the following RouteResultMask
to the RouteSpecification
object:
//Set the itinerary only mask routeSpec.ResultMask = RouteResultMask.Itinerary;
The CalculateRoute
method
provides considerably more control than the CalculateSimpleRoute
method; however, keep
in mind that only 50 waypoints are allowed with this method.
Finally, as with the CalculateSimpleRoute
method, if your route
exceeds 50,000 kilometers, an error is thrown.
Before we get into the details of getting the route
object information returned by the previously discussed methods,
there is one more setting you can set to the RouteSpecification
object to control the
driving times, the DriverProfile
object.
By default, MapPoint Web Service considers the valid driving
times in a day to be from 9:00 a.m. to 5:00 p.m. When you
calculate a route without setting any specific driver profile
settings, routes are calculated using these default times.
However, if you want to drive from 10:00 a.m. to 3:00 p.m., use
the DriverProfile
object.
To set specific starting and ending driving times in a day,
use the DriverProfile
object;
this object has two fields, DayStartTime
and DayEndTime
, using which you can set the
starting time and ending time in a day. These two values are
always expressed in minutes elapsed since the day has started at
12:00 a.m. (except for the default values of -1 and -1).
To set a DayStartTime
at
10:00 a.m., use the following code:
//Create a driver profile object DriverProfile driverProfile = new DriverProfile(); //Start driving every day at 10 AM in the morning driverProfile.DayStartTime = 10 * 60;
Similarly, you can set the DayEndTime
at 3:00 p.m. as
follows:
//End driving every day at 3 PM in the evening //3 PM = 12 + 3 = 15 hours since 12:00 AM driverProfile.DayEndTime = 15 * 60;
To set this DriverProfile
object to the RouteSpecification
object to put the new
driving day start and end times into effect while calculating your
route, use the following code:
//Assign Driver's profile routeSpec.DriverProfile = driverProfile;
Keep in mind that setting the driver’s profile with custom driving start and end times changes the total trip time as well as the driving directions accordingly.
Depending on where you are actually driving, sometimes it
makes sense to see the driving directions and distances in the
units that are used locally; for example in the United States, the
distance is measured in miles, while in the United Kingdom, the
distance is measured in kilometers. MapPoint Web Service allows
you to set your distance preference for route calculations via the
UserInfoRouteHeader
object.
This object is set to the RouteServiceSoap
instance before calling
the CalculateRoute
or CalculateSimpleRoute
methods:
//Create an instance of user info route header UserInfoRouteHeader routeHeader = new UserInfoRouteHeader(); //Set distance unit to Miles routeHeader.DefaultDistanceUnit = DistanceUnit.Mile; //Assign it to Route Service instance routeService.UserInfoRouteHeaderValue = routeHeader; //Calculate Route route = routeService.CalculateRoute(routeSpec);
Depending on what the default distance unit is set to, the route object contains the information about the total route distance and segment distance accordingly. The default distance unit always starts out as kilometers, and you need to change that if you want miles.
You can also use the UserInfoRouteHeader
object to obtain the
driving directions in any of the supported languages; to get
driving directions in French, use the following code:
//Create an instance of user info route header UserInfoRouteHeader routeHeader = new UserInfoRouteHeader(); //Create Culture Info routeHeader.Culture = new CultureInfo(); //And set it to French routeHeader.Culture.Name = "FR"; //Assign it to Route Service instance routeService.UserInfoRouteHeaderValue = routeHeader; //Calculate Route route = routeService.CalculateRoute(routeSpec);
This code results in driving directions in French. For a full list of languages supported by MapPoint Web Service, refer to Chapter 5.
Now that we have seen how to calculate a route with different options, it’s time to look at the itinerary details contained within a route.
A Route
object contains
several details about a calculated route, including the total driving
time, trip time, distance traveled, and detailed segment level driving
directions, distance, and time.
Route summary information contains the details, such
as the amount of time the entire trip took, total time spent
driving, and total distance traveled. This information can be
obtained from the RouteItinerary
object instance. A valid route exposes the RouteItinerary
object via the Itinerary
field, and the RouteItinerary
object provides several
fields, such as Distance
,
TripTime
, and DrivingTime
, to provide information about
total distance traveled, total trip time, and time spent driving,
respectively. The following code shows how to access this
information from a Route
object:
//Getting the Route Summary //Get total distance string distance = route.Itinerary.Distance.ToString("#.##"); //Get total drive time string totalDriveTime = String.Format("Total drive time: {0} Hours", (Convert.ToDouble(route.Itinerary.DrivingTime)/ (60 * 60)).ToString("#,##")); //Get total trip time string totalTripTime = String.Format("Total trip time: {0} Hours", (Convert.ToDouble(route.Itinerary.TripTime)/ (60 * 60)).ToString("#.##"));
The distance is expressed in kilometers by default unless you set it otherwise as shown in the previous section. The trip and drive times are expressed in seconds, and in this example, I convert them into hours.
A route summary with the previous example’s formatting looks as follows:
Total Distance: 198.42 (Miles) Total drive time: 3.94 Hours Total trip time: 3.94 Hours
You might notice that the trip and drive times are the same in this case; however, if you set the driving day start and end timings and your route spans across multiple days, you see a difference between the trip time and the drive time (since trip time is the amount of time spent both driving and resting).
Route details include the segment-level driving
instructions along with the bearing and distance. These can be
obtained from the Segment
array
in the RouteItinerary.Segments
field.
Each Segment
object
contains a collection of Direction
objects, distance traveled,
driving time, trip time, and a LatLong
object. Each Direction
object contains information such
as driving directions, driving instructions, and bearing directions
that are used to display detailed driving directions.
The following example shows how to use the RouteItinerary.Segments
to display
detailed driving directions:
//Get the directions foreach(Segment segment in route.Itinerary.Segments) { //Get segment distance if(segment.Distance > 0) { string segmentDistance = segment.Distance.ToString("#.##"); //Display segment distance Console.WriteLine(segmentDistance.ToString()); } //Get directions for each segment foreach(Direction direction in segment.Directions) { //Simple use //string instruction = direction.Instruction; //Complex use //See whether we need this direction as a specific entry switch(direction.Action) { case DirectionAction.Depart: case DirectionAction.Arrive: //Display instruction //Ex: Arrive Finish Console.WriteLine(direction.Instruction); break; case DirectionAction.Other: //State Borders etc //Display only as needed //Ex: Entering Oregon Console.WriteLine(direction.Instruction); break; default: if(direction.Towards != null && direction.Towards != string.Empty) { //Display instruction along with "towards" text //Ex: Take Ramp (LEFT) onto I-405 [I-405 / Renton] Console.WriteLine( String.Format(" {0} [{1}] ", direction.Instruction, direction.Towards)); */ } else { //Display instruction along with no "towards" text //Ex: Take Ramp (LEFT) onto I-405 Console.WriteLine( String.Format(" {0} ", direction.Instruction)); } break; } } }
As you can see, each Direction
instance contains a DirectionAction
enumeration that you can
use to identify what kind of information the current instance
contains. In this example, I have considered only a couple of
actions such as Arrive
, Depart
, and Other
, but you can add more custom driving
directions display logic around the rest of the direction action
enumerations.
In this chapter, you have seen how a route is
represented programmatically using MapPoint Web Service APIs. You
learned that to calculate routes, you use the RouteServiceSoap.CalculateSimpleRoute
and
RouteServiceSoap.CalculateRoute
methods. When a route is calculated, it contains route segments, and
each segment contains a collection of directions. You can change the
route distance units and the language used in describing driving
directions using the UserInfoRouteHeader
object. When displaying
driving directions, you learned to use the DirectionAction
enumeration to understand
the type of directions contained in a Direction
object.
In the next chapter, we will learn how to render routes.
52.14.151.45