Calculating alternative routes
This article discusses the use case of alternative . PTV xRoute provides the ability to request several alternative routes in one request.
Benefits
Sometimes, a driver can have a precise knowledge of information which might be missing in the map (traffic lights, traffic incident, damaged road, personal convenience or preference, etc...). The driver could then prefer to take another route than the theoretically optimal one. Therefore PTV xRoute proposes alternative routes of good quality (in regards to the request criteria).
Prerequisites
Check if the following prerequisites are fulfilled before you start with the use case.
- Installed and licensed PTV xRoute and xMap services.
Programming Guide
The following xRoute example show how to request alternative routes.
const colors = ['#9c0c0c', '#159107', '#470994'];
var outputString = '[dist(m),time(s)] = ';
var map = new L.Map('map', {
center: [49.591270, 6.124217],
zoom: 17
});
// Add tile layer to map
var tileUrl = xServerUrl + '/services/rest/XMap/tile/{z}/{x}/{y}';
var tileLayer = new L.TileLayer(tileUrl, {
minZoom: 3,
maxZoom: 18,
noWrap: true
}).addTo(map);
var start = {
"x": 6.094,
"y": 49.623
};
var destination = {
"x": 6.204,
"y": 49.611
};
var boundsForMap = L.latLngBounds([49.591270, 6.124217]);
function calculateRoute() {
xroute.calculateRoute({
"waypoints": [{
"$type": "OffRoadWaypoint",
"location": {
"offRoadCoordinate": start,
}
}, {
"$type": "OffRoadWaypoint",
"location": {
"offRoadCoordinate": destination,
}
}],
"resultFields": {
"alternativeRoutes": true,
"polyline": true
},
"geometryOptions": {
"responseGeometryTypes": ["GEOJSON"]
}
}, function(route, exception) {
displayRoutes(route);
outputString += `main[${route.distance}m,${Math.round(route.travelTime)}s]`;
for (let i = 0; i < route.alternativeRoutes.length; i++) {
outputString += `, alt #${i}[${route.alternativeRoutes[i].distance}m,${Math.round(route.alternativeRoutes[i].travelTime)}s]`;
}
print(outputString);
});
};
function displayRoutes(route) {
for (let i = route.alternativeRoutes.length; i > 0; i--) {
displayGeoJson(route.alternativeRoutes[i-1].polyline.geoJSON, colors[i-1], 5);
}
displayGeoJson(route.polyline.geoJSON, '#2882C8', 5);
map.fitBounds(boundsForMap);
};
function displayGeoJson(geoJson, color, weight) {
var jsonObject = JSON.parse(geoJson);
var geoJsonLayer = new L.GeoJSON(jsonObject, {
style: {
color: color,
weight: weight
}
}).addTo(map);
boundsForMap.extend(geoJsonLayer.getBounds());
};
new L.Marker([start.y, start.x]).addTo(map);
new L.Marker([destination.y, destination.x]).addTo(map);
calculateRoute();
This example displays the results of a request with alternative routes. For each alternative route basic information such as the traveltime and the route distance and through the corresponding result field the is returned.
The following xRoute example show how to request alternative routes and encoded paths and how to use the returned encoded Path to determine further information such as in this case the carbon emissions.
const colors = ['#9c0c0c', '#159107', '#470994'];
var outputString = 'co2WellToWheel [co2(kg)] = ';
var scenarioA = {
"$type": "EmissionValueScenario_FRENCH_CO2E_DECREE_2017_639",
"scenarios": [
"ROUTE_SPECIFIC_AVERAGE_FUEL_CONSUMPTION",
"ACTUAL_FUEL_CONSUMPTION"
]
};
var map = new L.Map('map', {
center: [49.591270, 6.124217],
zoom: 17
});
// Add tile layer to map
var tileUrl = xServerUrl + '/services/rest/XMap/tile/{z}/{x}/{y}';
var tileLayer = new L.TileLayer(tileUrl, {
minZoom: 3,
maxZoom: 18,
noWrap: true
}).addTo(map);
var start = {
"x": 6.094,
"y": 49.623
};
var destination = {
"x": 6.204,
"y": 49.611
};
var boundsForMap = L.latLngBounds([49.591270, 6.124217]);
function calculateRoute() {
xroute.calculateRoute({
"waypoints": [{
"$type": "OffRoadWaypoint",
"location": {
"offRoadCoordinate": start,
}
}, {
"$type": "OffRoadWaypoint",
"location": {
"offRoadCoordinate": destination,
}
}],
"resultFields": {
"alternativeRoutes": true,
"polyline": true,
"encodedPath": true
},
"geometryOptions": {
"responseGeometryTypes": ["GEOJSON"]
}
}, function(route, exception) {
displayRoutes(route);
calculateEmissions(route.encodedPath, 'main');
for (let i = 0; i < route.alternativeRoutes.length; i++) {
calculateEmissions(route.alternativeRoutes[i].encodedPath, `alt #${i}`);
}
print(outputString);
});
};
function calculateEmissions(encodedPath, name) {
xroute.calculateRoute({
"waypoints": [{
"$type": "PathWaypoint",
"encodedPath": encodedPath
}],
"resultFields": {
"emissions": true
},
"routeOptions": {
"emissionOptions": {
"valueScenarios": [scenarioA]
},
"effectiveFuelConsumption": {
"fleetSpecificAverageFuelConsumption": "15.00",
"routeSpecificAverageFuelConsumption": "17.00",
"actualFuelConsumptionForThisRoute": "19.00"
}
}
}, function(route, exception) {
outputString += (name != "main") ? ', ' : '';
outputString += `${name}[${route.emissions.values[0].co2eWellToWheel.toFixed(2)}]`;
});
}
function displayRoutes(route) {
for (let i = route.alternativeRoutes.length; i > 0; i--) {
displayGeoJson(route.alternativeRoutes[i-1].polyline.geoJSON, colors[i-1], 5);
}
displayGeoJson(route.polyline.geoJSON, '#2882C8', 5);
map.fitBounds(boundsForMap);
};
function displayGeoJson(geoJson, color, weight) {
var jsonObject = JSON.parse(geoJson);
var geoJsonLayer = new L.GeoJSON(jsonObject, {
style: {
color: color,
weight: weight
}
}).addTo(map);
boundsForMap.extend(geoJsonLayer.getBounds());
};
new L.Marker([start.y, start.x]).addTo(map);
new L.Marker([destination.y, destination.x]).addTo(map);
calculateRoute();