Unreachable Route Location
This article discusses the use case of start or destination locations of that are located at roads that are unreachable for the configured . For example, a location in a pedestrian zone that is the destination of a truck route.
Benefits
Even if a is located at a road that is not reachable a route shall be returned. There are two main approaches:
- The route on the road network starts or ends at a road nearby that is reachable for the vehicle.
- The route starts or ends at the normally unreachable nearest road and contains roads that are not allowed for the vehicle. These roads are marked as "violated".
Prerequisites
Check if the following prerequisites are fulfilled before you start with the use case.
- Installed and licensed PTV xRoute and xMap services.
- Installed map includes Luxembourg by HERE with the Feature Layer theme PTV_TruckAttributes.
Programming Guide
The following xRoute examples show different typical cases of unreachable locations. The other routing based services like xDima show the same behavior.
Route from a park to a pedestrian zone
Delivery vehicles are not allowed to enter the park but they are allowed to enter the pedestrian zone in the center of Luxemburg.
The location in the park is connected to the road network by a segment of type LINK_SEGMENT represented by a straight line to the road outside the park. Such a long link segment is normally not desired and a result limitation of type WaypointNotLinkedLimitation is returned. If you do not want that the route contains the link segment from the location in the park to the road outside the park, use an OnRoadWaypoint instead of the OffRoadWaypoint.
If there is no reachable road segment within a distance of maximumDistanceToSegment the route cannot be calculated and a WaypointNotLinkableFault is returned. This is more important for unreachable islands that may be quite far from the nearest reachable road.
By default the roads that are normally prohibited but exceptionally allowed for delivery vehicles are assigned a penalty for route selection and thus are only used
if there is no other alternative. The penalty to control this behavior is
deliveryOnlyPenalty.
When you set this penalty to 0 in the code below the pedestrian zone is treated as a normal road and the resulting route uses more of the
pedestrian zone. However, with a penalty of 0 also other pedestrian zones in the middle of the route are treated as normal roads. Because of this the default is a high penalty.
Vehicles that do not deliver goods are not allowed to enter the pedestrian zone. This can be configured in the vehicle by setting the field isDelivery
to false. Then, the route on the road network starts at the nearest reachable road outside the pedestrian zone.
var map = new L.Map('map', {
center: [49.61, 6.125],
zoom: 13
});
// 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 park = {
"$type": "OffRoadWaypoint",
"location": {
"offRoadCoordinate": {
"x": 6.1230132,
"y": 49.6131135
}
}
}
var pedestrianZone = {
"$type": "OffRoadWaypoint",
"location": {
"offRoadCoordinate": {
"x": 6.1294973,
"y": 49.6117966
}
}
}
xroute.calculateRoute({
"waypoints" : [park, pedestrianZone],
"requestProfile": {
"vehicleProfile": {
"legalCondition": {
"isDelivery": true
}
},
"routingProfile": {
"course": {
"violations": {
"enabled": false
},
"specialAreas": {
"deliveryOnlyPenalty": 2500
}
},
"linking": {
"maximumDistanceToSegment": 50000
}
}
},
"resultFields" : {
"polyline" : true
}
}, routingFinished);
function displayPolyline(poly) {
var polyline = [];
for(var i = 0; i < poly.length;++i) {
polyline.push(L.latLng(poly[i].y, poly[i].x));
}
polylineLayer = L.polyline(polyline, {
color: '#2882C8',
weight: 8
});
polylineLayer.addTo(map);
map.fitBounds(polylineLayer.getBounds());
};
function routingFinished(route, exception) {
var polyline = route.polyline.plain.polyline;
displayPolyline(polyline);
resultLimitationMessage = "no result limitation"
if (route.resultLimitations) {
resultLimitationMessage = "result limitation: " + route.resultLimitations[0].message;
}
print(route.distance + 'm, ' + resultLimitationMessage);
}
Route with truck restrictions
In the following example the start of the route is not reachable. The nearest road to the start location has no restriction but it can be left only by passing a road that cannot be used by vehicles higher than 280cm. This restriction is part of the Feature Layer theme "PTV_TruckAttributes".
By default, violations are enabled. Because of this the route can be calculated and starts directly at the nearest road to the given location. The route response contains information that the route violates the height restriction. More specific information about which part of the route is violated is contained in the segments and legs of the route response. If you reduce the height of the vehicle in the code below to a height less than 280cm the route can be calculated without violations.
If the violations are disabled in the code below the route cannot be calculated and the calculateRoute operation returns an exception.
var map = new L.Map('map', {
center: [49.61, 6.125],
zoom: 13
});
// Add tile layer to map
var tileUrl = xServerUrl + '/services/rest/XMap/tile/{z}/{x}/{y}?storedProfile=silkysand&layers=labels,transport,background,PTV_TruckAttributes';
var tileLayer = new L.TileLayer(tileUrl, {
minZoom: 3,
maxZoom: 18,
noWrap: true
}).addTo(map);
var start = {
"$type": "OffRoadWaypoint",
"location": {
"offRoadCoordinate": {
"x": 6.424727439880372,
"y": 49.70447220629954
}
}
}
var notReachableHeightRestriction = {
"$type": "OffRoadWaypoint",
"location": {
"offRoadCoordinate": {
"x": 6.437087059020997,
"y": 49.71041133859443
}
}
}
xroute.calculateRoute({
"waypoints": [start, notReachableHeightRestriction],
"requestProfile": {
"featureLayerProfile": {
"themes": [{
"enabled": true,
"id": "PTV_TruckAttributes"
}]
},
"vehicleProfile": {
"dimensions": {
"height": 400
}
},
"routingProfile": {
"course": {
"violations": {
"enabled": true
}
}
}
},
"resultFields": {
"polyline": true,
"segments" : {
"enabled": true,
"polyline": true
}
}
}, routingFinished);
function displayPolyline(poly, colorIn, opacityIn, bound) {
var polyline = [];
for (var i = 0; i < poly.length; ++i) {
polyline.push(L.latLng(poly[i].y, poly[i].x));
}
polylineLayer = L.polyline(polyline, {
color: colorIn,
weight: 8,
opacity: opacityIn
});
polylineLayer.addTo(map);
if(bound)
{
map.fitBounds(polylineLayer.getBounds());
}
};
function displayViolations(segments) {
for (var i = 0; i < segments.length; ++i) {
if (segments[i].violated) {
var polylineViolated = segments[i].polyline.plain.polyline;
displayPolyline(polylineViolated, '#800080', 0.5, false);
}
}
};
function routingFinished(route, exception) {
var polyline = route.polyline.plain.polyline;
displayPolyline(polyline,'#2882C8', 1, true);
var segments = route.segments;
displayViolations(segments);
violationString = ' no restriction violated';
if (route.violated) violationString = ' part of the route violates a restriction';
print(route.distance + 'm, ' + violationString);
}
Factory premises isolated by gates
Some factory premises are isolated from the main road network by gates and the roads inside these factory premises are attributed as normal roads without restrictions. Such road network characteristics have an impact on both linking a coordinate to a road segment as well as routing in the road network.
Road coordinates may be linked to isolated areas, because with violations enabled as it is the default, a route will always be found.
If violations are turned off, the coordinate will be linked to a different road segment returning an appropriate result limitation.
var map = new L.Map('map', {
center: [49.61, 6.125],
zoom: 13
});
// 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 isolatedByGate = {
"$type": "OffRoadWaypoint",
"location": {
"offRoadCoordinate": {
"x": 6.0977062552,
"y": 49.6201522
}
}
}
var destination = {
"$type": "OffRoadWaypoint",
"location": {
"offRoadCoordinate": {
"x": 6.0951612402,
"y": 49.620822199
}
}
}
xroute.calculateRoute({
"waypoints" : [isolatedByGate, destination],
"requestProfile": {
"routingProfile": {
"course": {
"violations": {
"enabled": false
}
}
}
},
"resultFields" : {
"polyline" : true,
"segments" : {
"enabled": true,
"polyline": true
}
}
}, routingFinished);
function displayPolyline(poly) {
var polyline = [];
for(var i = 0; i < poly.length;++i) {
polyline.push(L.latLng(poly[i].y, poly[i].x));
}
polylineLayer = L.polyline(polyline, {
color: '#2882C8',
weight: 8
});
polylineLayer.addTo(map);
map.fitBounds(polylineLayer.getBounds());
};
function routingFinished(route, exception) {
var polyline = route.polyline.plain.polyline;
displayPolyline(polyline);
resultLimitationMessage = "no result limitation"
if (route.resultLimitations) {
resultLimitationMessage = "result limitation: " + route.resultLimitations[0].message;
}
print(route.distance + 'm, ' + resultLimitationMessage);
}
Whether or not the route is actually violated depends on the vehicle configuration. With the default profile all gates are allowed to be passed, because it is defined as to be free for deliveries (LegalCondition field isDelivery
set to true). However, depending on the vehicle profile LegalCondition fields isDelivery
and isEmergency
, passing gates may result in a violation. The example below illustrates a routing which violates such a gate because in the vehicle profile it is defined that the used vehicle is neither a delivery (isDelivery
set to false) nor an emergency vehicle (isEmergency
set to false).
var map = new L.Map('map', {
center: [49.61, 6.125],
zoom: 13
});
// 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 isolatedByGate = {
"$type": "OffRoadWaypoint",
"location": {
"offRoadCoordinate": {
"x": 6.0977062552,
"y": 49.6201522
}
}
}
var destination = {
"$type": "OffRoadWaypoint",
"location": {
"offRoadCoordinate": {
"x": 6.0951612402,
"y": 49.620822199
}
}
}
xroute.calculateRoute({
"waypoints" : [isolatedByGate, destination],
"requestProfile": {
"vehicleProfile": {
"legalCondition": {
"isDelivery": false,
"isEmergency": false
}
}
},
"resultFields" : {
"polyline" : true,
"segments" : {
"enabled": true,
"polyline": true
},
"nodes" : true
}
}, routingFinished);
function displayPolyline(poly, colorIn, opacityIn, bound) {
var polyline = [];
for (var i = 0; i < poly.length; ++i) {
polyline.push(L.latLng(poly[i].y, poly[i].x));
}
polylineLayer = L.polyline(polyline, {
color: colorIn,
weight: 8,
opacity: opacityIn
});
polylineLayer.addTo(map);
if (bound)
{
map.fitBounds(polylineLayer.getBounds());
}
};
function displayViolations(segments, nodes) {
for (var i = 0; i < segments.length; ++i) {
if (nodes[i].violated) {
var polylineViolated = segments[i].polyline.plain.polyline;
displayPolyline(polylineViolated, '#800080', 0.5, false);
}
}
};
function routingFinished(route, exception) {
var polyline = route.polyline.plain.polyline;
displayPolyline(polyline,'#2882C8', 1, true);
var segments = route.segments;
var nodes = route.nodes;
displayViolations(segments, nodes);
violationString = ' no restriction violated';
if (route.violated) violationString = ' part of the route violates a restriction';
print(route.distance + 'm, ' + violationString);
}