ArcGIS Runtime SDK for macOS

Find a route

With ArcGIS Runtime SDK, you can:

  • Calculate point-to-point and multipoint routes
  • Optimize the results to find the shortest or the fastest route
  • Reorder stops to find the best sequence
  • Avoid restricted areas and maneuvers
  • Specify time windows of arrival and departure for each stop

A route task is a network analysis task that is executed asynchronously. It returns results with details about a route that visits two or more stops (locations) within a transportation network. This operation is sometimes referred to as solving a route.

Transportation networks are created from features (lines and points) that represent roads, bridges, tunnels, bike paths, train tracks and other elements in the network. The geometric intersections of features help to define connectivity between the network elements they represent. The connectivity of the transportation network is analyzed to find a route.

Note:

To learn more, see the topic What is a network dataset.

This topic's first sections lead through the process to find a route using an online service. See the section Routing with local data to see how using local data is different from using a service. Whether you use a route service or local data, the overall process is the same.

Choosing a routing data source

You can use a transportation network exposed as an online ArcGIS route service (an ArcGIS Network Analysis service). To use an online service, you must have a network connection to the service from your device.

This topic's first sections lead through the process to find a route using an online service. See the section Routing with local data to see how using local data is different from using a service. Whether you use a route service or local data, the overall process is the same.

Network Analyst services are hosted in Esri's cloud platform, ArcGIS Online, or can be published on your own ArcGIS servers. These services provide a REST API for clients such as mobile and Web applications. For more information about publishing a service, see Tutorial: Publishing a network analysis service.

How do route services differ? The most important criteria for choosing a service (or a transportation network for that matter) is the area that it covers. You cannot find a route using a service that does not encompass all the stops and barriers that your user will specify. In addition, route services offer differing levels of capability and specialization.

You can build a transportation network from your own data, or use a dataset provided by someone else, such as Esri's World Street Map data. Then, you can publish a route service on your own portal or on ArcGIS Online. Or, you could use a route service created by someone else that suits your needs. For example, the Esri World Route Service is capable of finding routes almost anywhere because it references road data that covers much of the world. Since the ArcGIS Online road data also includes traffic data for many areas, you can find the best routes and account for dynamic traffic conditions. For instance, you can find the best route from home to work with a departure time of 7:00 a.m. and compare that route with one you generate for 8:00 a.m.

Like other services, some route services require authentication to access. You provide this authentication when you create the route task object.

Creating and loading the route task

The route task is an object that refers to the transportation network, accepts route task parameters, is executed to find a route, and reports results.

Create an instance of the route task object, set its source to the route service you selected in the previous step.

@property (nonatomic, strong) AGSRouteTask *routeTask;
...
self.routeTask = [[AGSRouteTask alloc] initWithURL:[NSURL URLWithString:@"https://sampleserver6.arcgisonline.com/arcgis/rest/services/NetworkAnalysis/SanDiego/NAServer/Route"]];

Then, load the route task.

[self.routeTask loadWithCompletion:^(NSError * _Nullable error) {
 if (error) {
  NSLog(@"%@", error.localizedDescription);
 }
 else if (self.routeTask.loadStatus == AGSLoadStatusLoaded) {
  //the route task loaded
  ...               
 }
}];

Specifying route task parameters

Route task parameters specify how a route should be found. There are many parameters that let you customize how the route is determined. Parameters include stops and barriers. (More about those later.) Other parameters include travel mode, whether stops map be reordered to find an optimized route, the length units to be used in the turn-by-turn directions, and so forth.

The best way to specify parameters is to call the method on the route task that retrieves the default routing parameters defined for the service, and then change the defaults as needed before executing the route task. The service's default parameters support the most common use case for that service. Different services can have different defaults. While it is possible to create the parameters from scratch, this approach is prone to errors and usually not done.

Once the route task has been loaded retrieve its default parameters. Specify that the directions and the route are returned. Remember to set the output spatial reference so that it can be displayed correctly in the map view.

