Flexible / Configurable Weighting Update

I invite you to try a planned feature for 1.0 which is now in a usable shape. It allows you to heavily customize the existing vehicle profiles without any Java knowledge. And not only per-request but also for the CH and LM preparations.

Cargo bike example:

base: bike

vehicle_height: 2.3
vehicle_width: 1.2

# let's assume cargo bikes are e-bikes and we should lower speed to prefer shorter and not faster routes automatically
max_speed:
  road_class:
    primary: 28

# if no other condition matches
max_speed_fallback: 25

priority:
  # exclude steps
  road_class:
    steps: 0

  surface:
    sand: 0.5
  # prefer better tracks
  track_type: { other: 1.1, grade1: 1.1 }
  # prefer official bike routes
  bike_network: { other: 0.5 }
  # avoid all situations where we have to get off the bike
  get_off_bike: 0.5

As you can see from the examples there are already several things implemented:

  • avoid, prefer or block roads with with a certain road_class (motorway, primary), surface, track_type, road_access (destination, …), road_environment (tunnel, bridge), toll, bike or hike network etc
  • define maximum vehicle properties like for speed, length, weight, height and width
  • lower the average speed via a speed_factor i.e. influence the time!
  • cap maximum speed (also influences the time!)
  • avoid, prefer or block areas via GeoJSON or also change speed or cap speed based on these areas.
  • avoid, prefer or block countries also works if issue 1875 is fixed (usage: add country encoded value and set border_directory)
  • change distance influence to prefer shorter but potentially slower routes

As there is no documentation except the PR itself and the tests I would appreciate your feedback about the usage and what is unclear or even your first custom profiles :slight_smile:.

Previously discussed here and here.

6 Likes

Have hacked together an interesting feature where we can avoiding certain turns like left_turns. Currently it still has some unexpected behaviour (for T-junctions) and is rather slow for longer routes, as the junction calculation stuff is done while the graph exploration, but it is really fun and interesting which routes are found:

Update: this matter is a bit more tricky as there is sometimes no reason to avoid certain left turns, e.g. for a T-junction coming from bottom, going to left - this is a complete different situation compared with a normal 4-road junction where oncoming traffic needs to be “crossed”.

2 Likes

Cool :slight_smile: I tried it on my machine and got it up and running straight away. First I copied the cargo bike example into the flex box field in the left side pane. Then I tried this bike route (without customization)

it does not take the official bike route that we can see on open cycle map:

image

So I tried with this simplified custom bike:

base: bike

priority:
  bike_network: { other: 0.5 }

and the new route was then using the bike network as expected: :+1:

However, the new route is 5.8km instead of 3.4km long, so I tried playing with the distance_term_constant:

distance_term_constant: 0.10

And after trying a few different values I got the short route again. I am sure there are better examples where there are different ‘intermediate’ routes depending on the priority/distance trade-off, but in my quick example the calculated road was merely snapping back an forth between the two alternatives (depending on the parameters).

1 Like

That’s a very interesting feature.

How can I test this?

I’m running my own instance successfully, but I’m not seeing the flex input field on the left side.

routing.ch.disabling_allowed and routing.lm.disabling_allowed is set to true in config.yml

Tested with master and latest web service jar

I’ve opened a new topic for setting up flex mode: Setup for Flexible / Configurable Weighting Update

You probably need to recreate the js: https://github.com/graphhopper/graphhopper/blob/master/docs/core/quickstart-from-source.md#javascript

E.g. I’m using the following so that changes will be updated automatically:

cd graphhopper/web
$ BROWSERIFYSWAP_ENV='development' npm run watch

btw: you can test this without the UI too via sending the content via curl or similar.

This was now finally merged into master with additional documentation: https://github.com/graphhopper/graphhopper/pull/1841

The data format has slightly changed but is described in the docs.

Get Started with CustomWeighting

Have updated this small tutorial and published it as a blog post:

1 Like

This is a very cool feature! In light of your request on feedback about usage and examples I’ll briefly describe how I’m using it to provide routes for emergency vehicles in case it’s helpful for someone else to see:

I create a new FlagEncoder by copying the car flag encoder https://github.com/graphhopper/graphhopper/blob/master/core/src/main/java/com/graphhopper/routing/util/CarFlagEncoder.java and modifying the speeds like so

double emergencyCarSpeedIncrease = 1.5;
// autobahn
defaultSpeedMap.put("motorway", (int) emergencyCarSpeedIncrease * 100);
defaultSpeedMap.put("motorway_link", (int) emergencyCarSpeedIncrease * 70);
...

I reference this new encoder in DefalutFlagEncoderFactory.java and FlagEncoderFactory.java.

I then create a yaml profile with other specifics (vehicle size, etc.) and modify the config.yml like so:

line 11: graph.flag_encoders: car, emergencycar
line 19: graph.encoded_values: max_weight,max_height,max_width
line 43+:

- name: emergencycar
      vehicle: emergencycar
      weighting: custom
      custom_model_file: ./emergencycar.yml

I can now make requests to my server using the route-custom?profile=emergencycar endpoint!

2 Likes

Thanks, this is the feedback we need!

Indeed for increasing the speed values currently still editing the flag encoder is required. We could think about allowing this for the server-side profile that does not modify an existing profile.

I can now make requests to my server using the route-custom?profile=emergencycar endpoint!

If you do not need further customization you can also use the standard endpoint GET /route?profile=emergencycar or via POST /route.

