Find closest facilities

A closest facility task allows you to find facilities that are closest to a given incident using ArcGIS Network Analyst services.

A Network Analyst service contains one or more network analysis layers. ArcGIS provides different types of network analysis layers, such as route, service area, closest facility, and so on, depending on the type of analysis performed. A closest facility task relies on a closest facility analysis layer.

Learn about creating a network analysis service

Finding the closest hospital to an accident, the closest police cars to a crime scene, and the closest store to a customer's address are examples of closest facility problems. When finding closest facilities, specify how many to find and whether the travel direction is toward or away from the facilities. Once you've found the closest facilities, you can display the best route to or from them, return the travel cost for each route, and display directions to each facility. Additionally, you can specify an impedance cutoff beyond which a facility should not be searched. For example, you can set up a closest facility problem to search for hospitals within a 15-minute drive to an accident. Hospitals that take longer than 15 minutes to reach will not be included in the results.

Create a closest facility task

To instantiate a closest facility task, provide a URL to the REST resource that represents a closest facility layer in a Network Analyst service. If the service is secured, provide the credentials that can be used to access the service. The following code snippet shows how to create a closest facility task for the closest facility layer in the San Diego, CA, service on an ArcGIS Online sample server:

ClosestFacilityTask {
        id: closestFacilityTask
        url: "http://sampleserver6.arcgisonline.com/arcgis/rest/services/NetworkAnalysis/SanDiego/NAServer/ClosestFacility"
    }

Prepare the input

Provide input to the closest facility task using properties of the ClosestFacilityTaskParameters component. Declare a new ClosestFacilityTaskParameters component and modify its properties to provide the input.

// Declare a ClosestFacilitiesParameters
    ClosestFacilityTaskParameters {
        id: closestFacilityTaskParameters
    }

The following sections describe some of the inputs you can provide to a closest facility task.

Cutoff

You can specify a cutoff value for the impedance beyond which facilities should be not found. For instance, while locating the closest hospitals from the site of an accident, a cutoff value of 15 minutes indicates that the service should search for the closest hospital within 15 minutes of the accident. If the closest hospital is 17 minutes away, no hospitals return in the closest facility search. A cutoff value is especially useful when searching for multiple facilities.

// Set the default breaks
    ClosestFacilityTaskParameters {
        id: closestFacilityTaskParameters
        defaultCutoff: 15.0
    }

Facility count

Sometimes you may want to find multiple closest facilities from an incident, for example, the nearest three fire stations to a fire. You can do this by setting the defaultTargetFacilityCount property.

// Set the default target facility count
    ClosestFacilityTaskParameters {
        id: closestFacilityTaskParameters
        defaultTargetFacilityCount: 3.0
    }

Facilities

Facilities represent locations that can serve as the starting point or ending point of a closest facility analysis, for example, a fire station or hospital.

Facility features

You can create an array of objects representing facility features. Add features to a NAFeatureAsFeature component to create a collection of facilites.

//Define the closest facility task, its parameter collection, and the graphic symbols that will be displayed on the map to represent them
    ClosestFacilityTaskParameters {
        id: closestFacilityTaskParameters
        facilities: facilitiesFeatures
    }
    
    NAFeaturesAsFeature {
        id: facilitiesFeatures
        spatialReference: map.spatialReference      
    }
    
		 	Graphic {
        id: facilityGraphic
        symbol: markerSymbol
    }

		 	SimpleMarkerSymbol {
        id: markerSymbol
        color: "turquoise"
        style: Enums.SimpleMarkerSymbolStyleSquare
        size: 18
    }
    
    //Each time the user clicks on the map, add a graphic feature to the collection of facilities to be used by the closest facility task
    Map {
       id: mainMap
       anchors: parent.fill

       onMouseClicked: {
          var graphic = facilityGraphic.clone();
              graphic.geometry = mouse.mapPoint;
              facilitiesFeatures.addFeature(graphic); 
    }

Incidents

Incidents also represent locations that can serve as the starting point or ending point of a closest facility analysis, for example, a fire or a traffic accident.

Incident features

You can create an array of objects representing incident features in the same way as discussed above for facility features. You can then assign these features using incidents.

// Set the incidents (represented as features)
    NAFeaturesAsFeature {
        id: incidentsFeatures
    }

    ClosestFacilityTaskParameters {
        id: closestFacilityTaskParameters
        incidents: incidentsFeatures
    }

Travel direction

You can find facilities by accumulating impedance in the direction away from the facility toward the incident, or in the reverse direction toward the facility from the incident. This gives different results on a network with one-way restrictions and different impedances based on the travel direction. The direction you choose depends on the nature of your analysis.

The closest facility for a fire response, for example, should be calculated away from the fire station toward the fire since it's imperative to get fire trucks and personnel quickly to the location of the fire. Alternatively, the closest facility for a traffic accident should choose the opposite direction since the urgent part of the trip for an incoming patient is going to the hospital.

// Set the travel direction
    ClosestFacilityTaskParameters {
        id: closestFacilityTaskParameters
        travelDirection: Enums.NATravelDirectionFromFacility
    }

Drive directions

The task can also return turn-by-turn driving directions for the route if you enable returnDirections on ClosestFacilityTaskParameters. 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 and uses kilometers as the distance units:

// Set how the directions should appear
    ClosestFacilityTaskParameters {
        id: closestFacilityTaskParameters
        returnDirections: true
        directionsLanguage: "fr_FR"
        directionsLengthUnit: Enums.DirectionsLengthUnitKilometers
        
    }

Executing a closest facility task

Once you define a ClosestFacilityTaskParameters component with the desired properties, find the closest facility by calling the solve method.

closestFacilityTask.solve(closestFacilityTaskParameters);

Retrieve results

The closest facility task emits the solveStatusChanged signal during and at the end of the task. After the signal emits indicating the task completed successfully, the results are contained in the solveResult property. The route's geometry is returned as a graphic in the list of routes.

ClosestFacilityTask {
        id: closestFacilityTask
        url: "http://sampleserver6.arcgisonline.com/arcgis/rest/services/NetworkAnalysis/SanDiego/NAServer/ClosestFacility"

        onSolveStatusChanged: {
            if (solveStatus === Enums.SolveStatusCompleted)
            {
                for (var index = 0; index < solveResult.routes.length; index++) {
                    var route = solveResult.routes[index];

                    var graphic = route.route;
                    graphic.symbol = routeSymbol;

                    graphicsLayer.addGraphic(graphic);
                }
            }
            else if (solveStatus === Enums.SolveStatusErrored)
            {
                console.log("Solve error:" + solveError.message);
            }
        }
    }