Finding the closest facility to a location

To find the closest facility to a location, the ArcGIS Runtime for Java API provides a task called the Closest Facility task which can be used with online services as detailed below. 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 which contain Network Analyst tools.

Initializing a Closest Facility task

To initialize a Closest Facility task, declare a ClosestFacilityTask object and pass the URL of a network analysis service REST endpoint to the constructor. To find such a URL, you can use the ArcGIS Services Directory. See the Discovering services topic for more information. 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");

Specifying a Closest Facility task's input parameters

The Closest Facility task's execution method, solveAsync, takes a ClosestFacilityTaskParameters object as input. At a minimum, you will 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 may be defined as a list of graphics, a URL which defines a map service query that returns points or a layer from the network analysis service's corresponding map service. Often, you may also want to define the Barriers parameter, which defines locations that a route to the closest facility must avoid. This parameter may 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.

Below is an example of initializing a ClosestFacilityTaskParameters object with a single graphic and facilities from a GraphicsLayer. The solveAsync method will return both geometry and directions for the calculated route. Note that returnCFRoutes(true) is not explicitly called because it has a default value of true.

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

		// create parameters
		ClosestFacilityTaskParameters params = new ClosestFacilityTaskParameters();
		params.setFacilities(new NAFeaturesAsFeature(facilityLocations));
		params.setIncidents(ArrayList<Graphic>(trafficAccidentGraphic));

Executing a Closest Facility task and handling results

Once you have initialized a ClosestFacilityTaskParameters object with the desired input, finding the closest facility simply requires a call to the solveAsync method. The Closest Facility task passes its results to the onCallback method, which is called whenever an operation completes. The operation's results are contained in a ClosestFacilityResult object. The route's geometry is returned as a graphic in the list of routes. The code below builds on the callback above to retrieve the route, apply a symbol to it and add it to a graphics layer:

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

            @Override
            public void onError(Throwable e) {
                e.printStackTrace();            
            }

            @Override
            public void onCallback(ClosestFacilityResult result) {
                List<Route> routes = result.getRoutes();
                //assume one route
                Graphic routeGraphic = new Graphic(routes.get(0).getRoute().getGeometry(), routeSymbol);
                graphicsLayer.addGraphic(routeGraphic);
            }
        });

Directions are returned as a list in the RoutingDirections field. Each RoutingDirection contained within this list represents one step in the directions. The RoutingDirection'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. The code below steps through the directions, retrieving and formatting the description, distance, and travel time of each. Note that, to keep the example simple, the formatting used is very basic and null checks are omitted.

String directions = "";
	    // Loop through each step of the directions
	    for (RoutingDirection direction : routes.get(0).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 for Java Sample application, installed with the SDK.

2/7/2013