BTW: the road access could be also something that is “tweakable” by the yaml file in a next version, e.g. to avoid excluding of one-ways and instead putting a slow speed or low priority on it. But we are currently not sure if this is wanted nor which problems we face when implementing this.

This is so excellent!!! I cannot wait!! Good work to you all!! I’m playing around with the pre-release now, its so flexible, and thank you for such straightforward blog documentation!

A few quick questions:

  1. Will version-1.0 allow you weight subtypes of highways?
    for example - a subtype of footways such as marked crosswalks which are tagged:
    • highway=footway
    • footway=marked <–can this tag be weighted?
  • or another example, sidewalks:
    • highway=footway
    • footway=sidewalk <–or can this tag be weighted?
  1. Is the bike_network in the documentation referring to the OpenCycleMap bicycle network? Can the Ways/Roads of that network be customized at all?

  2. I assume the Geojson will have a max file size, or number of feature limitation listed in the documentation? (the geojson feature might be my best work-around, if I can’t specifically “prefer” those subtypes of highways in Question #1)

Great work!! I’ll be eagerly awaiting the release and full documentation! =]

This is not yet possible. Still you could create a new parser (in Java) for the footway tag that would allow this. Support for sidewalks would be nice to have in core for sure.

Is the bike_network in the documentation referring to the OpenCycleMap bicycle network?

It refers to official bike routes that are easily visible with OpenCycleMap, but they are just tags in OSM data.

Can the Ways/Roads of that network be customized at all?

You can customize the route but of course not the ways itself.

I assume the Geojson will have a max file size, or number of feature limitation listed in the documentation?

There are no such limitations yet, but everyone who sets up GraphHopper will set a limit likely with a reverse proxy or dropwizard itself.

(the geojson feature might be my best work-around, if I can’t specifically “prefer” those subtypes of highways in Question #1)

What do you mean here?

Great work!! I’ll be eagerly awaiting the release and full documentation! =]

It is already “full” documentation. If something is unclear do not hesitate to ask and we’ll improve.

Still you could create a new parser (in Java) for the footway tag that would allow this.

Which .java file do I need to modify to add a footway parser? I assume it’s one of these? I’m sorry, I’m trying to find it myself, I don’t come from a java background!

(the geojson feature might be my best work-around, if I can’t specifically “prefer” those subtypes of highways in Question #1)

Sorry that was unclear - I meant to say if I cannot figure how to code a new footway parser (in Java), then I was going to use the my_area geojson (discussed in the documentation), to create weighted polygons around the footway=marked crosswalks of interest, but it sounds like I can just put a footway parser into Java!

Yes, see e.g. the OSMRoadClassParser for something similar.

Maybe this can be done even without doing any changes in Java code: For example by default the possible values for RoadClass are:

public enum RoadClass {
    OTHER("other"), MOTORWAY("motorway"),
    TRUNK("trunk"), PRIMARY("primary"), SECONDARY("secondary"),
    TERTIARY("tertiary"), RESIDENTIAL("residential"), UNCLASSIFIED("unclassified"),
    SERVICE("service"), ROAD("road"), TRACK("track"),
    BRIDLEWAY("bridleway"), STEPS("steps"), CYCLEWAY("cycleway"),
    PATH("path"), LIVING_STREET("living_street"), FOOTWAY("footway"),
    PEDESTRIAN("pedestrian"), PLATFORM("platform"), CORRIDOR("corridor");

A cheap and somewhat hacky way would be first checking if your OSM data even uses all these tags. If for example it does not use ‘platform’ at all you could simply tag all your cross-walks with highway=platform and then in your custom profile you can setup some priority/speed for road_class: {"platform": 0.6} or something. Of course this approach fails if there are roads that are actually tagged as platform and that you do not want to be treated like crosswalks. A slightly cleaner way would be modifying RoadClass.java and simply add CROSSWALK("crosswalk") and tag all your crosswalks with highway=crosswalk (I mean tagging on your local file, you should not push these changes to openstreetmap.org unless this is something that is appreciated by the OSM community). Do not forget to re-build GraphHopper after modifying RoadClass.java though.

What I am trying to say is that if you do custom modifications of your OSM file it might be easier to use some of the existing tags (like highway) than writing another parser for another tag. That being said like @karussell pointed out adding a parser for the footway tag would be a nice addition for GraphHopper.

2 Likes

A cheap and somewhat hacky way would be first checking if your OSM data even uses all these tags. If for example it does not use ‘platform’ at all you could simply tag all your cross-walks with highway=platform and then in your custom profile you can setup some priority/speed for road_class: {"platform": 0.6} or something. Of course this approach fails if there are roads that are actually tagged as platform and that you do not want to be treated like crosswalks. A slightly cleaner way would be modifying RoadClass.java and simply add CROSSWALK("crosswalk") and tag all your crosswalks with highway=crosswalk

  • THAT’S IT!!! That’s a perfect work around!!!

you should not push these changes to openstreetmap.org

  • Yes, totally agree, all these modifications will only happen locally.

it might be easier to use some of the existing tags (like highway) than writing another parser for another tag. That being said like @karussell pointed out adding a parser for the footway tag would be a nice addition for GraphHopper.

  • I agree with that too! I would love to learn how to write the parser myself (and might still try in the coming weeks), but that would be cool if your team eventually developed that into version-1.0. =]
Powered by Discourse