Calculating alternative routes
This article discusses the use case of alternative routing A 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.
- 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 polyline A 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 |