Calculating alternative routes

This article discusses the use case of alternative routingA route corresponds to a path of a vehicle through the underlying transport network. The main attributes of a route are the distance and the time that the vehicle travels along the path.. 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.

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 polylineA polyline is a continuous line composed of one or more line segments given as a set of tuples with x,y and optional z coordinates. 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();

Related Topics

Showcase Calculate Alternative routes
Technical concept Alternative routes