Avoiding pathways is a common routing consideration for many people doing route optimization — from flooded bike paths to collapsed tunnels, roadside rockslides, underpasses with high levels of crime, slowdowns when crossing train tracks, and beyond.
With Nextmv, we’re building a decision automation platform that seeks to treat decisions as code, meaning they look and feel like regular software and make it easier to build, test, adapt, and ship to production. When it comes to adapting to changes with pathways, the Nextmv SDK provides a consolidated experience for configuring a decision engine with the variables and constraints you need without a lot of extra fuss or work.
This blog post will demonstrate how you can avoid certain pathways — in this case a set of train tracks — or discourage pathways by slowing down their maximum allowable speed so much that they will only be chosen if still beneficial.
Configuring your route optimization engine
For this example, we’re going to create routes in a favorite city of mine: Paderborn, Germany. If you were to ask someone in Paderborn which pathway they’d likely want to avoid, they’d probably mention crossing the train tracks.
We will start with the function that sets up our router engine, which allows you to solve single and multi vehicle routing problems. For this example, we’ll keep things simple with a single vehicle and two stops.
Let's start with our input file:
As you can see, our input file accounts for one vehicle and two stops. The vehicle has a start and an end location, and the stops each have an ID as well as a geographical location.
In the example below we are configuring a router instance to consume this input file. (I’ve excluded the extract method and definitions for brevity.)
The measures method is the one that specifies how our router engine determines the cost of going from one location to another. We have multiple pre-built measures. In this example, we will use the RoutingKit measure. The RoutingKit measure allows us to account for real-road networks and profiles for vehicles such as cars, bikes, and pedestrians as we optimize our routes.
Let me draw your attention to the vehicle profile that we have currently configured: goroutingkit.Car()
This is a prebuilt profile based on OpenStreetMap (OSM) data that knows which ways a car can use and at which speeds it typically travels.
Forbidding train track crossing with route optimization
OK, we’ve configured our input file to specify our vehicles, stops, and measure (with the car vehicle profile). Now, let’s run it through our model. We get the following solution.
There are two spots here where we have to cross train tracks. Crossing the tracks on the right side is usually pretty slow, so let’s see what the solution looks like when we forbid using that way. In order to do so, we head over to https://www.openstreetmap.org/ and find that way crossing the train tracks. We select that way and note down the way id (280764574):
Equipped with this way id, we can write a custom profile that forbids using this particular way.
A TagMapFilter specifies which OSM ways a vehicle is allowed to use. In this sample, we explicitly forbid usage of the way 280764574. For all other ways we let our standard CarTagMapFilter decide.
Here is what that solution looks like:
Note how we have successfully avoided crossing the train tracks.
Discouraging train track crossings with route optimization
Now, what if we know that crossing our train tracks is pretty slow, but we don’t want to completely forbid using that way. Instead, we would prefer to avoid using it whenever it isn’t beneficial. We can do that to by influencing the speed at which we allow our vehicle to move along that way. Here is what that looks like:
We are setting the speed to 1 km/h on that way. This makes it possible to still use the way at the cost of being very slow when using it. And in fact when we run this, we are back to our original solution because the way that we slowed down is only a few meters long and being very slow for only a few meters does not change the optimal solution.
With only a few lines of code we have been able to forbid and slow down certain pathways. Of course you can imagine that it is possible to have the code read those ids from a file, so you never have to touch the code itself.