Custom profile with shortest weight

Hi all,

Is it possible to have a custom profile with a shortest weight at the same time? If I remember correctly, I have read on the forum and some documentation on profiles that it is not possible. I thought I would ask on the forum again.

The reason why I am asking is because I want to create a custom profile where a vehicle takes the shortest distance, but also prefers roads with a specific encoded_value.

For example, in the screenshot below, the top profile (name: shortest) is a standard car profile that prefers the shortest distances. The custom profile below (name: short_easy) prefers routes based on the priority weighting assigned to the routing_priority encoded value. Is it possible to add to this custom profile that the shortest distance must be taken as well as roads as defined by the priority weighting assigned to routing_priority?

You can use the custom weighting and increase the distance_influence parameter to prefer shorter routes: https://github.com/graphhopper/graphhopper/blob/master/docs/core/custom-models.md#customizing-distance_influence

Thank you for the reply @easbar.

Is it perhaps possible to do this without using distance_influence, i.e., leave distance_infleunce: 0?

For example, can I extend ShorttestWeighting.java and add something like:

“if routing_priroty == 4 then PRIORITY = 1”,
“if routing_priroty == 3 then PRIORITY = 0.8”,
“if routing_priroty == 2 then PRIORITY = 0.6”,
“if routing_priroty == 1 then PRIORITY = 0.4”,
“if routing_priroty == 0 then PRIORITY = 0.2”

image

You can use the custom rules only with the CustomWeighting or you extend ShortestWeighting but this is not recommended. I would even go so far that we could deprecate ShortestWeighting as often this is requested but not what users need. E.g. do you really want to use a shortcut of e.g. 1km when it takes 5 hours longer? (could happen for ferries or less extreme for living streets etc)

A “shortest” Weighting with a priority is not really a “shortest” anymore and more similar to a CustomWeighting with a very high distance_influence IMO.

Thank you for your response @karussell

I want to build four different profiles and compare them on the web interface. These four are, “shortest”, “fastest”, “shortest RP” that uses my routing_priority encoded value and “fastest RP” with the same routing_priority EV.

For “Shortest” I use the basic shortest distance standard profile. Where I have:

  • Speed = 1 (using my maxspeed EV for each road_segment)
  • Priority = 1
  • Distance_influence = 0

For “Fastest” use the basic shortest distance standard profile. Where I have:

  • Speed = 1 (using my maxspeed EV for each road_segment)
  • Priority = 1
  • Distance_influence = 0

For “shortest RP” I would like to do a modified shortest distance profile which will also consider the road priority (my routing_priority EV)

For “fastest RP” I would like to do a modified fastest time profile that will use the speed of each road segment to calculate the fastest route between two points and it will also take the priority of a road into account**

This is what I have so far:

profiles:
- name: shortest
vehicle: car
weighting: shortest
distance_factor : 0

- name: fastest
  vehicle: car
  weighting: fastest
  distance_factor : 0

- name: fast_easy (aka fastest_RP)
  vehicle: car
  weighting: custom
  distance_factor : 0
  custom_model: {

“speed”: [
{
“if”: “max_speed > 0”, “multiply_by”: 1
}
],
“priority”: [
{
“if”: “max_speed > 0”, “multiply_by”: 1
},
{
“if”: “routing_priority == 4”, “multiply_by”: 1
},
{
“else_if”: “routing_priority == 3”, “multiply_by”: 0.8
},
{
“else_if”: “routing_priority == 2”, “multiply_by”: 0.6
},
{
“else_if”: “routing_priority == 1”, “multiply_by”: 0.4
},
{
“else”: “”, “multiply_by”: 0.2
}
],
“distance_influence”: 0
}

distance_factor is only considered for short_fastest weighting it is ignored for all the other weightings.

I still recommend you to use the custom weighting for all your weightings. And to consider the distance use different values for distance_influence in the custom_model - see the documentation: https://github.com/graphhopper/graphhopper/blob/master/docs/core/custom-models.md

A value of 30 means that one extra kilometer of detour must save you 30s of travelling time or else you are not willing to take the detour. Or to put it another way, if a reference route takes 600s and is 10km long, distance_influence=30 means that you are willing to take an alternative route that is 11km long only if it takes no longer than 570s (saves 30s)

Thank you for the suggestion @karussell.

Perhaps let me give a bit more context to what I want to achieve.

Our data set has been built from GPS data and for this reason we have defined explicit SPEED and PRIORITY values (routing_priority) for each road segment (edge). We currently compile this data set for use on Garmin devices as well as iGO and we get very similar route selection and travel time results. These results have been field tested over decades and are adjusted over time to reflect changing road conditions. We would really want to use these values in our weighting.

We tried using custom models but this simply modifies the values which are already baked into the graph, whereas we would like to bake our own SPEED and PRIORITY into the graph.

