Skip To Content

Find a route

In this topic

To calculate routes and obtain directions you need to adopt the route task AGSRouteTask. Using this task you can optimize the results to find the shortest or the fastest route, reorder stops to find the best sequence, avoid restricted areas and maneuvers, and specify time windows of arrival and departure for each stop. For more information on how tasks work please read the Tasks overview topic.

The route task requires either a local network dataset on your Mac to compute routes, or access to a remote ArcGIS Network Analyst Service. When using a local network dataset, routes can be computed on the Mac even when it has no network connectivity. On the other hand, using remote services requires the Mac to have a network connection and real-time traffic updates can be incorporated into the analysis.

Local Network Datasets

Network datasets are designed to model transportation networks. They are created from source features, which can include simple features (lines and points) representing roads, bridges, tunnels, bike paths, train tracks and various other elements in the network. The geometry of the source features helps establish connectivity between these elements. When you compute a route, the analysis always happens on an underlying network dataset.

Learn more about Network Datasets

There are 2 ways to make a network dataset available on a Mac .

  • Include it within the application
  • Place it in a location accessible to your Mac (for example, in a folder)

These options are described in more detail later in this topic.

Network Analyst Services

Network Analyst services are based on network datasets. They contain on or more analysis layers, such as Route, Service Area, Closest Facility, and so on, depending on the type of analysis to be performed. A Route task requires the service to contain a Route analysis layer in order to compute routes.

Network Analyst services can be hosted in Esri's cloud platform, ArcGIS Online, or can be published on your own on-premise ArcGIS servers. These services provide a REST API for clients such as mobile and web applications.

Learn more about Network Analyst services.

Creating a Route task

Using network dataset included within the application

To include a network dataset in your application, you need to add the *.geodatabase file and the *.tn folder to your application's Xcode project. When you subsequently build your application, Xcode will copy the dataset to the application bundle. When a user installs your application on their Mac, the dataset is installed as part of the application. The following image shows a network dataset added to an Xcode project. Local Network Dataset

Note:

When adding these files to your project, make sure you choose the Create folder references for any added folders option. This will ensure that the folder hierarchy of the *.tn folder is properly maintained.

To instantiate a route task using a network dataset bundled with the application, you need to provide the name of the *.geodatabase file and the network. The following code snippet shows how to create a route task for the network dataset used in the example above.

var error: NSError?
let routeTask = AGSRouteTask(databaseName: "RuntimeSanDiego", network: "Streets_ND", error: &error)

Using network dataset

In this scenario, the network dataset is not bundled within the application. Rather, it is placed in a recognized file path.

To instantiate a route task you need to provide the full path to the *.geodatabase file inside your custom bundle, and the name of the network. The following code snippet shows how to create a route task for the network dataset used in the example above.

var error: NSError?
let documentsDir = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String
let fullPath = "\(documentsDir)NetworkData.bundle/RuntimeSanDiego.geodatabase"
let routeTask = AGSRouteTask(databasePath: fullPath, network: "Streets_ND", error: &error)

Using remote Network Analyst services

To instantiate a route task using a remote service, you need to provide a URL to a REST endpoint that represents a Route analysis layer in a Network Analyst service. If the service is secured, you 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 traffic map service for San Diego in ArcGIS Online:

let url = NSURL(string: "http://sampleserver6.arcgisonline.com/arcgis/rest/services/NetworkAnalysis/SanDiego/NAServer/Route")
let routeTask = AGSRouteTask(URL: url)

Note:
No matter how you create the task, you need to ensure its memory does not get deallocated before it has a chance to execute. To do this, you need to create a strong reference to it if you're using ARC. See 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 the 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 to calculate the fastest route or to 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

Network Attributes
Impedances

In the previous example, Length and Time are supported impedances. The following code snippet sets the impedance to Length to calculate the shortest route:

let params:AGSRouteTaskParameters = ...
params.impedanceAttributeName = "Length"

Stops

Stops specify the locations that must be visited along the route. You need at least two stops to calculate a valid route; however, you can add more stops if you like.

There are two ways to specify stops: features and layer definition.

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 on 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 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 a.m. and the route arrives at the stop at 9:50 a.m., there is a wait time of 10 minutes that is added to the total time. If the timeWindowEnd property is set to 11:00 a.m., and the earliest a route can reach the stop is 11:25 a.m., a violation of 25 minutes is noted.