[weakSelf.routeTask defaultRouteParametersWithCompletion:^(AGSRouteParameters * _Nullable routeParams, NSError * _Nullable error) {
 if (error) {
  NSLog(@"%@", error.localizedDescription);
 }
 else {
  weakSelf.routeParameters = routeParams;
  weakSelf.routeParameters.returnDirections = true;
  weakSelf.routeParameters.returnRoutes = true;
  weakSelf.routeParameters.outputSpatialReference = weakSelf.mapView.spatialReference;                  
 }
}];

Your app might allow users to choose some parameters directly, such as whether the stops should be followed in the order specified or in optimum order. Your app would get these choices from the user and set the corresponding route task parameters.

Specifying stops and barriers

A simple route could be from a start point to an end point. In the parlance of routing, both of these points are referred to as stops. A route must have at least two stops, but may have more. Although there are a variety of stop types, they are always point locations along a transportation network.

The role a stop serves in the route is defined with the StopType. A stop can be a Stop (the default), Waypoint or RestBreak. A Stop is a location that the route must visit. A Waypoint is location that the route must travel through without making a stop (for this reason, waypoint locations are not described in the driving directions). At a RestBreak, the route stops for the driver to take a break.

If you use a table to define stops, an integer field called LocationType can be used to define the stop type, where a 0 defines a Stop, 1 defines a Waypoint, and 2 defines a RestBreak.

Note:

There are some restrictions for how waypoints and rest breaks can be used. Waypoints cannot be the first or last stop, have time windows defined, or have added costs defined. Waypoints and rest breaks cannot be used if FindBestSequence for the route is true.

How you get stops for the route is a design decision. Here are some options, and you'll probably come up with other ideas, too.

  • Get the current location of your device and use it as a starting point.
  • Let users choose stops by clicking near roads on a map.
  • Access an address from an address book, geocode the address, and use the result as a stop.

Barriers are places that your route must avoid because they are impassable, or places that add cost to the route if traversed. The best route usually has the least cost.

Unlike stops which are always points, barriers can be points, polylines, or polygons. Like stops, you can define barriers in various ways. Your app could allow users to draw barrier graphics. Another option is to use graphics from a feature table. For example, you may have a feature table with areas affected by a forest fire, and you want your route to avoid those areas.

You do not have to specify any barriers to find a route.

Regardless of how you define your route's stops and barriers, all must share a spatial reference. That spatial reference doesn't have to match the spatial reference of the route service or transportation network.

To set the stops create an array of new stops and pass it to the AGSRouteParameters setStops method. Barriers can be created as point, polylines or polygons. Point barriers are created as AGSPointBarriers and added as an array of points to the AGSRouteParameters using the setPointBarriers method or directly from a feature tables using the setPointBarriersWithFeatureTable method. Equivalent methods exist for polylines and polygons.

//create the stops
AGSPoint *stop1Point = AGSPointMake(-13041171, 3860988, spatialReference);
AGSStop *stop1 = [[AGSStop alloc] initWithPoint:stop1Point];
stop1.name = @"Origin";
        
AGSPoint *stop2Point = AGSPointMake(-13041693, 3856006, spatialReference);
AGSStop *stop2 = [[AGSStop alloc] initWithPoint:stop2Point];
stop2.name = @"Destination";
        
//set the stops on the routeParameters
[self.routeParameters setStops:@[stop1, stop2]];)
 
...       

//create the barriers
AGSPoint *point = AGSPointMake(-13041171, 3860988, spatialReference);
AGSPointBarrier *pointBarrier = [[AGSPointBarrier alloc] initWithPoint:point];)

//set the point barriers on the routeParameters
[self.routeParameters setPointBarriers:@[pointBarrier]];

Executing the route task

Execute the route task while providing the route task parameters.

[self.routeTask solveRouteWithParameters:self.routeParameters completion:^(AGSRouteResult * _Nullable routeResult, NSError * _Nullable error) {
 if (error) {
  NSLog(@"Error = %@", error.localizedDescription);
 }
 else {
  ...
 }
}];

Processing results

