Route to closest location

You can do the following using the ArcGIS Runtime SDK closest facilities task:

  • Find the nearest facilities to incidents based on network travel time
  • Set a maximum impedance (distance or time for example) to search for facilities
  • Set the number of facilities to find for each incident
  • Avoid restricted areas and maneuvers
  • Specify different travel modes to model various transportation scenarios

A closest facilities task is a network analysis operation that is executed asynchronously. It returns results with details regarding the closest facilities to incidents and the routes to travel for a given transportation network. This operation is sometimes referred to as solving for closest facilities or finding closest facilities.

Transportation network datasets are modeled from features (lines and points) that represent roads, bridges, tunnels, bike paths, train tracks, junctions, 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 the best routes between incidents and facilities.

Note:

To learn more, see What is a network dataset in the ArcGIS Desktop documentation.

Choose a data source

The closest facilities task supports using online services or a local mobile geodatabase as its data source for a network.

Use an online network service

To model travel between incidents and facilities, you can use a transportation network exposed as an online ArcGIS service (an ArcGIS network analysis service). Network Analysis 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.

Note:

Some geoprocessing functionality is also available locally using Local Server and geoprocessing packages.

The most important criterion for choosing a service is the area that it covers. You cannot find the closest facilities using a service that does not encompass all the incidents, facilities, and barriers that your user will specify. In addition, services offer differing levels of capability and specialization, which are determined by the service properties and the underlying transportation network dataset.

You can build a transportation network dataset from your own data, or use a dataset provided by someone else, such as Esri's World Street Map data. Then, you can publish the data as a closest facility service on your own portal or on ArcGIS Online. Or, you could use a closest facility service created by someone else that suits your needs, such as the Esri World Closest Facility Service, which references data that covers much of the world. Since the ArcGIS Online data also includes traffic for many areas, analysis can account for dynamic traffic conditions. For instance, you can find the closest facility for a departure time of 7:00 a.m. and compare that route with one you generate for 8:00 a.m.

Accessing a closest facility service may require credentials, which is also true for accessing map and feature services. You provide these credentials when you create the closest facilities task object or by adding a token to the AuthenticationManager.

When using ArcGIS Enterprise portal, default utility services may be configured, such as a closest facilities service. ArcGIS Runtime API provides methods to obtain the default services' URLs for a given portal. Setting a default service on a portal is optional, however, so they may not always be set.

Note:

A closest facilities geoprocessing service can also be published and consumed. For more information on publishing, see the Find Closest Facilities tool and the Publishing a geoprocessing service help topics. For consuming geoprocessing services from Runtime, see Geoprocessing.

Use local data

You can find closest facilities using a transportation network stored on your device, meaning that your device does not need a network 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 or 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.

To learn more about mobile geodatabases see Creating ArcGIS Runtime content.

To learn more about mobile map packages see create a mobile map package with ArcGIS Pro.

Find the closest facilities

The basic steps for finding the closest facilities are outlined below.

  1. Create and load the closest facilities task
  2. Specify closest facility task parameters
  3. Execute the closest facilities task
  4. Process results

Create and load the closest facilities task

The closest facilities task is an object that references a closest facilities service or local transportation network and accepts parameters that define how closest facilities should be found on the network. When executed, it returns routes to the closest facilities as results.

The following example creates a closest facilities task from a public service:

//Creating a closest facilities task from a public service:
QUrl uri("http://sampleserver6.arcgisonline.com/arcgis/rest/services/NetworkAnalysis/SanDiego/NAServer/ClosestFacility");
ClosestFacilityTask* task = new ClosestFacilityTask(uri, parent);

You can create a closest facilities task from a portal's default service (if one is defined) as follows:

//Creating a closest facilities task from a portal's default service:
// url for the portal - e.g. "http://www.arcgis.com"
Credential* cred = new Credential(username, password, parent);
Portal* portal = new Portal(uri, cred, parent);


ClosestFacilityTask* task = nullptr;
connect(portal, &Portal::doneLoading, parent, [portal, cred, &task, parent](Error loadError)
{
  if (!loadError.isEmpty())
    return;


  QUrl serviceUrl = portal->portalInfo()->helperServices()->closestFacilityServiceUrl();
  task = new ClosestFacilityTask(serviceUrl, cred, parent);
});


portal->load();

You can also create a closest facilities task from a mobile map package or mobile geodatabase stored on the device.

Specify closest facility task parameters

