Bus flag encoder on graphhopper.com

Hi everyone,

I’ve been trying to implement a bus flag encoder, but I just can’t get it working as well as the one on graphhopper.com.

Do you have any plans to release this flag encoder? I can’t seem to find it in the codebase anywhere.

My BusFlagEncoder is pretty hacky, and the way I’ve implemented it is just to copy CarFlagEncoder, and replace the restrictions with this:

super(speedBits, speedFactor, maxTurnCosts);
restrictions.addAll(Arrays.asList("motor_vehicle", "vehicle", "access", "psv", "bus"));
restrictedValues.add("agricultural");
restrictedValues.add("forestry");
restrictedValues.add("no");
restrictedValues.add("restricted");
restrictedValues.add("delivery");
restrictedValues.add("military");
restrictedValues.add("emergency");

intendedValues.add("yes");
intendedValues.add("private");
intendedValues.add("permissive");

An example route that I’m looking at is this busway in Brisbane, Australia:

https://www.graphhopper.com/maps/?point=-27.47468%2C153.017895&point=-27.476898%2C153.019504&locale=en-US&vehicle=bus&weighting=fastest&elevation=true&layer=OpenStreetMap

It works fine on graphhopper.com using the bus vehicle, but mine looks like this:

Any help would be greatly appreciated!

Some technical information:

Data date: 2016-06-13T20:28:02Z
Import date: 2016-06-15T02:58:41Z
GH version: 0.8
Jar date: 2016-06-15T02:09:12Z

config.properties:

graph.flag_encoders=bus|block_fords=false
graph.bytes_for_flags=8
graph.elevation.provider=srtm
graph.elevation.cache_dir=./srtmprovider/
graph.elevation.dataaccess=MMAP
prepare.ch.weightings=fastest
prepare.threads=2
prepare.min_one_way_network_size=200
graph.dataaccess=RAM_STORE
osmreader.instructions=false
osmreader.way_point_max_distance=1

I’ve replaced my hacky copy-paste job with an overridden class. Here is the complete code for my bus encoder; I’m not a Java developer so please pardon any bad code. I still don’t know why it doesn’t work in the above example:

// vim: set expandtab:

package com.graphhopper.routing.util;

import com.graphhopper.reader.OSMRelation;
import com.graphhopper.reader.OSMWay;
import com.graphhopper.reader.osm.conditional.ConditionalTagsInspector;
import com.graphhopper.reader.osm.conditional.DateRangeParser;
import com.graphhopper.util.Helper;
import com.graphhopper.util.PMap;

import java.util.*;


public class BusFlagEncoder extends CarFlagEncoder
{
    public BusFlagEncoder()
    {
        super();
    }

    public BusFlagEncoder(PMap properties)
    {
        super(properties);
    }

    public BusFlagEncoder(String propertiesStr)
    {
        super(propertiesStr);
    }

    public BusFlagEncoder(int speedBits, double speedFactor, int maxTurnCosts)
    {
        super(speedBits, speedFactor, maxTurnCosts);
        restrictions.remove("motorcar");
        restrictions.add("psv");
        restrictions.add("bus");

        restrictedValues.remove("private");

        intendedValues.add("private");

        absoluteBarriers.remove("bus_trap");
        absoluteBarriers.remove("sump_buster");
    }

    @Override
    public String toString()
    {
        return "bus";
    }
}

Aha! My Java skills are shocking - I messed up the constructor inheritance. Also, I had to remove “no” as a restricted value; access == no doesn’t mean that psv != yes. Here is my bus code, for anyone else that might find it useful:

// vim: set expandtab:

package com.graphhopper.routing.util;

import com.graphhopper.reader.OSMRelation;
import com.graphhopper.reader.OSMWay;
import com.graphhopper.reader.osm.conditional.ConditionalTagsInspector;
import com.graphhopper.reader.osm.conditional.DateRangeParser;
import com.graphhopper.util.Helper;
import com.graphhopper.util.PMap;

import java.util.*;


public class BusFlagEncoder extends CarFlagEncoder
{
    public BusFlagEncoder()
    {
        this(5, 5, 0);
    }

    public BusFlagEncoder(PMap properties)
    {
        this(
                (int) properties.getLong("speed_bits", 5),
                properties.getDouble("speed_factor", 5),
                properties.getBool("turn_costs", false) ? 1 : 0
        );
        this.properties = properties;
        this.setBlockFords(properties.getBool("block_fords", true));
    }

    public BusFlagEncoder(String propertiesStr)
    {
        this(new PMap(propertiesStr));
    }

    public BusFlagEncoder(int speedBits, double speedFactor, int maxTurnCosts)
    {
        super(speedBits, speedFactor, maxTurnCosts);
        restrictions.remove("motorcar");
        restrictions.add("psv");
        restrictions.add("bus");

        restrictedValues.remove("no");
        restrictedValues.remove("private");

        absoluteBarriers.remove("bus_trap");
        absoluteBarriers.remove("sump_buster");
    }

    @Override
    public String toString()
    {
        return "bus";
    }
}
1 Like

Yes, we improved the bus vehicle profile a lot to consider several tagging situations, but it is not as easy as it seems. E.g. you have to take into account special psv or bus lanes and oneway restrictions which are accessible in the opposite directions for busses. The bus and truck vehicle profiles are not open source (yet), see our enterprise offering (no link here as it is the community where we want to avoid this ‘ads’). But as we improve the ‘flexibility mode’ more in the next release such custom profiles will be a lot easier, see https://github.com/graphhopper/graphhopper/pull/730

Ah yep, cool. Thanks! I’ve modified DefaultFlagEncoderFactory and FlagEncoderFactory to support bus and my other custom vehicle; I assume this won’t be necessary in the future?

Also, is it fairly safe to build the graph with multiple vehicles at once, and run them all in a single GH instance?

I assume this won’t be necessary in the future?

In the future you’ll do this via a configuration, no need to change a Java class. But how exactly is still open.

is it fairly safe to build the graph with multiple vehicles at once, and run them all in a single GH instance?

Yes, since some versions flex and speed mode support multiple vehicles.