I’ve been thinking about something to make GraphHopper routes more flexible and could use some pointers on where to start.
Basically, I want to allow different routing profiles between waypoints in a single route:
With 3 waypoints (A→B→C): use one profile for A→B, then a different one for B→C
With 4 waypoints: three different profiles could be used across the segments
…
I’m thinking about motorcycle routing specifically. Sometimes you want:
Twisty roads for the scenic parts of your trip
Hop on the highway for the boring stretch
Specifically avoid some annoying cities to drive through
Right now I’m stuck with one profile for the whole journey, which isn’t ideal for mixed-purpose rides. Some motorcycle specific apps have that feature, and sometimes that is the only real value-added service they provide. A well tuned custom profile on Graphhopper works very well for most motorcycle applications.
Where to start?
I’m trying to figure out:
Is this something that could work with the current architecture?
Which parts of the code would I need to touch?
How would I handle the transitions between profiles at waypoints?
Any obvious pitfalls or challenges I should watch out for?
I wanted to check with you all before heading down a path that might not make sense.
Any thoughts or pointers to the right parts of the codebase would be helpful!
Why couldn’t this be done on the client-side? E.g. storing the profile per leg on the client-side and then submitting different route requests to the server? Currently I cannot see an advantage when this is done on the server-side. (except maybe the easier usage)
Specifically avoid some annoying cities to drive through
Why is there a separate profile required? Avoiding or excluding areas is possible in a single custom model.
A well tuned custom profile on Graphhopper works very well for most motorcycle applications
Thanks for the idea, it seems indeed a good starting point. I was too focused on the routing engine side of things.
Why is there a separate profile required? Avoiding or excluding areas is possible in a single custom model.
I think that by default most motorcyclists would want to avoid big cities and avoid if possible medium cities, but I can’t assume for them. I must allow for some preset that is friendlier towards urban areas and maybe even TRUNK segments. Would be useful for people living near cities that want to quickly go towards the country-side and THEN only stay on twisty roads far away from cities. The time wasted by going only on small roads or around very big cities all the time is not always justified, but in the end each motorcyclist must decide, I can’t make THE perfect profile for everyone.
Feel free to contribute your changes back
I would love to contribute a clean motorcycle profile to GH, however currently the real issue is with the quality of the data from OSM. Many many (many many many) roads are missing three VERY important information:
motor_vehicle: private
road_class: many unclassified roads that sometimes could count as tertiary and ridable roads
surface : asphalt, gravel, …
With more consistent data, one could assume that missing data must be treated as a potentially dangerous or hazardous road and to be avoided. Sadly, currently, you would exclude many nice lovely scenic roads, at least in my area. I must keep looking and trying things.
Interesting. I would have expected Swiss OSM to be of rather high quality. Can you share a couple of examples of roads where you are missing important information (for you purpose)?
This might be out of scope, but for Switzerland there is are very high quality free to use digital maps not related to OSM: Karten I’d be interested to hear if you find these is useful, especially if used with GraphHopper and/or combined with OSM.
Switzerland is well documented if you stay on highways, trunks, cities, primary and most secondary roads.
However, on the country-side, with tertiary roads or smaller roads, it is not the same. If you start customizing the profile for motorcycles, you end up way more often on those smaller roads.
Also, Switzerland is notorious for having roads everywhere around forests and country-side that are forbidden to motor vehicles. A lot of tags for that are missing.
Just to give you an idea: while testing GH self-hosted, I used a long route that crosses almost all of Switzerland. This route did not map as I would have wanted in a motorcycle routing app. I use it often to debug or test my setup. Well, after I verified it was correctly avoiding big cities, I noticed it did use a small road forbidden to traffic. I have updated OSM data since. I also noticed that a primary road that motorcyclists know very well and use A LOT was actually missing the speed limit.
So yeah, the quality of the data is not so great, I would say. It works well for cars. But when you push setting to find curvy roads, you also find the not so well documented roads.
My first prototype is working. The edge cases are not supported and there are no unit tests to catch them yet.
I am happy with the global result and the minimal change to the UI to add segment profiles.
I am not 100% happy with those two points, but it is a PoC.
I had to touch Api.ts to add a new function that doesn’t use a counter that checks the order of requests like routeWithDispatch() does.
Note: this counter seems to work only because most sub-requests take the same time to process on average. As soon as you mix different profiles, some slower than others (just a guess, didn’t measure it), it happens very often that the order is mixed up and some results are discarded, which is catastrophic when you had a batch of 4 requests like in my example.
I had to create a temporary mutable type for the paths to be able to merge the results. Maybe there is a cleaner way that keeps the existing readonly attribute and does only copies. This is probably my fault because of my low level of React/Javascript knowledge.