Closest facility task parameters specify how the analysis should be performed. A variety of parameters are available that let you customize how the closest facilities are determined, such as incident locations, facility locations, barriers to network travel, travel mode, target facility count, output spatial reference, and so on.

You can get the default set of closest facility task parameters from the closest facility task object. These default parameters are determined by properties of the service and the underlying transportation network dataset. Different services will most likely have different defaults. Rather than building task parameters from scratch, it's recommended to start with the default parameters for the service and to then modify individual parameter values you want to change.

The following example gets the default ClosestFacilityParameters and changes some of the parameter values:

// get the default parameters
ClosestFacilityParameters params;
connect(task, &ClosestFacilityTask::createDefaultParametersCompleted, parent, [&params](QUuid, ClosestFacilityParameters defaultParameters)
{
  params = defaultParameters;
  params.setReturnDirections(true);
  params.setReturnRoutes(true);
  params.setOutputSpatialReference(SpatialReference::wgs84());
});


task->createDefaultParameters();

Your app might allow users to choose some parameters directly, such as cost attributes to accumulate or the number of facilities to find. Your app would get these choices from the user and set the corresponding values on the parameter object.

Specify incidents, facilities, and barriers

Incidents and facilities are points features. They can be created either explicitly from Point objects or by specifying a feature table (local or online) with a geometry of type point. When using a feature table, you can optionally set a where clause to filter which features to use. When specifying an online feature table, the table will not be queried until solve is called.

Barriers are locations along the network that either restrict travel completely (a road closure for example) or add to the cost of travel when traversed (road work or increased traffic for example).

Barriers can be points, polylines, or polygons, and you can define barriers in various ways. Your users might draw barrier graphics interactively, your app might load graphics from a feature table, and so on. For example, you may have a feature table with areas affected by a forest fire that must be avoided. Barriers are optional when solving for closest facilities but when relevant, can make your results more accurate.

The solve operation projects input features to the spatial reference of the transportation network dataset used by the service. The spatial reference of the incidents, facilities, and barriers must be defined but can be different than the transportation network dataset's spatial reference.

The following example creates incidents, facilities, and barriers objects and uses them to set properties on the closest facility parameters:

// create an incident from a location
Point incidentLoc1(-13034379.7137452, 3858390.14190331, SpatialReference::webMercator());
Incident incident(incidentLoc1);


// assign the incidents to the parameters
QList<Incident> incidents{incident};
params.setIncidents(incidents);


// create a facility from a location
Point facilityLoc1(-13032763.2362459, 3860880.60006008, SpatialReference::webMercator());
Facility facility(facilityLoc1);


// assign the facilities to the parameters
QList<Facility> facilities{facility};
params.setFacilities(facilities);


// create a PointBarrier to avoid
Point accidentLocation(-13033331.7103904, 3859368.53617918, SpatialReference::webMercator());
PointBarrier barrier(accidentLocation);


// add the point barriers to the route parameters
QList<PointBarrier> pointBarriers{barrier};
params.setPointBarriers(pointBarriers);

You can also use online tables to define facilities and incidents as follows:

// specify facilities using an online feature table:
// e.g. http://sampleserver6.arcgisonline.com/arcgis/rest/services/NetworkAnalysis/SanDiegoInputs/MapServer/0
ServiceFeatureTable* srvTableFacilities = new ServiceFeatureTable(urlToFacilitiesTable, parent);
QueryParameters qpFacilities;


// set a where clause of 1=1 to return all features
qpFacilities.setWhereClause("1=1");
params.setFacilitiesWithFeatureTable(srvTableFacilities, qpFacilities);

The following example uses a local table to define facilities:

// specify facilities using a feature table in a local runtime geodatabase
Geodatabase* gdb = new Geodatabase(gdbPath, parent);
connect(gdb, &Geodatabase::doneLoading, parent, [gdb, &params](Error loadError)
{
  if (!loadError.isEmpty())
    return;


  GeodatabaseFeatureTable* tableFacilities = gdb->geodatabaseFeatureTable("facilities");


  // set a where clause to use only some points, in this example the table has a 'Type' field defined
  QueryParameters qpFacilites;
  qpFacilites.setWhereClause("Type='Hospital' or Type='Fire Station'");
  params.setFacilitiesWithFeatureTable(tableFacilities, qpFacilites);
});


gdb->load();

Note:

The input table's field values can be used to populate properties for incidents, facilities, and barriers. For local geodatabases, this is based on a naming convention. For details, see Closest facility analysis. When publishing a closest facility service, the default names can be altered. For details, see Loading Network Analysis Objects in ArcMap.

