Find the closest facility

Fnding the closest hospital to an accident, the closest police cars to a crime scene, and the closest store to a customer's address are all examples of closest facility problems. Using the ArcGIS Runtime SDK for Java, use the ClosestFacilityTask class to obtain the closest facility to a location using an online Network Analysis service endpoint as detailed herein. To perform closest facility operations against local data, for example, to support offline or disconnected usage, you can use local geoprocessing services based on geoprocessing packages that contain Network Analyst tools.

Initialize a closest facility task

To initialize a closest facility task, declare a ClosestFacilityTask object and pass the uniform resource locator (URL) of a Network Analysis service REST endpoint to the constructor. To find such a URL, you can use the ArcGIS Services Directory. This example uses the Closest Facility layer of the ESRI_NA service.

ClosestFacilityTask task = new ClosestFacilityTask(
    "http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/" + 
    "Network/USA/NAServer/Closest%20Facility");

Specify a closest facility task's input parameters

The ClosestFacilityTask's execution method takes a ClosestFacilityParameters object as input. At a minimum, you need to specify the Incidents and Facilities parameter, as this determines the locations between which the closest routes will be calculated. Both incident and facility locations can be defined as a list of graphics, a URL that defines a map service query that returns points, or a layer from the network analysis service's corresponding map service. You may also want to define the Barriers parameter, which defines locations that a route to the closest facility must avoid. This parameter can be defined using the same methods as incidents or defined as a list of StopGraphics. Other commonly used boolean parameters include ReturnRoutes, which specifies whether a route geometry to the facility is returned, and ReturnDirections, which specifies whether or not the returned result will include directions.

The following code sample is an example of initializing a ClosestFacilityParameters object with a single graphic and facilities from a graphics layer. The solve method returns both geometry and directions for the calculated route.

Note:

setReturnCFRoutes(true) is not explicitly called because routes are returned by default.

// get facilities graphics from graphics layer
List<Graphic> facilityGraphics = new ArrayList<Graphic>();
int[] graphicIds = facilityGraphicsLayer.getGraphicIDs();
for (int i = 0; i < graphicIds.length; i++) {
  facilityGraphics.add(facilityGraphicsLayer.getGraphic(graphicIds[i]));
}
NAFeaturesAsFeature facilities = new NAFeaturesAsFeature();
facilities.addFeatures(facilityGraphics);

// assumes incident graphic was stored when added
NAFeaturesAsFeature incidents = new NAFeaturesAsFeature();
incidents.addFeature(incidentGraphic);
incidents.setSpatialReference(mapSR);

// create parameters
ClosestFacilityParameters params = new ClosestFacilityParameters();
params.setFacilities(facilities);
params.setIncidents(incidents);
params.setOutSpatialReference(map.getSpatialReference());

Solve the task and handle the results

Once you've initialized a ClosestFacilityParameters object with the desired input, finding the closest facility simply requires a call to the solve method. The closest facility task passes its results to the onCallbackmethod, which is called whenever an operation completes. The operation's results are contained in a ClosestFacilityResult object. The route's geometry is obtained from the graphic which is itself returned by calling getRouteGraphic() on the Route instance. The following code sample builds on the callback above to retrieve the route, apply a symbol to it, and add it to a graphics layer:

task.solve(params, new CallbackListener<ClosestFacilityResult>() {

  @Override
  public void onError(Throwable e) {
    // handle error as desired
  }

  @Override
  public void onCallback(ClosestFacilityResult result) {
    // example uses only the top route in results
    Route topRoute = result.getRoutes().get(0);
    Graphic routeGraphic = new Graphic(topRoute.getRouteGraphic().getGeometry(), routeSymbol);
    graphicsLayer.addGraphic(routeGraphic);
  }
});

Directions for each Route are returned as a list of RouteDirections by calling getRoutingDirections. Each RouteDirections represents one step in the directions. The RouteDirections's geometry field is the segment of the route covered by the step, while the text, length, and time fields store the step's description, distance, and estimated travel time, respectively. The following code sample steps through the directions, retrieving and formatting the description, distance, and travel time of each.

Note:

To keep this example simple, the formatting used is very basic and null checks are omitted.

String directions = "";
// Loop through each step of the directions
for (RouteDirection direction : topRoute.getRoutingDirections()){
  // Get the current step's description and format it
  // (e.g. "Turn right at High Street. 3 miles. 5 minutes.")
  String length = String.format("%.2f", direction.getLength());
  String time = String.format("%.2f", direction.getTime());	    	
  directions += direction.getText() + ". " + length + " miles. " + time + " minutes.\n";
}

Examples of using the Route, Service Area, and Closest Facility tasks can be found in the ArcGIS Runtime SDK for Java sample viewer application installed with the SDK.