A stop can have additional attributes depending on 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.

Network Analysis Classes
Attributes of Stops

Attributes can 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, and so on.

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 and departure, which side of the vehicle the curb is on, and so on.

Some attributes can be both input and output. These attributes are specified by the client but can be modified or overridden 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

Layer definition

In addition to specifying stops by value (that is, providing the actual value for each feature as previously described), 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 specifying 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 set up 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 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 snippet 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:

let layerDef = AGSNALayerDefinition()
layerDef.layerName = "<layer_in_the_service_containing_stops>"
layerDef.whereClause = "facility_type = 'Hospital'"
layerDef.geometry = losangelesPolygon
layerDef.spatialRelationship = .Contains

Once you set up a layer definition identifying the features to use, you can use it to specify stops using the 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.

esriNAUTRestriction
Restrictions

The following code snippet applies restrictions in order to avoid passenger ferries and toll roads:

routeParams.restrictionAttributeNames = ["Avoid Ferries", "Avoid Toll Roads"]

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.

As with stops, there are two ways to specify barriers: features and layer definition.

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 polygon. You can then assign these barrier features to the parameter object using setPointBarriersWithFeatures:, setPolylineBarriersWithFeatures:, or setPolygonBarriersWithFeatures: depending on the type of geometry that was assigned to the feature.

Note:

You need to create separate arrays for point, polyline, and polygon barriers.

A barrier can also have additional attributes depending on 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 can 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

In addition to specifying barriers by value (that is, providing the actual value for each feature as previously described), 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, and so on. 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 specifying which barriers should be included in the analysis.

Once you set up a layer definition identifying the features to use, you can use it to specify barriers using the setPointBarriersWithLayerDefinition:, setPolylineBarriersWithLayerDefinition:, or setPolygonBarriersWithLayerDefinition: method on an AGSRouteTaskParameters object.

Time windows

A time window specifies a period of time within which a stop should be visited on a route. For example, if you 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.

Learn more about time windows

To enable time windows in your analysis, you need to do the following:

  1. Enable the useTimeWindows property on AGSRouteTaskParameters.
  2. Specify the time of departure from the origin using the startTime property on AGSRouteTaskParameters.
  3. 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, and so on) through the directionsLengthUnits property and, depending on the languages supported by the service, you can also specify which language to use through the directionsLanguage property.

The following code snippet requests driving directions in French, using kilometers as the distance units:

params.returnDirections = true
params.directionsLanguage = "fr_FR"
params.directionsLengthUnits = .Kilometers

U-turn policy

You can specify whether 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.

Learn more about U-turns

The following code snippet allows U-turns only at dead ends and intersections :

params.uTurns = .AtDeadEndsAndIntersections

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.

Learn more about line types

Geometry options

You can request that the geometry of the route feature 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, 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 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 allows 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 returns 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 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.

let op = routeTask.solveWithParameters(params)
The method returns an NSOperation object that you can use to cancel the operation if, for instance, the user is no longer interested in the results of the task.

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 that uses the task) adopt the AGSRouteTaskDelegate protocol.

An instance of your class must also be set as the task's delegate. This allows 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 that 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 the routeTask:operation:didSolveWithResult: method when the operation completes successfully. Results are passed to the delegate method as an AGSRouteTaskResult object.

func routeTask(routeTask: AGSRouteTask!, operation op: NSOperation!, didSolveWithResult routeTaskResult: AGSRouteTaskResult!) {
 //process the results
}
Note:

If your delegate methods are not being invoked when the task finishes execution, check to make sure that the task is not getting deallocated prematurely. You need to retain the task if you're using manual retain-release, or create a strong reference to it if you're using ARC.

An AGSRouteTaskResult object contains an array of AGSRouteResult objects representing the routes that were calculated. Each AGSRouteResult object contains the following:

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

Note:

It is a good practice to inspect the messages, at least during development, as it can 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.

func routeTask(routeTask: AGSRouteTask!, operation op: NSOperation!, didFailSolveWithError error: NSError!) {
 println("Error : \(error)")
}

Note:

If your delegate methods are not being invoked when the task finishes execution, check to make sure that the task is not getting deallocated before it finishes execution. You need to retain the locator so create a strong reference using ARC.

Related topics