Using Avoid Option
Very often when building the vehicle routing problem (VRP) for your fleet with the complex constraints for the large territories, you would like specific vehicles to avoid visiting some identified areas or using some specific roads, etc. In this case, we suggest using the avoid
option, which allows for setting more precise constraints for the problems, making the vehicles avoid the specific unwanted or non-priority routes that violate the specific properties.
Note that the avoid options are applicable only when the location distribution radius (including all the jobs' locations and the vehicles' start, end, and break locations) is under 190 km.
Avoid Features
-
features
- the array of routing features that are preferable to be excluded from the route calculation. Available avoid feature options are: -
tollRoad
- avoid toll roads -
controlledAccessHighway
- avoid controlled-access highways -
ferry
- avoid ferries -
carShuttleTrain
- avoid car shuttle trains -
tunnel
- avoid tunnels -
dirtRoad
- avoid dirt roads -
difficultTurns
- avoid difficult turns, sharp turns, and U-turns on highways and motorways (for trucks only) -
uTurns
- avoid u-turns on highways and motorways (for trucks only)
For example, to build a route avoiding tunnels and controlled-access highways, add the following to the vehicle constraints in the fleet part of the problem:
"profiles": [
{
"type": "truck",
"name": "truck_1",
"avoid": {
"features": [
"tunnel",
"controlledAccessHighway"
]
}
}
]
Avoid Areas
-
areas
- the array of specific areas that are preferably not to be visited during the tour. Specified with the boundingBox
type - a rectangular area defined by a comma-separated list of two latitude and two longitude values: -
north
- number [ -90 .. 90 ] - latitude in WGS 84 degrees of the northern boundary of the box. -
south
- number [ -90 .. 90 ] - latitude in WGS 84 degrees of the southern boundary of the box. -
west
- number [ -180 .. 180 ] - longitude in WGS 84 degrees of the western boundary of the box. -
east
- number [ -180 .. 180 ] - longitude in WGS 84 degrees of the eastern boundary of the box.
For example, to build a route avoiding a specific area on the map, add the following to the vehicle constraints in the fleet part of the problem:
"profiles": [
{
"type": "truck",
"name": "truck_1",
"avoid": {
"areas": [
{
"type": "boundingBox",
"north": 52.523425044655696,
"south": 52.432243159759814,
"east": 13.435039860200588,
"west": 12.990627124745892
}
]
}
}
]
Avoid Map Segments
-
segments
- the specific map segments to be avoided. Each segment identifier entry has the following structure: {segmentId}(#{direction})?
The individual parts are: -
segmentId
- the identifier of the referenced topology segment inside the catalog in the format of domain:system:type:id
, e.g.: here:cm:segment:207551710
. You can find the detailed explanation of how to get the segment identifiers here. -
direction
(optional) - Either *
for bidirectional (default), +
for positive direction, or -
for negative direction.
For example, to build a route avoiding two segments on the map, add the following to the vehicle constraints in the fleet part of the problem:
"profiles": [
{
"type": "truck",
"name": "truck_1",
"avoid": {
"segments": [
{
"here:cm:segment:207551710#+",
"here:cm:segment:76771992#*"
}
]
}
}
]
Note that the maximum amount of the penalized segments for one request should not be greater than 250. "Penalized segments" refer to the segments that have a restriction on maximum baseSpeed
with maxSpeedOnSegment
or avoided with avoid[segments]
.
Avoid Zone IDs
-
zoneIdentifiers
- the specific map zones to be avoided. An array of routing zone identifiers in the format of domain:system:type:id
that routes will avoid going through. For example, the identifier here:cm:envzone:2
references the Berlin Umweltzone environmental zone.
One possible way to get the zone IDs for avoidance is to obtain them from the routingZone
blocks in the response message. You can find the detailed explanation of how to get the zone identifiers here.
Generally, the information about various map zones originates from the respective catalogs of platform.here.com. If you do not have access to the platform catalogs, then you can use the routing response described above.
For example, to build a route avoiding a specific zone on the map, add the following to the vehicle constraints in the fleet part of the problem:
"profiles": [
{
"type": "truck",
"name": "truck_1",
"avoid": {
"zoneIdentifiers": [
"here:cm:envzone:2"
]
}
}
]
Avoid Truck Road Types
-
truckRoadTypes
- the specific road types with additional regulations for traversal by heavy vehicles to be avoided by the trucks. For example, the BK Bearing Class regulations in Sweden, ET categories in Mexico, etc. The identifiers for the supported truck road types can be found here.
For example, to build a route avoiding three specific roads, add the following to the vehicle constraints in the fleet part of the problem:
"profiles": [
{
"type": "truck",
"name": "truck_1",
"avoid": {
"truckRoadTypes": [
"BK1",
"BK2",
"BK3"
]
}
}
]
Avoid Zone Categories
-
zoneCategories
- the specific map zone categories and map zones to be avoided. An array of zone identifiers that will not be taken into account for the evaluation of zone categories to avoid. -
categories
- an array of routing zone categories to avoid. -
exceptZoneIds
- an array of zone identifiers, which will not be taken into account for the evaluation of zone categories to avoid.
For example, to build a route avoiding three specific zone categories, add the following to the vehicle constraints in the fleet part of the problem:
"profiles": [
{
"type": "truck",
"name": "truck_1",
"avoid": {
"zoneCategories": [
"category1",
"category2",
"category3"
]
}
}
]
In case when permission is granted to access some zones within the avoided zone category, the route can be planned using the optional exceptZoneIds
category with an array of the routing zone identifiers in the format of domain:system:type:id
. You can find the detailed explanation of how to get the zone identifiers here.
For example, to build a route avoiding some specific zone category but excluding some zones from the avoid option, add the following to the vehicle constraints in the fleet part of the problem:
"profiles": [
{
"type": "truck",
"name": "truck_1",
"avoid": {
"zoneCategories": [
"category1"
]
"exceptZoneIds" [
"here:cm:envzone:2",
"here:cm:envzone:261"
]
}
}
]
Note that using the avoid
option does not totally prevent the vehicles from visiting the specific areas or roads, but it prefers the routes through areas that are not avoided.
Below we consider two different examples of avoiding areas
and features
when planning a tour.
Avoid Areas Example
Below let's consider a simple example with a vehicle that is going to execute 4 jobs. Due to our constraints, when serving the tour, the vehicle should avoid some specific area which lies within the coordinates 52.523425044655696, 52.432243159759814, 13.435039860200588, 12.990627124745892, that are included in the boundingBox
added in the fleet part of the problem.
As we can see from the plan
part, none of the jobs' locations lies directly within the boundingBox
, but the route between those jobs would definitely cross that area. So, building the problem the way we do below, should create an alternative route so that the vehicle will avoid that specific area.
Problem
{
"fleet": {
"types": [
{
"id": "2759a4c35b01",
"profile": "truck_1",
"costs": {
"fixed": 9.0,
"distance": 0.002,
"time": 0.009
},
"shifts": [
{
"start": {
"time": "2022-07-22T08:49:00Z",
"location": {
"lat": 52.530971,
"lng": 13.384915
}
},
"end": {
"time": "2022-07-22T19:49:00Z",
"location": {
"lat": 52.530971,
"lng": 13.384915
}
}
}
],
"capacity": [
50
],
"amount": 1
}
],
"profiles": [
{
"type": "truck",
"name": "truck_1",
"avoid": {
"areas": [
{
"type": "boundingBox",
"north": 52.523425044655696,
"south": 52.432243159759814,
"east": 13.435039860200588,
"west": 12.990627124745892
}
]
}
}
]
},
"plan": {
"jobs": [
{
"id": "job_1",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 52.61233361982292,
"lng": 13.378211244312677
},
"duration": 135
}
],
"demand": [
14
]
}
]
}
},
{
"id": "job_2",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 52.396871659783336,
"lng": 13.05446681343765
},
"duration": 516
}
],
"demand": [
7
]
}
]
}
},
{
"id": "job_3",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 52.39394204075849,
"lng": 13.082571195347363
},
"duration": 571
}
],
"demand": [
9
]
}
]
}
},
{
"id": "job_4",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 52.387946983417116,
"lng": 13.066284687565254
},
"duration": 378
}
],
"demand": [
6
]
}
]
}
}
]
}
}
Solution
When the jobs were assigned and the route was built, we can see the overall tour statistics including total cost, distance, and duration. Here we should note that this data was calculated considering the longer tour after avoiding the area that we have included in the avoid option.
{
"statistic": {
"cost": 464.185,
"distance": 157451,
"duration": 15587,
"times": {
"driving": 13987,
"serving": 1600,
"waiting": 0,
"break": 0
}
},
"tours": [
{
"vehicleId": "2759a4c35b01_1",
"typeId": "2759a4c35b01",
"stops": [
{
"location": {
"lat": 52.530971,
"lng": 13.384915
},
"time": {
"arrival": "2022-07-22T08:49:00Z",
"departure": "2022-07-22T08:49:00Z"
},
"load": [
36
],
"activities": [
{
"jobId": "departure",
"type": "departure"
}
],
"distance": 0
},
{
"location": {
"lat": 52.39394204075849,
"lng": 13.082571195347365
},
"time": {
"arrival": "2022-07-22T10:11:47Z",
"departure": "2022-07-22T10:21:18Z"
},
"load": [
27
],
"activities": [
{
"jobId": "job_3",
"type": "delivery"
}
],
"distance": 61552
},
{
"location": {
"lat": 52.38794698341712,
"lng": 13.066284687565254
},
"time": {
"arrival": "2022-07-22T10:28:36Z",
"departure": "2022-07-22T10:34:54Z"
},
"load": [
21
],
"activities": [
{
"jobId": "job_4",
"type": "delivery"
}
],
"distance": 63931
},
{
"location": {
"lat": 52.396871659783336,
"lng": 13.05446681343765
},
"time": {
"arrival": "2022-07-22T10:41:27Z",
"departure": "2022-07-22T10:50:03Z"
},
"load": [
14
],
"activities": [
{
"jobId": "job_2",
"type": "delivery"
}
],
"distance": 65802
},
{
"location": {
"lat": 52.61233361982292,
"lng": 13.378211244312675
},
"time": {
"arrival": "2022-07-22T12:29:14Z",
"departure": "2022-07-22T12:31:29Z"
},
"load": [
0
],
"activities": [
{
"jobId": "job_1",
"type": "delivery"
}
],
"distance": 145670
},
{
"location": {
"lat": 52.530971,
"lng": 13.384915
},
"time": {
"arrival": "2022-07-22T13:08:47Z",
"departure": "2022-07-22T13:08:47Z"
},
"load": [
0
],
"activities": [
{
"jobId": "arrival",
"type": "arrival"
}
],
"distance": 157996
}
],
"statistic": {
"cost": 464.185,
"distance": 157451,
"duration": 15587,
"times": {
"driving": 13987,
"serving": 1600,
"waiting": 0,
"break": 0
}
},
"shiftIndex": 0
}
]
}
Avoid Option Is Not Used
Let's compare the results above to a situation where we don't use the avoid
option in a similar problem. If we try to solve the same problem but with the avoid
option removed from the fleet
part, then we expect that the route will be built without any area restrictions, thus the overall statistics of the tour should be different.
Problem
{
"fleet": {
"types": [
{
"id": "2759a4c35b01",
"profile": "truck_1",
"costs": {
"fixed": 9.0,
"distance": 0.002,
"time": 0.009
},
"shifts": [
{
"start": {
"time": "2022-07-22T08:49:00Z",
"location": {
"lat": 52.530971,
"lng": 13.384915
}
},
"end": {
"time": "2022-07-22T19:49:00Z",
"location": {
"lat": 52.530971,
"lng": 13.384915
}
}
}
],
"capacity": [
50
],
"amount": 1
}
],
"profiles": [
{
"type": "truck",
"name": "truck_1"
}
]
},
"plan": {
"jobs": [
{
"id": "job_1",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 52.61233361982292,
"lng": 13.378211244312677
},
"duration": 135
}
],
"demand": [
14
]
}
]
}
},
{
"id": "job_2",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 52.396871659783336,
"lng": 13.05446681343765
},
"duration": 516
}
],
"demand": [
7
]
}
]
}
},
{
"id": "job_3",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 52.39394204075849,
"lng": 13.082571195347363
},
"duration": 571
}
],
"demand": [
9
]
}
]
}
},
{
"id": "job_4",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 52.387946983417116,
"lng": 13.066284687565254
},
"duration": 378
}
],
"demand": [
6
]
}
]
}
}
]
}
}
Solution
As we can see from the solution below, the overall distance of the tour is now 97776 m compared to 157451 m in the previous solution where the avoid
option was used. Therefore, the total duration and cost of the tour were decreased as well. That means that the tour was built without restricting the vehicle visiting the specific area and the algorithm selected the best route to serve the jobs.
{
"statistic": {
"cost": 301.95,
"distance": 97776,
"duration": 10822,
"times": {
"driving": 9222,
"serving": 1600,
"waiting": 0,
"break": 0
}
},
"tours": [
{
"vehicleId": "2759a4c35b01_1",
"typeId": "2759a4c35b01",
"stops": [
{
"location": {
"lat": 52.530971,
"lng": 13.384915
},
"time": {
"arrival": "2022-07-22T08:49:00Z",
"departure": "2022-07-22T08:49:00Z"
},
"load": [
36
],
"activities": [
{
"jobId": "departure",
"type": "departure"
}
],
"distance": 0
},
{
"location": {
"lat": 52.39394204075849,
"lng": 13.082571195347365
},
"time": {
"arrival": "2022-07-22T09:32:23Z",
"departure": "2022-07-22T09:41:54Z"
},
"load": [
27
],
"activities": [
{
"jobId": "job_3",
"type": "delivery"
}
],
"distance": 12006
},
{
"location": {
"lat": 52.38794698341712,
"lng": 13.066284687565254
},
"time": {
"arrival": "2022-07-22T09:49:12Z",
"departure": "2022-07-22T09:55:30Z"
},
"load": [
21
],
"activities": [
{
"jobId": "job_4",
"type": "delivery"
}
],
"distance": 52603
},
{
"location": {
"lat": 52.396871659783336,
"lng": 13.05446681343765
},
"time": {
"arrival": "2022-07-22T10:02:03Z",
"departure": "2022-07-22T10:10:39Z"
},
"load": [
14
],
"activities": [
{
"jobId": "job_2",
"type": "delivery"
}
],
"distance": 54982
},
{
"location": {
"lat": 52.61233361982292,
"lng": 13.378211244312675
},
"time": {
"arrival": "2022-07-22T11:09:49Z",
"departure": "2022-07-22T11:12:04Z"
},
"load": [
0
],
"activities": [
{
"jobId": "job_1",
"type": "delivery"
}
],
"distance": 56853
},
{
"location": {
"lat": 52.530971,
"lng": 13.384915
},
"time": {
"arrival": "2022-07-22T11:49:22Z",
"departure": "2022-07-22T11:49:22Z"
},
"load": [
0
],
"activities": [
{
"jobId": "arrival",
"type": "arrival"
}
],
"distance": 96591
}
],
"statistic": {
"cost": 301.95,
"distance": 97776,
"duration": 10822,
"times": {
"driving": 9222,
"serving": 1600,
"waiting": 0,
"break": 0
}
},
"shiftIndex": 0
}
]
}
Avoid Features Example
Let's consider a simple example where we need a vehicle to avoid tunnels when serving 2 jobs. In the fleet part of the problem below we have added the avoid
option to the vehicle truck_1
, and specified tunnel
in the features
. Now we expect that the vehicle will choose the alternative way between the jobs, although the nearest way would be using the tunnel.
Problem
{
"fleet": {
"types": [
{
"id": "2759a4c35b01",
"profile": "truck_1",
"costs": {
"fixed": 9.0,
"distance": 0.002,
"time": 0.009
},
"shifts": [
{
"start": {
"time": "2022-07-22T08:49:00Z",
"location": {
"lat": 52.524021669858236,
"lng": 13.346234778981403
}
},
"end": {
"time": "2022-07-22T19:49:00Z",
"location": {
"lat": 52.524021669858236,
"lng": 13.346234778981403
}
}
}
],
"capacity": [
50
],
"amount": 1
}
],
"profiles": [
{
"type": "truck",
"name": "truck_1",
"avoid": {
"features": [
"tunnel"
]
}
}
]
},
"plan": {
"jobs": [
{
"id": "job_1",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 52.534591259017255,
"lng": 13.368714336895204
},
"duration": 215
}
],
"demand": [
11
]
}
]
}
},
{
"id": "job_2",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 52.48682246237135,
"lng": 13.373210248775834
},
"duration": 135
}
],
"demand": [
14
]
}
]
}
}
]
}
}
Solution
When the jobs are assigned and the route is built, we can see the overall tour statistics including the total cost, distance, and duration. We should note that those data were calculated considering the longer tour after avoiding the tunnel included in the avoid option. Check the example below to compare the solution after removing the avoid
option.
{
"statistic": {
"cost": 84.50899999999999,
"distance": 18202,
"duration": 4345,
"times": {
"driving": 3995,
"serving": 350,
"waiting": 0,
"break": 0
}
},
"tours": [
{
"vehicleId": "2759a4c35b01_1",
"typeId": "2759a4c35b01",
"stops": [
{
"location": {
"lat": 52.52402166985824,
"lng": 13.346234778981405
},
"time": {
"arrival": "2022-07-22T08:49:00Z",
"departure": "2022-07-22T08:49:00Z"
},
"load": [
25
],
"activities": [
{
"jobId": "departure",
"type": "departure"
}
],
"distance": 0
},
{
"location": {
"lat": 52.534591259017255,
"lng": 13.368714336895204
},
"time": {
"arrival": "2022-07-22T09:05:29Z",
"departure": "2022-07-22T09:09:04Z"
},
"load": [
14
],
"activities": [
{
"jobId": "job_1",
"type": "delivery"
}
],
"distance": 4143
},
{
"location": {
"lat": 52.48682246237135,
"lng": 13.373210248775834
},
"time": {
"arrival": "2022-07-22T09:37:12Z",
"departure": "2022-07-22T09:39:27Z"
},
"load": [
0
],
"activities": [
{
"jobId": "job_2",
"type": "delivery"
}
],
"distance": 11832
},
{
"location": {
"lat": 52.52402166985824,
"lng": 13.346234778981405
},
"time": {
"arrival": "2022-07-22T10:01:25Z",
"departure": "2022-07-22T10:01:25Z"
},
"load": [
0
],
"activities": [
{
"jobId": "arrival",
"type": "arrival"
}
],
"distance": 18196
}
],
"statistic": {
"cost": 84.50899999999999,
"distance": 18202,
"duration": 4345,
"times": {
"driving": 3995,
"serving": 350,
"waiting": 0,
"break": 0
}
},
"shiftIndex": 0
}
]
}
Avoid Feature Is Not Used
Let's compare the results above to a situation where we don't use the avoid
option in the same problem. If we try to solve the same problem but with the avoid
option removed from the fleet
part, then we expect that the route will be built without any restrictions, thus the vehicle will be able to pass through the tunnel, and the overall statistics of the tour should be different.
Problem
{
"fleet": {
"types": [
{
"id": "2759a4c35b01",
"profile": "truck_1",
"costs": {
"fixed": 9.0,
"distance": 0.002,
"time": 0.009
},
"shifts": [
{
"start": {
"time": "2022-07-22T08:49:00Z",
"location": {
"lat": 52.524021669858236,
"lng": 13.346234778981403
}
},
"end": {
"time": "2022-07-22T19:49:00Z",
"location": {
"lat": 52.524021669858236,
"lng": 13.346234778981403
}
}
}
],
"capacity": [
50
],
"amount": 1
}
],
"profiles": [
{
"type": "truck",
"name": "truck_1"
}
]
},
"plan": {
"jobs": [
{
"id": "job_1",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 52.534591259017255,
"lng": 13.368714336895204
},
"duration": 215
}
],
"demand": [
11
]
}
]
}
},
{
"id": "job_2",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 52.48682246237135,
"lng": 13.373210248775834
},
"duration": 135
}
],
"demand": [
14
]
}
]
}
}
]
}
}
Solution
As we can see from the solution below, the overall distance of the tour is now 17017 m compared to 18202 m in the previous solution when the route was built avoiding the tunnel. Therefore, the total duration and cost of the tour were decreased as well.
{
"statistic": {
"cost": 77.918,
"distance": 17017,
"duration": 3876,
"times": {
"driving": 3526,
"serving": 350,
"waiting": 0,
"break": 0
}
},
"tours": [
{
"vehicleId": "2759a4c35b01_1",
"typeId": "2759a4c35b01",
"stops": [
{
"location": {
"lat": 52.52402166985824,
"lng": 13.346234778981405
},
"time": {
"arrival": "2022-07-22T08:49:00Z",
"departure": "2022-07-22T08:49:00Z"
},
"load": [
25
],
"activities": [
{
"jobId": "departure",
"type": "departure"
}
],
"distance": 0
},
{
"location": {
"lat": 52.534591259017255,
"lng": 13.368714336895204
},
"time": {
"arrival": "2022-07-22T09:05:29Z",
"departure": "2022-07-22T09:09:04Z"
},
"load": [
14
],
"activities": [
{
"jobId": "job_1",
"type": "delivery"
}
],
"distance": 4143
},
{
"location": {
"lat": 52.48682246237135,
"lng": 13.373210248775834
},
"time": {
"arrival": "2022-07-22T09:29:23Z",
"departure": "2022-07-22T09:31:38Z"
},
"load": [
0
],
"activities": [
{
"jobId": "job_2",
"type": "delivery"
}
],
"distance": 10649
},
{
"location": {
"lat": 52.52402166985824,
"lng": 13.346234778981405
},
"time": {
"arrival": "2022-07-22T09:53:36Z",
"departure": "2022-07-22T09:53:36Z"
},
"load": [
0
],
"activities": [
{
"jobId": "arrival",
"type": "arrival"
}
],
"distance": 17013
}
],
"statistic": {
"cost": 77.918,
"distance": 17017,
"duration": 3876,
"times": {
"driving": 3526,
"serving": 350,
"waiting": 0,
"break": 0
}
},
"shiftIndex": 0
}
]
}