Replicate maxPossibleSpeed through custom model file


we are using the GH routing engine as a component in one of our java projects. We are using GraphHopper version 2.3.

In our setup we need routing for Vespas, i.e. essentially small, slow motorcycles. We initially hard-coded these with a custom flag encoder like this:

public class VespaFlagEncoder extends MotorcycleFlagEncoder {

    public VespaFlagEncoder() {
        // motorcycles are capped at 120 km/h, vespas should be noticeably slower
        maxPossibleSpeed = 50;

    public String toString() {
        return "vespa";

The hopper is then initialised like this (simplified):

Flagencoder = new VespaFlagEncoder();
String vehicle = "vespa";

EncodingManager em = EncodingManager.create(encoder);

hopper = new GraphHopperOSM().forDesktop();
hopper.setProfiles(new Profile(vehicle).setVehicle(vehicle).setWeighting("fastest"));
hopper.getCHPreparationHandler().setCHProfiles(new CHProfile(vehicle));

… and queried like this:

GHRequest request = new GHRequest(origin.y, origin.x, dest.y, dest.x);

GHResponse response = hopper.route(request);

We currently try to use the new GH config file interface to handle the whole router initialisation to be more flexible and rely less on hard-coding custom vehicles. We successfully managed to parse a config object from the following YAML file:

datareader.file: <PATH-TO-OSM>
graph.location: <CACHE-DIR>
graph.flag_encoders: motorcycle
  - name: vespa
    vehicle: motorcycle
    weighting: custom
    custom_model_file: vespa_model.yml
  - profile: vespa
prepare.min_network_size: 200
graph.dataaccess: RAM_STORE

and associated custom vespa_model.yml:

    motorway: 0
    trunk: 50
    primary: 50
    secondary: 50
    tertiary: 50
max_speed_fallback: 50

Printing the resulting GraphHopperConfig object yields:

name=vespa|vehicle=motorcycle|weighting=custom|turnCosts=false|hints={custom_model_file=empty, custom_model=distanceInfluence=70.0|speedFactor={}|maxSpeed={road_class={motorway=0, trunk=50, primary=50, secondary=50, tertiary=50}}|maxSpeedFallback=50.0|priorityMap={}|areas={}}
datareader.file: <PATH-TO-OSM>
graph.location: <CACHE-DIR>
graph.flag_encoders: motorcycle
prepare.min_network_size: 200
graph.dataaccess: RAM_STORE

We can use this to initialise our hopper simply as follows:

hopper = new GraphHopperOSM().forDesktop();

and query it as before.

Problem: The two hoppers route differently. In particular, if my custom model does not contain the motorway:0 setting, it actually chooses a route which contains a significant portion of road_class motorway, despite the overall speed-cap of 50 km/h (which I don’t want and which the initial VespaFlagEncoder did not do). If on the other hand I set motorway:0, as above, I still get a deviation, this time with a shortcut along a poor surface-quality unhewn cobble street (the blue route corresponds to the VespaFlagEncoder, the red route with the suboptimal short-cut is produced from the custom model as shown above) …

Question: Now that we have most of the relevant context … What is the correct way to control, via GH yaml configs and custom model files, the exact behaviour of the VespaFlagEncoder. In other words: how do I control the maxPossibleSpeed attribute of the encoder through the model configuration? Contrary to the available documentation, the config key max_speed_fallback does not appear to achieve this, I think … or am I missing some other aspect where the two solutions deviate and which could be the cause of the differing routing behaviour …

I am aware that config files are still a beta feature in 2.3 but we would like to refrain from upgrading to 3.0 until there is a proper release.

In this case it is best to use the unreleased version 3 (e.g. 3.0-pre3). There won’t be any changes to the JSON format in 3.0 anymore and it is also better documented and tested in production. In fact, the only problem that hinders a 3.0 release is related to the custom model that we are heavily working on.

See the updated blog post with many examples and a demo server here:

Thanks you for the quick response and the reference to the blog post :slight_smile:

Is there an overview of breaking changes when going from 2.3 to the (pre-releases of) 3.0, so that we can assess what impact the migration would have elsewhere?

Otherwise we will probably simply wait until the proper release is out :man_shrugging:

We list all breaking changes that we are aware of here. The format for customizable routing is completely different now and the recommended way for server-side profiles and custom profiles per request is JSON now. Still YAML is supported for server-side profiles (without explicit docs but should be easy to translate the JSON format)

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.