Chapter 7. MapPoint Web Service Route APIs

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.

Understanding 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.

Table 7-1. Methods available on the RouteServiceSoap class

Method

Notes

CalculateRoute

Calculates and returns a route (Route object) based on identified route segments and specifications

CalculateSimpleRoute

Calculates and returns a route (Route object) based on an array of latitude and longitude coordinates

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.

Anatomy of a Route

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.

Sample route with segments and waypoints
Figure 7-1. Sample route with segments and waypoints

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.

Representing a Route Programmatically

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.

Table 7-2. Fields exposed on the RouteSpecification class

Field

Notes

DataSourceName

Name of the data source as a string.

DriverProfile

The time to start and end driving each day (DriverProfile object).

ResultMask

Indicates, as a RouteResultMask enumeration, whether a returned route should include driving directions, a calculated route representation, or both.

Segments

The specification of each segment that makes up the route as an array of SegmentSpecification objects. The order of the array is the order of the stops on the route.

Table 7-3 shows the fields of the SegmentSpecification object:

Table 7-3. SegmentSpecification fields

Field

Notes

Options

The route preference and map view options (SegmentOptions object) for the specified segment of the route

Waypoint

The waypoint (Waypoint object) for the route segment; the beginning of the segment

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.

Programmatic representation of a route using MapPoint Web Service types
Figure 7-2. Programmatic representation of a route using MapPoint Web Service types

With this introduction, let’s look at how to create Route objects using the RouteServiceSoap APIs.

Calculating a Route

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.

Calculating a Route Using the CalculateSimpleRoute Method

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.

Calculating a Route Using the CalculateRoute Method

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 Waypoints 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.

Controlling the driving times

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.

Setting default distance units

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.

Setting the default culture

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.

Displaying Details of 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.

Displaying the Route Summary

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).

Displaying Route Details

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.

Where Are We?

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.148.113.229