If your app shows the device's location, you may wish to use the geometry of this location for the incident geometry.

Other closest facility parameters

Additional properties on the closest facility parameters object allow you to refine how travel across the network is modeled, to place thresholds on the solve, and to restrict the results that are returned. The parameters are as follows:

  • Accumulate attribute names—A list of cost attributes to accumulate. Cost attributes for a particular service can be obtained from ClosestFacilityTaskInfo.CostAttributes.
  • Travel mode—The type of travel used when solving for closest facilities. Travel modes on a network dataset define how a pedestrian, car, truck, or other medium of transportation moves through the network. A list of travel modes for a particular service can be returned using ClosestFacilityTaskInfo.TravelModes.
  • Default target facility count—The maximum number of facilities to be found for each incident. This value must be at least 1 or more. Individual incidents can override the default value by specifying target facility count.
  • Default impedance cutoff—An impedance value after which the solve will stop searching for facilities. Any facilities beyond this value will not be include in the results.
  • Start time—The date and time used for solving for closest facilities. This can affect the solve result if the network data source incorporates historic or live traffic.
  • Start time usage—Indicates whether the start time represents the departure or arrival along the closest facility routes.
  • Travel direction—Indicates whether the direction of travel is from incidents to facilities or from facilities to incidents. On a network with one-way restrictions and traffic data, changing the travel direction can produce different results. The direction you choose depends on the nature of your analysis.

Execute the closest facilities task

To find closest facilities, call the ClosestFacilityTask::solveClosestFacility method and connect to the ClosestFacilityTask::solveClosestFacilityCompleted signal to await the result. A task parameters object(ClosestFacilityParameters) that defines input features and task preferences is passed to the method, and a ClosestFacilityResult object is returned upon completion.

ClosestFacilityResult solveResult;
connect(task, &ClosestFacilityTask::solveClosestFacilityCompleted, this, [&solveResult](QUuid, ClosestFacilityResult closestFacilityResult)
{
  solveResult = closestFacilityResult;
  // process results...
});
task->solveClosestFacility(params);

To find closest facilities, call the ClosestFacilityTask.solveClosestFacility method and obtain th result from the solveClosestFacilityCompleted property. A task parameters object (ClosestFacilityParameters) that defines input features and task preferences is passed to the method, and a ClosestFacilityResult object is returned upon completion.

var solveResult;
task.solveClosestFacilityStatusChanged.connect( function() {
    solveResult = task.solveClosestFacilityResult;
    // process results...
});


task.solveClosestFacility(params);

Incidents and routes to closest facilities

Process results

When the closest facility task completes, results are available as a ClosestFacilityResult object. Depending on the success of the task, the messages property on the ClosestFacilityResult object may be populated. These messages contain information about how the task was solved.

Output incidents, facilities, or barriers

If the task parameters are set to return incidents, facilities, or barriers, properties of the closest facility result for these outputs are populated. These output features are copies of the corresponding inputs with additional properties such as locationStatus and distanceToNetworkLocation. The location of output incidents and facilities may also differ slightly from the input locations since output incidents and facilities are snapped to the closest non-restricted network element.

Incident to facility routes

Depending on the input parameters, an incident may be routed to multiple facilities. To retrieve each of these routes from the results, use the corresponding facility and incident indices. To help with this, rankedFacilityIndexes returns the output facilities indices in order. The following example shows how to retrieve the routes in order:

// iterate over the solve result incidents
double totalTime = 0.;
for (int incidentIndex = 0; incidentIndex < solveResult.incidents().length(); ++incidentIndex)
{
  // For the present incident get the rankings of the facilities (an ordered list of the returned facilities indexes)
  // Example:  if the facility ranking is [2,0,1,3] then ClosestFacilityResult.Facilities[2] is the closest, followed
  //  by ClosestFacilityResult.Facilities[0] and so on.
  QList<int> rankedFacilitiesIndexes = solveResult.rankedFacilityIndexes(incidentIndex);


  // Use the ranked list of facilities and get the route for this incident-facility combination. Since the
  // facility indexes are in ranked order the 'best' route will be first, followed by the second best and so on.
  for (int facilityIndex : rankedFacilitiesIndexes)
  {
    //use the closestFacilityRoute...
    ClosestFacilityRoute closestFacilityRoute = solveResult.route(facilityIndex, incidentIndex);
    totalTime += closestFacilityRoute.totalTime();
  }
}

Each closest facility route in the results contains the polyline between an incident and facility, as well as the time spent traveling the route and the total time (travel time plus wait time if any).

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)