Route Task
A Route task allows you to calculate point-to-point and multi-point routes using ArcGIS Server Network Analyst services.
A Network Analyst service contains one or more Network Analysis layers. ArcGIS provides different types of analysis layers, such as Route, Service Area, Closest Facility, etc depending upon the type of analysis to be performed. A Route task relies on a Route analysis layer to compute routes.
ArcGIS Online provides Network Analyst services based on street data for North America and Europe, but you can also create your own services using ArcGIS Server.
Learn about creating Network Analyst Services.
Creating a Route task
To instantiate a Route task, you need to provide a URL to REST resource that represents a Route layer in a Network Analyst service. If the service is secured, you will also need to provide the credentials that can be used to access the service. The following code snippet shows how to create a Route task for the Route layer in the ESRI_Route_NA service on ArcGIS Online.
NSURL* url = [NSURL URLWithString: @"http://tasks.arcgisonline.com/ArcGIS/rest/services/NetworkAnalysis/ESRI_Route_NA/NAServer/Route";
AGSRouteTask* routeTask = [[AGSRouteTask alloc] initWithURL: url];
When you create the task, you need to ensure you take ownership of it. Otherwise, its memory might get deallocated before it has a chance to execute. If you instantiate the task using alloc as shown above , you automatically have ownership. However, if you instantiate the task using a convenience constructor, for instance routeTaskWithURL: , you explicitly need to take ownership by either sending it a retain message, or by assigning it to a property that will retain it.
When you are finished using the task, you should relinquish ownership so that its memory can be reclaimed. You do this either by sending the task a release message or by setting the corresponding property to nil.
Please refer to Apple's Memory Management Programming Guide for more information on how to manage object memory.
Preparing the input
You provide input to the Route task using an object of AGSRouteTaskParameters class. You can instantiate a new AGSRouteTaskParameters object and modify its properties to provide the input. But many times, you may want to calculate routes using the defaults specified in the service. In such cases, you first need to invoke retrieveDefaultRouteTaskParameters on AGSRouteTask to get the default values. The default values are returned to the route task's delegate as an AGSRouteTaskParameters object via the routeTask:operation:didRetrieveDefaultRouteTaskParameters: method.
The following sections describe some of the inputs you can provide to a Route task.
Impedance
Impedance specifies a cost that should be minimized in the resulting route. For example, impedance could be set to Time in order to calculate the fastest route or Length to calculate the shortest route. Impedances supported by the service are listed in the Services Directory under Network Dataset -> Network Attributes with a Usage Type of esriNAUTCost
In the example shown above, Length and Time are supported impedances. The following code snippets sets the impedance to Length in order to calculate the shortest route.
AGSRouteTaskParameters* params = ...;
params.impedanceAttributeName = @"Length";
Stops
Stops specify the locations that must be visited along the route. You need at least 2 stops to calculate a valid route, however, you can add more stops if you like.
There are two ways to specify stops:
Features
You can create an array of AGSStopGraphic objects representing stop features. You can then assign these features to the parameter object using setStopsWithFeatures:. You need to provide a name and a point geometry.
The order of AGSStopGraphic objects in the array indicates, by default, the sequence in which stops will be visited by the route. However, if you enable the findBestSequence property on AGSRouteTaskParameters, the service will attempt to reorder the stops to find the most optimal route. You can also enable the preserveFirstStop and preserveLastStop properties on AGSRouteTaskParameters if you do not want the origin and destination stops to be reordered.
You can also optionally specify a routeName if you want to group stops into different routes. Stops having the same routeName will be assigned a separate route, and stops without a routeName will not be included in the analysis. If you do not assign a routeName to any stops, all stops will be combined into a single route.
If you enable Time Windows in your analysis, you can also assign each stop a start and end time specifying the time window within which the stop needs to be visited. If a stop's timeWindowStart property is set to 10:00 AM and the route arrives at the stop at 9:50 AM, there is a wait time of 10 minutes that is added to the total time. If the timeWindowEnd property is set to 11:00 AM, and the earliest a route can reach the stop is 11:25 AM, a violation of 25 minutes is noted.
A stop can have additional attributes depending upon how the Route layer in the Network Analyst service is configured. These attributes are listed in the Network Analysis Classes -> Class Name:Stops section of the Services Directory.
Attributes may be of type input, output, or both. Input attributes are specified by the client and are taken into consideration by the service while performing the analysis. For example, time window start/end, routeName, etc.
Output attributes are returned by the service along with the computed result when you enable returnStopGraphics on AGSRouteTaskParameters. Output attributes provide additional information about the stop pertaining to the results. For example, the time of arrival/departure, which side of the vehicle the curb is on, etc.
Some attributes can be both Input and Output. These attributes are specified by the client but can be modified or overriden by the service. For example, sequence, when the service finds a more optimal sequence than the one you specified.
Learn more about attributes supported by stop features.
The symbol and infoTemplateDelegate properties on AGSStopGraphic are relevant only if you add the stops to a graphics layer in order to display them on a map. They are not used in the analysis.
Layer Definition
Apart from specifying stops by-value (i.e providing the actual values for each feature as described above), you can also specify them by-reference. This is useful when you already have a set of well known or commonly used stops stored along with the Network Analyst service. In such cases, the application does not need to know the actual details about each stop. All it needs to do is set up a layer definition specifiying which stops should be included in the analysis.
For example, suppose you are writing an application for a logistics company. The company may already have a well established system of assigning daily delivery locations for each driver. Each location might be tagged with the driver's ID, stored in a central repository, and made available to the Network Analyst service. To take advantage of this setup, you can simply setup a layer definition referencing the stops assigned to the driver and use it to calculate a route for the driver. In this way, you do not need to do any additional work to first retrieve the most recent stops and then input them to the service.
A layer definition is represented by an object of the AGSNALayerDefinition class. You can use SQL statements and/or Spatial relationships to specify which stops should be used in the analysis. For example, the following code snippets sets up a layer definition referencing features that fall within the City of Los Angeles and have a value of "Overnight" for the delivery_type attribute.
AGSNALayerDefinition* layerDef = [[[AGSNALayerDefinition alloc] init] autorelease];
layerDef.layerName = @"<layer_in_the_service_containing_stops>";
layerDef.where = @"delivery_type = 'Overnight'";
layerDef.geometry = losangelesPolygon;
layerDef.spatialRelationship = AGSSpatialRelationshipContains ;
Once you have set up a layer definition identifying the features you wish to use, you can use it to specify stops using setStopsWithLayerDefinition:method on an AGSRouteTaskParameters object.
[params setStopsWithLayerDefinition: layerDef];
Restrictions
Restrictions allow you to place constraints on the analysis. For example, you can specify that the route should avoid toll roads. If the route is for an emergency vehicle, you can specify that rules governing one-way streets should be relaxed. The restrictions supported by the service are listed in the Services Directory under Network Dataset -> Network Attributes with a Usage Type of esriNAUTRestriction
The following code snippet applies restrictions in order to avoid passenger ferries and toll roads.
params.restrictionAttributeNames = [NSArray arrayWithObjects:@"Avoid Ferries",@"Avoid Toll Roads",nil];
Barriers
Barriers represent ad-hoc restrictions that must be taken into consideration when calculating a route. A barrier can specify a set of roads or a region that must be completely avoided by the route. For example, a bridge that may be closed due to construction work. Some barriers may permit travel through them albeit at an added cost. For example, an accident on a freeway may temporarily slow down the traffic. This can be represented by a barrier that allows travel along the freeway but increases the travel time required.
Just as with stops, there are two ways to specify barriers :
Features
You can create an array of AGSGraphic objects representing barrier features. You need to provide these features a geometry representing the location and shape of the barrier. The geometry can be a Point, Polyline, or a Polygon. You can then assign these barrier features to the parameter object using setPointBarriersWithFeatures:, setPolylineBarriersWithFeatures: , or setPolygonBarriersWithFeatures: depending upon the type of geometry that was assigned to the feature.
You need to create separate arrays for point, polyline, and polygon barriers.
A barrier can also have additional attributes depending upon how the Route layer in the Network Analyst service is configured. These attributes are listed in the Network Analysis Classes -> Class Name:Barriers, PolylineBarriers, PolygonBarriers section of the Services Directory. Attributes may be of type input (specified by the client), output (returned by the server), or both.
Learn more about Barriers and the attributes supported by point, polyline, and polygon barriers
Layer Definition
Apart from specifying barriers by-value (i.e providing the actual values for each feature as described above), you can also specify barriers by-reference. This is useful when you already have a set of well known or commonly used barriers stored along with the Network Analyst service. For instance, the Transportation Department of a city could provide a Network Analyst service containing information about barriers representing the most recent traffic conditions, incidents, construction work, etc. In such cases, the application does not need to know the actual details about each barrier. All it needs to do is set up a layer definition specifiying which barriers should be included in the analysis.
Once you have a setup a layer definition identifying the features you wish to use, you can use it to specify barriers using setPointBarriersWithLayerDefinition:, setPolylineBarriersWithLayerDefinition:, or setPolygonBarriersWithLayerDefinition: methods on an AGSRouteTaskParameters object
Time Windows
A Time WIndow specifies a period of time within which a stop should be visited by a route. For example, if you have made appointments to meet a number of customers at different locations, you can enable time windows in the analysis and specify a time window for each location to get a route that will allow you to honor your appointments.
To enable Time Windows in your anaysis you need to :
- Enable the useTimeWindows property on AGSRouteTaskParameters
- Specify the time of departure from the origin using the startTime property on AGSRouteTaskParameters
- Assign a time window to each stop as described earlier
Driving Directions
The Route task can also return turn-by-turn driving directions for the route if you enable returnDirections on AGSRouteTaskParameters. You can specify the distance units to use (Miles, Kilometers, etc) through the directionsLengthUnits property and, depending upon the languages supported by the service, you can also specify which language to use through the directionsLanguage property.
The following code snippet requests for driving directions in French and using Kilometers as the distance units:
params.returnDirections = YES;
params.directionsLanguage = @"fr_FR";
params.directionsLengthUnits = AGSNAUnitKilometers;
U-Turn policy
You can specify if U-turns are allowed everywhere (AGSNAUTurnAllowBacktrack), nowhere (AGSNAUTurnNoBacktrack), only at dead ends (AGSNAUTurnAtDeadEndsOnly), or only at intersections and dead ends (AGSNAUTurnAtDeadEndsAndIntersections). Allowing U-turns implies the vehicle can turn around at a junction and double back on the same street.
The following code snippet allows U-turns only at dead ends and intersections :
params.uTurns = AGSNAUTurnAtDeadEndsAndIntersections ;
Result options
Line Type
You can specify whether the geometry of the route feature should be simple straight lines connecting all the stops or follow the true shape of the underlying transportation network.
Geometry options
You can request for the geometry of the route feature to be generalized by modifying the outputGeometryPrecision and outputGeometryPrecisionUnits properties on AGSRouteTaskParameters. Generalizing a geometry removes vertices that add more detail beyond the precision you specify. Removing vertices makes the geometry smaller thus saving time needed to transfer the geometry over the network and also faster to draw as a map graphic.
You can also request the geometry to be projected into a coordinate system of your choice by setting the outSpatialReference property of AGSServerAreaTaskParameters. This may be useful if the spatial reference of your map is different from the spatial reference of the service. If you do not specify an outSpatialReference , the geometries are returned in the spatial reference of the service by default.
Ignore Invalid Locations
Enabling the ignoreInvalidLocations property will allow the Route task to return a route even if some stops are invalid, for instance, if they are not reachable on the underlying transportation network. If this property is disabled, the Route task will return an error even if one stop is invalid.
Refer to the AGSRouteTaskParameters API Reference for a complete list of inputs for the Route task.
Calculating routes
Once you have set up the input parameters, calculating routes is as simple as invoking solveWithParameters: on AGSRouteTask and passing in the AGSRouteTaskParameters object to use in the calculation.
NSOperation* op = [routeTask solveWithParameters:params];
Retrieving results and Handling errors
The Route task informs its delegate when operations complete successfully or when errors are encountered. To get results from the task and to properly handle any errors, you must set one of your classes as the task's delegate. You do this by making your class (typically the view controller which uses the task) adopt the AGSRouteTaskDelegate protocol.
@interface MyViewController : UIViewController <AGSRouteTaskDelegate> {
...
}
An instance of your class must also be set as the task's delegate. This will allow the task to invoke methods on your class in response to operations that the task performs.
routeTask.delegate = self;
Finally, your class should implement one ore more methods defined in the protocol which pertain to the operation being performed. There are a pair of methods for every type of operation - one for success and the other for failure. For instance, the delegate should implement routeTask:operation:didSolveWithResult: method for when the operation completes successfully. Results are passed to the delegate method as an AGSRouteTaskResult object.
- (void) routeTask:(AGSRouteTask*)routeTask operation:(NSOperation*)op didSolveWithResult:(AGSRouteTaskResult*) routeTaskResult{
//process the results
}
An AGSRouteTaskResult object contains an array of AGSRouteResult objects representing the routes that were calculated. Each AGSRouteResult object contains
- A graphic representing the route feature. The graphic's attributes provide information about route properties.
- An array of graphics representing the stops that are visited by the route (if you enabled returnStopGraphics on AGSRouteTaskParameters). Each graphic contains attributes that correspond to stop properties. These properties provide valuable information about the stop as it pertains to the computed route.
- A set of turn-by-turn driving directions (if you enabled returnDirections on AGSRouteTaskParameters)
The AGSRouteTaskResult object also contains an array of messages providing information about any warnings or errors encountered while calculating the route.
It is a good practice to inspect the messages, atleast during developement, as it could help troubleshoot any potential problems.
The delegate should also implement the routeTask:operation:didFailSolveWithError: method in order to be informed when an error is encountered. The error is passed into the method as an NSError object.
- (void) routeTask:(AGSRouteTask*)routeTask operation:(NSOperation*)op didFailSolveWithError:(NSError*) error{
NSLog(@"Error: %@",error);
}