Add extra parameter to each edge of graph

I’m very new to graphhopper, and am trying to use it for an android application I’m developing. I’d like to assign each road a “danger” factor (think some integer) such that I can then modify the routing to give a higher weight to more “dangerous” roads. I’ve spent several days looking over the sample code provided, but I’m struggling to understand how to implement this.

I understand that I need to create my own class MyGraphHopper that extends GraphHopper and override the createWeighting() function with my weighting function that would balance road distance/speed with danger. However, I don’t understand where and how I can add another int parameter (the danger) to be associate with each edge in the graph.

How can I associate a new integer value (the danger) with each edge in the graph graphhopper uses?

Thank you!

You can extend the FlagEncoder class and add the extra parameter intended in the applyWayTags method. Check out MotorcycleFlagEncoder class for reference where a curvature tag is added.

1 Like

Thank you! This was very helpful. What is the difference between handleWayTags and applyWayTags? In which of these functions do I update the value of my “danger” parameter.

I’ve included my code below where I hard-code the danger value to be “5” in both the handleWayTags and applyWayTags methods. Which is right, and does the code make sense? Thank you so much

public class DangerFlagEncoder extends CarFlagEncoder {
private EncodedValue dangerEncoder;

@Override
public int defineWayBits(int index, int shift) {
    // first two bits are reserved for route handling in superclass
    shift = super.defineWayBits(index, shift);
    //EncodedValue(String name, int shift, int bits, double factor, long defaultValue, int maxValue)
    dangerEncoder = new EncodedValue("Danger", shift, 4, 1, 0, 10);
    shift += dangerEncoder.getBits();
    return shift;
}
@Override
public long handleWayTags(ReaderWay way, long allowed, long priorityFromRelation) {
    long flags = super.handleWayTags(way, allowed, priorityFromRelation);
    //Add the danger level. Will update this later!
    flags = dangerEncoder.setValue(flags, 5);
    return flags;
}
@Override
public double getDouble(long flags, int key) {
    switch (key) {
        case DangerFlagEncoder.DANGER_KEY:
            //not sure why dividing by 10
            return (double) dangerEncoder.getValue(flags) / 10;
        default:
            return super.getDouble(flags, key);
    }
}
@Override
public void applyWayTags(ReaderWay way, EdgeIteratorState edge) {
    super.applyWayTags(way, edge);
    edge.setFlags(this.dangerEncoder.setValue(edge.getFlags(), 5));
}

}

Take a look at OSMReader and see where each of these methods is called. Your code looks correct to me. You don’t need to divide by 10 this depends on your implementation.

1 Like

Thanks for the pointer - read through OSMReader and makes more sense.

Now that I’ve created this new “DangerFlagEncoder” how do I make sure that this is the encoder that gets run?

Looking at GraphHopper.java, I see that setEncodingManager() is called in the init(CmdArgs args), but I can’t find where this function is called so I’m not sure how to define which encoder should be run. The alternative is that I can set the encoding manager in the MainActivity sample like so:

MyGraphHopper tmpHopp = new MyGraphHopper();
tmpHopp.setEncodingManager(new encodingManager(“danger”));
tmpHopp.forMobile();
tmpHopp.load(new File(mapsFolder, currentArea).getAbsolutePath() + “-gh”);

However, if I do this, do I also need to modify the DefaultFlagEncoderFactory so that it recognizes my DangerFlagEncoder?

Is this the right process and is there a better way?

Update: let’s say I make the toString method of the DangerFlagEncoder return “danger”. Then, if before i call hopper.rout(req), i call req.setVehicle(“danger”), then my DangerFlagEncoder should be selected.

However, the code crashes when I do this with the error “Cannot fetch best response if list is empty”. I’m assuming this is because DangerFlagEncoder is not being found and therefore there is no match between the “vehicle” and the relevant “encoder”. What do I need to do to make sure DangerFlagEncoder is included in the list of potential encoders?

You can specify the vehicles in the config.properties file.

Yes, I think so.

Looks like the right process.