Relaxing path restrictions (one-way etc) for the map-matching of bike trips

First of all many thanks for sharing your project (and related tools). I’ve been testing many free map-matching algorithms and none of those was comparable to Graphhopper in terms of speed (while not offering a better performance in terms of accuracy).

Brief explanation about the context, not strictly relevant to the issue:

I work for for wecity - a mobile app which rewards sustainable mobility - and I’m using the map-matching tool for the creation of maps which show the “safety” (/cyclability) rating of various OSM edges, as evaluated from the feedbacks uploaded by the app users along with the GPS traces of their bike commutes.

A rough explanation of the process leading to the maps:

    • I receive sets of “raw” GPS points (subject to error, thus in general not laying on any OSM edge), each of them representing a trip performed by a user, and the corresponding value from 1 to 5 representing the overall safety rating of the trip as evaluated by the user.
    • I use a python script (which sends a map-match request to my locally hosted graphhopper) to convert such trips into sequences of edges (each edge is intended as an unordered set of two points) that actually lay on the OSM graph, and store the sequences into a postgis database along with their safety ratings and a few other attributes.
    • I use spatial queries for grouping the records by edge, and compute an average rating for every unique edge within a set of map-matched trips (such set is selected filtering the whole map-matched trips database with conditions on the trip bounding box - e.g. the trip is contained within a given city administrative boundary - and/or on other trip features - e.g. datetime).

The whole process started to work quite well (after a few adjustments I may discuss in a further topic), so I started focusing on assessing the quality of the map-matching by visualizing the map matching response for a bunch of random trips.

For regarding the task of map-matching a wide variety of real bike trips, neither the profile “bike” or the profile “foot” seem to fully suit the task.

The bike profile does not allow to travel a one-direction road in the wrong direction. On some records the user is obviously doing that, and the map matched trip ends up showing major deviations wrt the original GPS track:

(Black line, white points: original track, grey points: points that were discarded before submitting to graphhopper)
(Red line, yellow points: map-matched track, Yellow polygon: gps accuracy region centered on map-matched track)

On the other hand the foot profile handles this case very well, but on some other examples it (rightly) avoids tracks that are designated for bikes only.

I’m sure those behaviors suit very well routing applications, since they avoid cyclists and pedestrians getting in trouble. For regarding a map-matching application I’d want my result to “care less” about these restrictions, thus to be mostly driven by the GPS points provided. Still, some of the restrictions are very useful (e.g. avoid motorways).

I decided to face the matter by editing the FlagEncoder files, and try to merge the two profile into one that suits my needs. I obtained good results (in terms of resulting paths) from editing the FootFlagEncoder, i.e. changing the block at line 192 in:

if (way.hasTag(“foot”, intendedValues) ||
way.hasTag(“bicycle”, intendedValues) ||
way.hasTag(“bicycle”, “dismount”) ||
way.hasTag(“highway”, “cycleway”))
return EncodingManager.Access.WAY;

On the other hand, I was not able to adapt the BikeFlagEncoder to allow crossing a one-direction edge in the wrong direction. Although my temporary patch fixed the issue, I think this second solution would be much more appropriate, as I’d obtain a plausible result in terms of time that could be useful for future features (e.g. it would be interesting to compare it with the duration of the original trip).

So, questions are:

  1. Do you think working on the FlagEncoders is the right way to face the issue?
  2. I was not able to understand where the one-direction restrictions are enforced in the bike profile. Is it doable to remove such restriction from the bike profile? Or should I manually change all the speeds defined in my edited version of the FootFlagEncoder to values similar to those found in the bike profile?

Many thanks,


thanks for sharing this interesting project :+1:.

Yes. You could also look at the custom models and if it’s possible to do your customisations only via yaml.

Sure, you can remove this block and only keep:

        accessEnc.setBool(false, edgeFlags, true);
        accessEnc.setBool(true, edgeFlags, true);
1 Like