The route task signals when the task is complete and results are available. The most familiar part of the results may be the linear graphic that traces the path of the route. Technically, it is a polyline that follows connected edges in the transportation network from stop to stop in a specific order. The route task can return the stops and barriers with the results. This makes it easier for your app to access all the associated graphics when displaying results. The route task also returns turn-by-turn directions that describe the route. If your app does not need one or more of these result elements, each can be turned off by setting route task parameters.

It is up to your app to present results in a useful way. Most commonly, the route, the stops, and sometimes the barriers are displayed on a graphics overlay on the map. The directions may be displayed in a list form or through a directions browser implemented by the app.

__weak typeof(self) weakSelf = self;
[self.routeTask solveRouteWithParameters:self.routeParameters completion:^(AGSRouteResult * _Nullable routeResult, NSError * _Nullable error) {
 if (error) {
  NSLog(@"Error = %@", error.localizedDescription);
 }
 else {
  weakSelf.generatedRoute = routeResult.routes[0];
  AGSSimpleLineSymbol *routeSymbol = [[AGSSimpleLineSymbol alloc] initWithStyle:AGSSimpleLineSymbolStyleSolid color:[UIColor yellowColor] width:5];
  AGSGraphic *routeGraphic = [[AGSGraphic alloc] initWithGeometry:weakSelf.generatedRoute.routeGeometry symbol:routeSymbol];
  [self.routeGraphicsOverlay.graphics addObject:routeGraphic];
 }
}];

//To get the directions explore the array of AGSDirectionManeuvers returned by the directionManeuvers property of the AGSRoute
self.generatedRoute.directionManeuvers
Route result displayed as a graphic on the map

Directions

Directions are returned for each route in the results if requested in the task parameters. Depending on the service configuration, directions can be returned in more than one language. Supported languages for a service are available in the closest facility task info.

Directions are composed of direction maneuvers. Each maneuver contains properties such as the direction text, which contains instructions that describe travel through a section of a route. A direction maneuver is further broken down into maneuver messages that give details about a specific maneuver.

Driving directions from an incident to the closest facility

If defined in the transportation network, directions may also include direction events, which are notifications that do not require any action when traversing the route, for example, crossing over a time zone boundary.

Direction maneuver’s can include from level and to level values to define things like floor levels inside a building. For example, a user may want to see just one level of a walking route that spans multiple floors.

In order to return from level and to level values for a route:

  • The route’s directions style must be Campus
  • The network dataset must be configured to support levels as described in the Setting directions topic in the desktop help. This applies to both local data and the underlying network used by a routing service
  • The ArcGIS Server version hosting the service must be 10.6 or higher (when using online routing services)

Routing with local data

You can find a route using a transportation network stored on your device, meaning that your device does not need a connection to a communication network to find a route. You have a couple of options for provisioning your device with a local transportation network: mobile geodatabases and mobile map packages. Either may be deployed with your app on the device.

If you'd like a ready-to-use and regularly updated network dataset (and locator) for your area of interest, you can license StreetMap Premium data (in mobile map package format). For details, see Add StreetMap Premium data.

Mobile geodatabase

When a transportation network is in a mobile geodatabase, you can access that network by specifying the location of the geodatabase and the name of the network.

Note:

To learn more, see Creating ArcGIS Runtime content.

//The network dataset file is stored in ageodatabase within this application
//(i.e. within the apps main bundle).
    
//locate the path to the RuntimeSanDiego.geodatabase
NSString *path = [[NSBundle mainBundle] pathForResource:@"RuntimeSanDiego" ofType:@"geodatabase"];
    
//instantiate an AGSRouteTask with the path to the geodatabase and the name of the network dataset
self.routeTask = [[AGSRouteTask alloc]initWithPathToDatabase:path networkName:@"Streets_ND"];

Mobile map package

A mobile map package can contain multiple maps, and each map can have multiple transportation networks. Here is the general workflow to access one of these networks:

  • Load the mobile map package from local storage
  • Get the map that contains the desired transportation network from the mobile map package
  • Get the desired transportation network from the map