We understand that the true Shortest Distance comes at the risk of taking a road which will take extremely long to drive, however we provide navigation to people who often need to negotiate a maze of off road tracks and then the true shortest distance could be very useful. And in offering this we need to be sure that we are calculating the true shortest distance. Our implementation will most probably not serve a single route to the user, we will serve more than one option for comparison. Over longer distances we want to offer Short Easy (distance/priority) as an alternative. We intend experimenting with distance influence only once we achieve the theoretical correct routes which we can compare with our field data.

For Fastest we would like to use distance/speed (priority = 1) and for Fast Easy we will use distance/(speed x Priority) and again serve both to the user for comparison.

So the question really is if there is a way to create a graph where one can simply specify the SPEED and PRIORITY per edge from a Tag that we already have populated for each edge?

Then you have to implement your own Weighting - see our documentation on how to do this. We currently do not support setting the speed or priority value in CustomWeighting (e.g. via a new set_to operator).

Thank you @karussell

… or your own FlagEncoder. For example BikeCommonFlagEncoder uses the avgSpeedEnc and the priorityEnc to set the speeds and priorities that are used in e.g. the FastestWeighting. But not sure what you mean here:

from a Tag that we already have populated for each edge?

Did you set this tag for each (GraphHopper) edge or each OSM way? For the former you could just use this in your own Weighting implementation as karussell suggested, for the latter the next step would be using this tag to set the speed/priority encoded values on the according GraphHopper edges, which is done in FlagEncoder. We are working on making this easier to use/modify by the way.

Hi @easbar

Thank you for the suggestions. I will have a look at BikeCommonFlagEncoder.

We set speed and routing_priority tags for each edge.

Thanks for you continuous improvements on your products.

I have extended the shortest weighting to create my custom ShortestEasy weighting with routing_priority. I have followed this document as you suggested @karussell:

However, I am getting these errors. Weighting, HintsMap and Graph cannot be found:

[ERROR] /home/t4a/Downloads/graphhopper-4.x/core/src/main/java/com/graphhopper/routing/weighting/ShortestEasyWeighting.java:[82,37] error: cannot find symbol
[ERROR] symbol: class HintsMap
[ERROR] location: class ShortestEasyWeighting
[ERROR] /home/t4a/Downloads/graphhopper-4.x/core/src/main/java/com/graphhopper/routing/weighting/ShortestEasyWeighting.java:[82,77] error: cannot find symbol
[ERROR] symbol: class Graph
[ERROR] location: class ShortestEasyWeighting
[ERROR] /home/t4a/Downloads/graphhopper-4.x/core/src/main/java/com/graphhopper/routing/weighting/ShortestEasyWeighting.java:[82,11] error: cannot find symbol
[ERROR] symbol: class Weighting
[ERROR] location: class ShortestEasyWeighting

I am not sure where I can find these to import or perhaps I am missing something else. Here is the code:

package com.graphhopper.routing;
import com.graphhopper.reader.ReaderWay;
import com.graphhopper.routing.util.FlagEncoder;
import com.graphhopper.routing.util.CarFlagEncoder;
import com.graphhopper.util.EdgeIteratorState;
import com.graphhopper.routing.weighting.ShortestWeighting;

public class ShortestEasyWeighting extends ShortestWeighting {
protected double maxSpeed;
protected double routingPriority;

protected double maxSpeed(ReaderWay way){
    String maxspeedValue = way.getTag("maxspeed");
    return maxSpeed;
}

protected double routingPriority(ReaderWay way){                                
        String routing_priorityValue = way.getTag("routing_priority");
    return routingPriority;
}

//public ShortestEasyWeighting(FlagEncoder flagEncoder, CarFlagEncoder carFlagEncoder) {
public ShortestEasyWeighting(FlagEncoder flagEncoder) {

    super(flagEncoder);
   // maxSpeed = carFlagEncoder.getMaxSpeed();
 //   routingPriority = carFlagEncoder.getRoutingPriority();

}

@Override
public double getMinWeight(double currDistToGoal) {
    return currDistToGoal;
}



//@Override
public double calcWeight(EdgeIteratorState edgeState, boolean reverse, int prevOrNextEdgeId) {
    //return edgeState.getDistance();
    return edgeState.getDistance() / (maxSpeed * routingPriority);
}

//@Override
public Weighting createWeighting(HintsMap hintsMap, FlagEncoder encoder, Graph graph) {
    String weightingStr = hintsMap.getWeighting().toLowerCase();
    if ("short_easy".equals(weightingStr)) {
        return new ShortestEasyWeighting(encoder);
    } else {
        return super.createWeighting(hintsMap, encoder, graph);
    }
}

@Override
public String getName() {
    return "short_easy";
}

}

Powered by Discourse