Hi All,
The requirement is solve a route with best sequence by the given stops. However, when solve with the service "https://route-api.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World", the result doesn't make sense for me.
This is the original sequence stops and route.
This green route is the response which findBestSequence is true.
The red route is the expectation result.
Attach is the code implemented by ArcGIS Map SDKs for JavaScript version 4.27
<!DOCTYPE html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no" />
<title>Network - Find Best Sequence</title>
<style>
html,
body,
#viewDiv { padding: 0; margin: 0; height: 100%; width: 100%; };
.buttons { position: absolute; top: 50px; right: 50px; z-index: 1; }
.best-sequence { top: 50px; right: 50px; z-index: 1; };
.optimize-layers { top: 100px; right: 50px; z-index: 1; };
</style>
<link rel="stylesheet" href="https://js.arcgis.com/4.27/esri/themes/light/main.css">
<style>
/* overwrite esri default css */
.esri-view .esri-view-surface--inset-outline:focus::after {
outline: none;
};
</style>
<script src="https://js.arcgis.com/4.27/"></script>
<script>
let _findBestSequence = null, _toggleOptimizeLayers = null;
require([
"esri/config", "esri/intl", "esri/Map", "esri/views/MapView", "esri/geometry/Point", "esri/geometry/Polyline",
"esri/symbols/SimpleLineSymbol", "esri/Graphic", "esri/layers/GraphicsLayer", "esri/rest/support/FeatureSet",
"esri/symbols/PictureMarkerSymbol", "esri/rest/route", "esri/rest/support/RouteParameters"],
function(
esriConfig, esriIntl, Map, MapView, Point, Polyline,
SimpleLineSymbol, Graphic, GraphicsLayer, FeatureSet,
PictureMarkerSymbol, route, RouteParameters) {
esriConfig.apiKey = "<API_KEY_WITH_OPTIMIZED_ROUTING>";
esriIntl.setLocale("en");
let _map, _stopLayer, _routeLayer, _bestStopLayer, _bestRouteLayer;
let _stop1, _stop2, _stop3, _stop4, _stop5, _stop6, _stop7, _stop8, _stop9;
const CURB_APPROACH = {
EITHER_SIDE: 0,
RIGHT_SIDE: 1,
LEFT_SIDE: 2,
NO_U_TURN: 3
};
const initMap = () =>
{
_map = new Map({
basemap: "arcgis-streets" // Basemap layer service
});
const CREEK_VIEW_PLZ = [-73.924596, 42.784273];
const CONSTRAINT_EXTENT = {
type: "extent",
xmin: -180,
ymin: -70,
xmax: 180,
ymax: 70
};
const view = new MapView({
map: _map,
center: CREEK_VIEW_PLZ,
constraints: {
geometry: CONSTRAINT_EXTENT,
minZoom: 3,
maxZoom: 18
},
zoom: 13,
container: "viewDiv"
});
_stopLayer = new GraphicsLayer({ id: "stop-layer" });
_routeLayer = new GraphicsLayer({ id: "route-layer" });
_bestStopLayer = new GraphicsLayer({ id: "best-stop-layer" });
_bestRouteLayer = new GraphicsLayer({ id: "best-route-layer" });
_map.addMany([_routeLayer, _stopLayer, _bestRouteLayer, _bestStopLayer]);
};
const stopSymbol = (sequence, fillColor, textColor) =>
{
const svgString = '<svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" width="28" height="28">' +
'<g>' +
`<circle r="12" cy="14" cx="14" stroke-linecap="butt" stroke="#000000" stroke-width="2" fill="${fillColor}" />` +
`<text text-anchor="middle" font-size="12" x="50%" y="50%" dy=".3em" stroke-width="0" fill="${textColor}" >${sequence}</text>` +
'</g>' +
'</svg >';
const svg = `data:image/svg+xml;charset=UTF-8;base64,${btoa(svgString)}`;
return new PictureMarkerSymbol({ url: svg, height: 28, width: 28 });
};
const createStopGraphic = (location, sequence, curbApproach) =>
{
const { longitude, latitude } = location;
const geometry = new Point({
type: "point",
x: longitude,
y: latitude
});
const symbol = stopSymbol(sequence, "#0000FF", "#FFFFFF");
const attributes = {
CurbApproach: curbApproach,
Name: sequence,
Sequence: sequence
};
const graphic = new Graphic({ geometry, symbol, attributes });
return graphic;
};
const addStops = () =>
{
const location1 = { longitude: -73.946891, latitude: 42.808323 };
const location2 = { longitude: -73.938998, latitude: 42.783614 };
const location3 = { longitude: -73.937482, latitude: 42.77529 };
const location4 = { longitude: -73.921461, latitude: 42.773114 };
const location5 = { longitude: -73.900918, latitude: 42.774755 };
const location6 = { longitude: -73.932357, latitude: 42.764845 };
const location7 = { longitude: -73.904294, latitude: 42.788485 };
const location8 = { longitude: -73.897857, latitude: 42.781619 };
const location9 = { longitude: -73.89135, latitude: 42.763158 };
_stop1 = createStopGraphic(location1, 1, CURB_APPROACH.RIGHT_SIDE);
_stop2 = createStopGraphic(location2, 2, CURB_APPROACH.RIGHT_SIDE);
_stop3 = createStopGraphic(location3, 3, CURB_APPROACH.RIGHT_SIDE);
_stop4 = createStopGraphic(location4, 4, CURB_APPROACH.RIGHT_SIDE);
_stop5 = createStopGraphic(location5, 5, CURB_APPROACH.RIGHT_SIDE);
_stop6 = createStopGraphic(location6, 6, CURB_APPROACH.RIGHT_SIDE);
_stop7 = createStopGraphic(location7, 7, CURB_APPROACH.RIGHT_SIDE);
_stop8 = createStopGraphic(location8, 8, CURB_APPROACH.RIGHT_SIDE);
_stop9 = createStopGraphic(location9, 9, CURB_APPROACH.RIGHT_SIDE);
_stopLayer.addMany([_stop1, _stop2, _stop3, _stop4, _stop5, _stop6, _stop7, _stop8, _stop9]);
};
const calculateRoute = async (parameters) =>
{
const url = "https://route-api.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World";
const defaultParameters = {
directionsLengthUnits: "kilometers",
findBestSequence: false,
ignoreInvalidLocations: false,
impedanceAttribute: null,
outputGeometryPrecision: 0,
outputGeometryPrecisionUnits: "feet",
outputLines: "true-shape",
outSpatialReference: "102100",
pointBarriers: null,
polylineBarriers: null,
polygonBarriers: null,
preserveFirstStop: true,
preserveLastStop: true,
restrictionAttributes: [],
restrictUTurns: "at-dead-ends-only",
returnBarriers: false,
returnDirections: true,
returnPolygonBarriers: false,
returnPolylineBarriers: false,
returnPointBarriers: false,
returnTraversedEdges: false,
returnTraversedJunctions: false,
returnTraversedTurns: false,
returnRoutes: true,
returnStops: true,
returnZ: false,
startTime: new Date()
};
const params = Object.assign({}, defaultParameters, parameters);
const routeParameters = new RouteParameters(params);
return route.solve(url, routeParameters).then((response) => {
results = response?.routeResults[0];
return results;
}).catch((error) => {
console.log(error);
});
};
const addRoutes = (routeResults, routeColor, routeLayer) =>
{
const route = routeResults.route;
route.symbol = {
type: "simple-line",
style: "solid",
color: routeColor,
width: 5
};
routeLayer.removeAll();
routeLayer.add(route);
};
const addBestStops = (routeResults) =>
{
const stops = routeResults.stops;
stops.forEach(item =>
{
item.symbol = stopSymbol(item.attributes.Sequence, "#00FF00", "#000000");
});
_bestStopLayer.addMany(stops);
}
_findBestSequence = () =>
{
if (_bestRouteLayer.graphics.length > 0)
{
return;
}
// THE MOCKUP DATA IS CALCULATED BY route-api.arcgis.com
// const routeResults = _getMockupRouteResult();
// if (routeResults)
// {
// addRoutes(routeResults, "#00FF00", _bestRouteLayer);
// addBestStops(routeResults);
// return;
//}
const featureSet = new FeatureSet({ features: [_stop1, _stop2, _stop3, _stop4, _stop5, _stop6, _stop7, _stop8, _stop9]});
const parameters = {
stops: featureSet,
findBestSequence: true,
};
calculateRoute(parameters).then((routeResults) =>
{
addRoutes(routeResults, "#00FF00", _bestRouteLayer);
addBestStops(routeResults);
});
};
_toggleOptimizeLayers = () =>
{
_bestRouteLayer.visible = !_bestRouteLayer.visible;
_bestStopLayer.visible = !_bestStopLayer.visible;
};
const _getMockupRouteResult = () =>
{
const routeResultString = `73.88902999999993,42.76705000000004],[-73.88870999999995,42.766770000000065],[-73.88854999999995,42.76663000000008],[-73.88834999999995,42.766440000000046],[-73.88830999999993,42.76640000000003],[-73.88828999999998,42.76638000000003],[-73.88818999999995,42.76628000000005],[-73.88808999999998,42.76619000000005],[-73.88774999999998,42.765870000000064],[-73.88760999999994,42.76574000000005],[-73.88750999999996,42.76565000000005],[-73.88741999999996,42.765570000000025],[-73.88697999999994,42.76517000000007],[-73.88711999999998,42.76508000000007],[-73.88724999999994,42.76499000000007],[-73.88742999999994,42.76487000000003],[-73.88757999999996,42.764770000000055],[-73.88771999999994,42.76469000000003],[-73.88783999999998,42.76461000000006],[-73.88880999999998,42.76400000000007],[-73.88968999999997,42.76352000000003],[-73.89104508699995,42.762671209000075]]]},"symbol":null,"attributes":{"ObjectID":1,"Name":"1 - 9","FirstStopID":1,"LastStopID":9,"StopCount":9,"StartTime":1695679888215,"EndTime":1695682127523,"StartTimeUTC":1695694288215,"EndTimeUTC":1695696527523,"Total_TravelTime":37.32144021498387,"Total_Miles":14.305202978168186,"Total_Kilometers":23.02205399019508,"Shape_Length":0.23989589944373005},"popupTemplate":null},"routeName":"1 - 9","stops":[{"aggregateGeometries":null,"geometry":{"spatialReference":{"latestWkid":4326,"wkid":4326},"x":-73.94689099999994,"y":42.80832300000003},"symbol":null,"attributes":{"ObjectID":1,"Name":"1","RouteName":null,"Sequence":1,"TimeWindowStart":null,"TimeWindowEnd":null,"ArriveCurbApproach":null,"DepartCurbApproach":1,"ArriveTime":1695679888215,"DepartTime":1695679888215,"ArriveTimeUTC":1695694288215,"DepartTimeUTC":1695694288215,"LocationType":0,"SourceID":1,"SourceOID":63147648,"PosAlong":0.34237244765307046,"SideOfEdge":2,"CurbApproach":1,"Status":0,"SnapX":-73.94672033928657,"SnapY":42.80822427066172,"SnapZ":0,"DistanceToNetworkInMeters":17.749139007493312,"Attr_Minutes":0,"Attr_TravelTime":0,"Attr_Miles":0,"Attr_Kilometers":0,"Attr_TimeAt1KPH":0,"Attr_WalkTime":0,"Attr_TruckMinutes":0,"Attr_TruckTravelTime":0,"Cumul_TravelTime":0,"Cumul_Miles":0,"Cumul_Kilometers":0},"popupTemplate":null},{"aggregateGeometries":null,"geometry":{"spatialReference":{"latestWkid":4326,"wkid":4326},"x":-73.93899799999997,"y":42.78361400000006},"symbol":null,"attributes":{"ObjectID":2,"Name":"2","RouteName":null,"Sequence":4,"TimeWindowStart":null,"TimeWindowEnd":null,"ArriveCurbApproach":1,"DepartCurbApproach":1,"ArriveTime":1695680734292,"DepartTime":1695680734292,"ArriveTimeUTC":1695695134292,"DepartTimeUTC":1695695134292,"LocationType":0,"SourceID":1,"SourceOID":63146091,"PosAlong":0.5636337747364589,"SideOfEdge":2,"CurbApproach":1,"Status":0,"SnapX":-73.93886363519862,"SnapY":42.78365781460919,"SnapZ":0,"DistanceToNetworkInMeters":12.012903327686413,"Attr_Minutes":0,"Attr_TravelTime":0,"Attr_Miles":0,"Attr_Kilometers":0,"Attr_TimeAt1KPH":0,"Attr_WalkTime":0,"Attr_TruckMinutes":0,"Attr_TruckTravelTime":0,"Cumul_TravelTime":14.101278520945046,"Cumul_Miles":6.0195674111523445,"Cumul_Kilometers":9.687540583087975},"popupTemplate":null},{"aggregateGeometries":null,"geometry":{"spatialReference":{"latestWkid":4326,"wkid":4326},"x":-73.93748199999999,"y":42.77529000000004},"symbol":null,"attributes":{"ObjectID":3,"Name":"3","RouteName":null,"Sequence":3,"TimeWindowStart":null,"TimeWindowEnd":null,"ArriveCurbApproach":1,"DepartCurbApproach":1,"ArriveTime":1695680526217,"DepartTime":1695680526217,"ArriveTimeUTC":1695694926217,"DepartTimeUTC":1695694926217,"LocationType":0,"SourceID":1,"SourceOID":63138337,"PosAlong":0.45030927837121815,"SideOfEdge":1,"CurbApproach":1,"Status":0,"SnapX":-73.9374952783505,"SnapY":42.77526012371141,"SnapZ":0,"DistanceToNetworkInMeters":3.4972226978186014,"Attr_Minutes":0,"Attr_TravelTime":0,"Attr_Miles":0,"Attr_Kilometers":0,"Attr_TimeAt1KPH":0,"Attr_WalkTime":0,"Attr_TruckMinutes":0,"Attr_TruckTravelTime":0,"Cumul_TravelTime":10.633365513763083,"Cumul_Miles":5.046930037515004,"Cumul_Kilometers":8.122276568847795},"popupTemplate":null},{"aggregateGeometries":null,"geometry":{"spatialReference":{"latestWkid":4326,"wkid":4326},"x":-73.92146099999997,"y":42.77311400000008},"symbol":null,"attributes":{"ObjectID":4,"Name":"4","RouteName":null,"Sequence":5,"TimeWindowStart":null,"TimeWindowEnd":null,"ArriveCurbApproach":1,"DepartCurbApproach":1,"ArriveTime":1695681105343,"DepartTime":1695681105343,"ArriveTimeUTC":1695695505343,"DepartTimeUTC":1695695505343,"LocationType":0,"SourceID":1,"SourceOID":63138761,"PosAlong":0.4422169742862514,"SideOfEdge":2,"CurbApproach":1,"Status":0,"SnapX":-73.92093689562441,"SnapY":42.77326540793081,"SnapZ":0,"DistanceToNetworkInMeters":46.023911694552666,"Attr_Minutes":0,"Attr_TravelTime":0,"Attr_Miles":0,"Attr_Kilometers":0,"Attr_TimeAt1KPH":0,"Attr_WalkTime":0,"Attr_TruckMinutes":0,"Attr_TruckTravelTime":0,"Cumul_TravelTime":20.285097158798607,"Cumul_Miles":8.172199575981388,"Cumul_Kilometers":13.151826698408081},"popupTemplate":null},{"aggregateGeometries":null,"geometry":{"spatialReference":{"latestWkid":4326,"wkid":4326},"x":-73.90091799999993,"y":42.77475500000003},"symbol":null,"attributes":{"ObjectID":5,"Name":"5","RouteName":null,"Sequence":6,"TimeWindowStart":null,"TimeWindowEnd":null,"ArriveCurbApproach":1,"DepartCurbApproach":1,"ArriveTime":1695681424473,"DepartTime":1695681424473,"ArriveTimeUTC":1695695824473,"DepartTimeUTC":1695695824473,"LocationType":0,"SourceID":1,"SourceOID":63139130,"PosAlong":0.8245841679039545,"SideOfEdge":1,"CurbApproach":1,"Status":0,"SnapX":-73.90102890910511,"SnapY":42.77492064346879,"SnapZ":0,"DistanceToNetworkInMeters":20.54614900282448,"Attr_Minutes":0,"Attr_TravelTime":0,"Attr_Miles":0,"Attr_Kilometers":0,"Attr_TimeAt1KPH":0,"Attr_WalkTime":0,"Attr_TruckMinutes":0,"Attr_TruckTravelTime":0,"Cumul_TravelTime":25.603939080683475,"Cumul_Miles":9.868476490319022,"Cumul_Kilometers":15.881658860608237},"popupTemplate":null},{"aggregateGeometries":null,"geometry":{"spatialReference":{"latestWkid":4326,"wkid":4326},"x":-73.93235699999997,"y":42.76484500000004},"symbol":null,"attributes":{"ObjectID":6,"Name":"6","RouteName":null,"Sequence":2,"TimeWindowStart":null,"TimeWindowEnd":null,"ArriveCurbApproach":1,"DepartCurbApproach":1,"ArriveTime":1695680344685,"DepartTime":1695680344685,"ArriveTimeUTC":1695694744685,"DepartTimeUTC":1695694744685,"LocationType":0,"SourceID":1,"SourceOID":63138157,"PosAlong":0.1916291835017726,"SideOfEdge":2,"CurbApproach":1,"Status":0,"SnapX":-73.93245806896545,"SnapY":42.76460917241386,"SnapZ":0,"DistanceToNetworkInMeters":27.52091696371127,"Attr_Minutes":0,"Attr_TravelTime":0,"Attr_Miles":0,"Attr_Kilometers":0,"Attr_TimeAt1KPH":0,"Attr_WalkTime":0,"Attr_TruckMinutes":0,"Attr_TruckTravelTime":0,"Cumul_TravelTime":7.607832029575178,"Cumul_Miles":4.0238698180457675,"Cumul_Kilometers":6.475802534674298},"popupTemplate":null},{"aggregateGeometries":null,"geometry":{"spatialReference":{"latestWkid":4326,"wkid":4326},"x":-73.90429399999994,"y":42.78848500000004},"symbol":null,"attributes":{"ObjectID":7,"Name":"7","RouteName":null,"Sequence":8,"TimeWindowStart":null,"TimeWindowEnd":null,"ArriveCurbApproach":1,"DepartCurbApproach":1,"ArriveTime":1695681710194,"DepartTime":1695681710194,"ArriveTimeUTC":1695696110194,"DepartTimeUTC":1695696110194,"LocationType":0,"SourceID":1,"SourceOID":63149967,"PosAlong":0.24651097243960704,"SideOfEdge":1,"CurbApproach":1,"Status":0,"SnapX":-73.90429443322716,"SnapY":42.788485495521385,"SnapZ":0,"DistanceToNetworkInMeters":0,"Attr_Minutes":0,"Attr_TravelTime":0,"Attr_Miles":0,"Attr_Kilometers":0,"Attr_TimeAt1KPH":0,"Attr_WalkTime":0,"Attr_TruckMinutes":0,"Attr_TruckTravelTime":0,"Cumul_TravelTime":30.36594730808806,"Cumul_Miles":11.373253179390383,"Cumul_Kilometers":18.303373785743467},"popupTemplate":null},{"aggregateGeometries":null,"geometry":{"spatialReference":{"latestWkid":4326,"wkid":4326},"x":-73.89785699999999,"y":42.781619000000035},"symbol":null,"attributes":{"ObjectID":8,"Name":"8","RouteName":null,"Sequence":7,"TimeWindowStart":null,"TimeWindowEnd":null,"ArriveCurbApproach":1,"DepartCurbApproach":1,"ArriveTime":1695681550048,"DepartTime":1695681550048,"ArriveTimeUTC":1695695950048,"DepartTimeUTC":1695695950048,"LocationType":0,"SourceID":1,"SourceOID":63149749,"PosAlong":0.4030693159607203,"SideOfEdge":1,"CurbApproach":1,"Status":0,"SnapX":-73.89795730532335,"SnapY":42.78176045622528,"SnapZ":0,"DistanceToNetworkInMeters":17.751683431579593,"Attr_Minutes":0,"Attr_TravelTime":0,"Attr_Miles":0,"Attr_Kilometers":0,"Attr_TimeAt1KPH":0,"Attr_WalkTime":0,"Attr_TruckMinutes":0,"Attr_TruckTravelTime":0,"Cumul_TravelTime":27.69685045415899,"Cumul_Miles":10.536587654594042,"Cumul_Kilometers":16.956892682908844},"popupTemplate":null},{"aggregateGeometries":null,"geometry":{"spatialReference":{"latestWkid":4326,"wkid":4326},"x":-73.89134999999999,"y":42.76315800000003},"symbol":null,"attributes":{"ObjectID":9,"Name":"9","RouteName":null,"Sequence":9,"TimeWindowStart":null,"TimeWindowEnd":null,"ArriveCurbApproach":1,"DepartCurbApproach":null,"ArriveTime":1695682127523,"DepartTime":1695682127523,"ArriveTimeUTC":1695696527523,"DepartTimeUTC":1695696527523,"LocationType":0,"SourceID":1,"SourceOID":63138941,"PosAlong":0.2554466608713769,"SideOfEdge":2,"CurbApproach":1,"Status":7,"SnapX":-73.89104508707719,"SnapY":42.76267120919345,"SnapZ":0,"DistanceToNetworkInMeters":59.64467303334708,"Attr_Minutes":0,"Attr_TravelTime":0,"Attr_Miles":0,"Attr_Kilometers":0,"Attr_TimeAt1KPH":0,"Attr_WalkTime":0,"Attr_TruckMinutes":0,"Attr_TruckTravelTime":0,"Cumul_TravelTime":37.32144021498387,"Cumul_Miles":14.305202978168186,"Cumul_Kilometers":23.02205399019508},"popupTemplate":null}]}'`;
return JSON.parse(routeResultString);
};
initMap();
addStops();
const featureSet = new FeatureSet({ features: [_stop1, _stop2, _stop3, _stop4, _stop5, _stop6, _stop7, _stop8, _stop9]});
const parameters = {
stops: featureSet
};
calculateRoute(parameters).then((routeResults) =>
{
addRoutes(routeResults, "#0000FF", _routeLayer);
});
});
const findBestSequence = () => _findBestSequence();
const toggleOptimizeLayers = () => _toggleOptimizeLayers();
</script>
</head>
<body>
<div class="buttons">
<button class="best-sequence" onclick="findBestSequence()">Find Best Sequence</button>
<button class="optimize-layers" onclick="toggleOptimizeLayers()">Show/Hide Best Sequence Layers</button>
</div>
<div id="viewDiv"></div>
</body>
</html>
Solved! Go to Solution.
As the document said, "As a result, the services revert to hierarchy if the straight-line distance between the stops is greater than 50 miles (80.46 kilometers), even if you have specified to find the route without using hierarchy."
reference
One of the possible explanation I guess is that ArcGIS Online prefer useHierarchy.
However, when set the route parameters useHierarchy to false, the result is also incomprehensible for me.
As the document said, "As a result, the services revert to hierarchy if the straight-line distance between the stops is greater than 50 miles (80.46 kilometers), even if you have specified to find the route without using hierarchy."
reference