Skip to content

Commit

Permalink
Merge branch 'refs/heads/master' into noisyRoadNearby
Browse files Browse the repository at this point in the history
# Conflicts:
#	core/src/test/java/com/graphhopper/routing/TrafficChangeWithNodeOrderingReusingTest.java
  • Loading branch information
ratrun committed Aug 30, 2024
2 parents d164276 + aade9fa commit 00a5383
Show file tree
Hide file tree
Showing 38 changed files with 127 additions and 399 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
### 10.0 [not yet released]

- the default u-turn time is now 0, the default u-turn weight is still infinite
- turn restriction support for restrictions with overlapping and/or multiple via-edges/ways, #3030
- constructor of BaseGraph.Builder uses byte instead of integer count.
- KeyValue is now KValue as it holds the value only. Note, the two parameter constructor uses one value for the forward and one for the backward direction (and no longer "key, value")
Expand Down
1 change: 1 addition & 0 deletions core/src/main/java/com/graphhopper/config/Profile.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.graphhopper.util.CustomModel;
import com.graphhopper.util.Helper;
import com.graphhopper.util.PMap;
import com.graphhopper.util.TurnCostsConfig;

/**
* Corresponds to an entry of the `profiles` section in `config.yml` and specifies the properties of a routing profile.
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/java/com/graphhopper/routing/Router.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@

import java.util.*;

import static com.graphhopper.config.TurnCostsConfig.INFINITE_U_TURN_COSTS;
import static com.graphhopper.util.TurnCostsConfig.INFINITE_U_TURN_COSTS;
import static com.graphhopper.util.DistanceCalcEarth.DIST_EARTH;
import static com.graphhopper.util.Parameters.Algorithms.ALT_ROUTE;
import static com.graphhopper.util.Parameters.Algorithms.ROUND_TRIP;
Expand Down Expand Up @@ -580,7 +580,7 @@ protected FlexiblePathCalculator createPathCalculator(QueryGraph queryGraph) {
throw new IllegalArgumentException("Cannot find LM preparation for the requested profile: '" + profile.getName() + "'" +
"\nYou can try disabling LM using " + Parameters.Landmark.DISABLE + "=true" +
"\navailable LM profiles: " + landmarks.keySet());
if (request.getCustomModel() != null && !request.getHints().getBool("lm.disable", false))
if (request.getCustomModel() != null)
FindMinMax.checkLMConstraints(profile.getCustomModel(), request.getCustomModel(), lookup);
RoutingAlgorithmFactory routingAlgorithmFactory = new LMRoutingAlgorithmFactory(landmarkStorage).setDefaultActiveLandmarks(routerConfig.getActiveLandmarkCount());
return new FlexiblePathCalculator(queryGraph, routingAlgorithmFactory, weighting, getAlgoOpts());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.graphhopper.util.Helper.createFormatter;
Expand Down Expand Up @@ -120,19 +118,18 @@ public Map<String, PrepareContractionHierarchies.Result> prepare(BaseGraph baseG
return Collections.emptyMap();
}
LOGGER.info("Creating CH preparations, {}", getMemInfo());
List<PrepareContractionHierarchies> preparations = chConfigs.stream()
.map(c -> createCHPreparation(baseGraph, c))
.collect(Collectors.toList());
Map<String, PrepareContractionHierarchies.Result> results = Collections.synchronizedMap(new LinkedHashMap<>());
List<Runnable> runnables = new ArrayList<>(preparations.size());
for (int i = 0; i < preparations.size(); ++i) {
PrepareContractionHierarchies prepare = preparations.get(i);
LOGGER.info((i + 1) + "/" + preparations.size() + " calling " +
"CH prepare.doWork for profile '" + prepare.getCHConfig().getName() + "' " + prepare.getCHConfig().getTraversalMode() + " ... (" + getMemInfo() + ")");
List<Runnable> runnables = new ArrayList<>(chConfigs.size());
for (int i = 0; i < chConfigs.size(); ++i) {
CHConfig chConfig = chConfigs.get(i);
LOGGER.info((i + 1) + "/" + chConfigs.size() + " Setting up CH preparation for profile " +
"'" + chConfig.getName() + "' " + chConfig.getTraversalMode() + " ... (" + getMemInfo() + ")");
runnables.add(() -> {
final String name = prepare.getCHConfig().getName();
final String name = chConfig.getName();
// toString is not taken into account so we need to cheat, see http://stackoverflow.com/q/6113746/194609 for other options
Thread.currentThread().setName(name);
PrepareContractionHierarchies prepare = PrepareContractionHierarchies.fromGraph(baseGraph, chConfig);
prepare.setParams(pMap);
PrepareContractionHierarchies.Result result = prepare.doWork();
results.put(name, result);
prepare.flush();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,22 +169,16 @@ private boolean isEdgeBased() {
}

private void initFromGraph() {
// todo: this whole chain of initFromGraph() methods is just needed because PrepareContractionHierarchies does
// not simply prepare contraction hierarchies, but instead it also serves as some kind of 'container' to give
// access to the preparations in the GraphHopper class. If this was not so we could make this a lot cleaner here,
// declare variables final and would not need all these close() methods...
logger.info("Creating CH prepare graph, {}", getMemInfo());
CHPreparationGraph prepareGraph;
if (chConfig.getTraversalMode().isEdgeBased()) {
TurnCostStorage turnCostStorage = graph.getTurnCostStorage();
if (turnCostStorage == null) {
if (turnCostStorage == null)
throw new IllegalArgumentException("For edge-based CH you need a turn cost storage");
}
logger.info("Creating CH prepare graph, {}", getMemInfo());
CHPreparationGraph.TurnCostFunction turnCostFunction = CHPreparationGraph.buildTurnCostFunctionFromTurnCostStorage(graph, chConfig.getWeighting());
prepareGraph = CHPreparationGraph.edgeBased(graph.getNodes(), graph.getEdges(), turnCostFunction);
nodeContractor = new EdgeBasedNodeContractor(prepareGraph, chBuilder, pMap);
} else {
logger.info("Creating CH prepare graph, {}", getMemInfo());
prepareGraph = CHPreparationGraph.nodeBased(graph.getNodes(), graph.getEdges());
nodeContractor = new NodeBasedNodeContractor(prepareGraph, chBuilder, pMap);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public class NameSimilarityEdgeFilter implements EdgeFilter {
"ally", "alley",
"arc", "arcade",
"bvd", "bvd.", "boulevard",
"av.", "avenue", "avenida",
"av.", "avenue", "avenida", "ave",
"calle",
"cl.", "close",
"crescend", "cres", "cres.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ public Toll getToll(ReaderWay readerWay, Toll currentToll) {
return currentToll;
}

return Toll.NO;
return Toll.HGV;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,9 @@ public Toll getToll(ReaderWay readerWay, Toll currentToll) {
}

RoadClass roadClass = RoadClass.find(readerWay.getTag("highway", ""));
switch (roadClass) {
case MOTORWAY:
case TRUNK:
return Toll.ALL;
default:
return currentToll;
}
return switch (roadClass) {
case MOTORWAY, TRUNK -> Toll.ALL;
default -> Toll.HGV;
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,9 @@ public void handleWayTags(int edgeId, EdgeIntAccess edgeIntAccess, ReaderWay way
speed = PUSHING_SECTION_SPEED;
} else if (pushingSectionsHighways.contains(highwayValue)) {
if (way.hasTag("bicycle", "designated") || way.hasTag("bicycle", "official") || way.hasTag("segregated", "yes")
|| CYCLEWAY_KEYS.stream().anyMatch(k -> way.getTag(k, "").equals("track")))
speed = highwaySpeeds.get("cycleway");
|| CYCLEWAY_KEYS.stream().anyMatch(k -> way.getTag(k, "").equals("track"))) {
speed = trackTypeSpeeds.getOrDefault(trackTypeValue, highwaySpeeds.get("cycleway"));
}
else if (way.hasTag("bicycle", "yes"))
speed = 12;
}
Expand All @@ -160,7 +161,8 @@ else if (way.hasTag("bicycle", "yes"))
speed = PUSHING_SECTION_SPEED; // unknown surface
} else if (way.hasTag("service")) {
speed = highwaySpeeds.get("living_street");
} else if ("track".equals(highwayValue)) {
} else if ("track".equals(highwayValue) ||
"bridleway".equals(highwayValue) ) {
if (surfaceSpeed != null)
speed = surfaceSpeed;
else if (trackTypeSpeeds.containsKey(trackTypeValue))
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@

package com.graphhopper.routing.weighting;

import com.graphhopper.config.TurnCostsConfig;
import com.graphhopper.util.TurnCostsConfig;
import com.graphhopper.routing.ev.BooleanEncodedValue;
import com.graphhopper.storage.TurnCostStorage;
import com.graphhopper.util.EdgeIterator;

import static com.graphhopper.config.TurnCostsConfig.INFINITE_U_TURN_COSTS;
import static com.graphhopper.util.TurnCostsConfig.INFINITE_U_TURN_COSTS;

public class DefaultTurnCostProvider implements TurnCostProvider {
private final BooleanEncodedValue turnRestrictionEnc;
Expand Down Expand Up @@ -75,7 +75,12 @@ public double calcTurnWeight(int edgeFrom, int nodeVia, int edgeTo) {

@Override
public long calcTurnMillis(int inEdge, int viaNode, int outEdge) {
return (long) (1000 * calcTurnWeight(inEdge, viaNode, outEdge));
// Making a proper assumption about the turn time is very hard. Assuming zero is the
// simplest way to deal with this. This also means the u-turn time is zero. Provided that
// the u-turn weight is large enough, u-turns only occur in special situations like curbsides
// pointing to the end of dead-end streets where it is unclear if a finite u-turn time would
// be a good choice.
return 0;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,38 +71,49 @@ public double calcTurnWeight(int inEdge, int viaNode, int outEdge) {
return 0;
}
}
return getMinWeightAndOriginalEdges(inEdge, viaNode, outEdge).minTurnWeight;
}

private Result getMinWeightAndOriginalEdges(int inEdge, int viaNode, int outEdge) {
// to calculate the actual turn costs or detect u-turns we need to look at the original edge of each virtual
// edge, see #1593
Result result = new Result();
if (isVirtualEdge(inEdge) && isVirtualEdge(outEdge)) {
var minTurnWeight = new Object() {
double value = Double.POSITIVE_INFINITY;
};
EdgeExplorer innerExplorer = graph.createEdgeExplorer();
graph.forEdgeAndCopiesOfEdge(graph.createEdgeExplorer(), viaNode, getOriginalEdge(inEdge), p -> {
graph.forEdgeAndCopiesOfEdge(innerExplorer, viaNode, getOriginalEdge(outEdge), q -> {
minTurnWeight.value = Math.min(minTurnWeight.value, weighting.calcTurnWeight(p, viaNode, q));
double w = weighting.calcTurnWeight(p, viaNode, q);
if (w < result.minTurnWeight) {
result.origInEdge = p;
result.origOutEdge = q;
result.minTurnWeight = w;
}
});
});
return minTurnWeight.value;
} else if (isVirtualEdge(inEdge)) {
var minTurnWeight = new Object() {
double value = Double.POSITIVE_INFINITY;
};
graph.forEdgeAndCopiesOfEdge(graph.createEdgeExplorer(), viaNode, getOriginalEdge(inEdge), e -> {
minTurnWeight.value = Math.min(minTurnWeight.value, weighting.calcTurnWeight(e, viaNode, outEdge));
double w = weighting.calcTurnWeight(e, viaNode, outEdge);
if (w < result.minTurnWeight) {
result.origInEdge = e;
result.origOutEdge = outEdge;
result.minTurnWeight = w;
}
});
return minTurnWeight.value;
} else if (isVirtualEdge(outEdge)) {
var minTurnWeight = new Object() {
double value = Double.POSITIVE_INFINITY;
};
graph.forEdgeAndCopiesOfEdge(graph.createEdgeExplorer(), viaNode, getOriginalEdge(outEdge), e -> {
minTurnWeight.value = Math.min(minTurnWeight.value, weighting.calcTurnWeight(inEdge, viaNode, e));
double w = weighting.calcTurnWeight(inEdge, viaNode, e);
if (w < result.minTurnWeight) {
result.origInEdge = inEdge;
result.origOutEdge = e;
result.minTurnWeight = w;
}
});
return minTurnWeight.value;
} else {
return weighting.calcTurnWeight(inEdge, viaNode, outEdge);
result.origInEdge = inEdge;
result.origOutEdge = outEdge;
result.minTurnWeight = weighting.calcTurnWeight(inEdge, viaNode, outEdge);
}
return result;
}

private boolean isUTurn(int inEdge, int outEdge) {
Expand All @@ -116,8 +127,15 @@ public long calcEdgeMillis(EdgeIteratorState edgeState, boolean reverse) {

@Override
public long calcTurnMillis(int inEdge, int viaNode, int outEdge) {
// todo: here we do not allow calculating turn weights that aren't turn times, also see #1590
return (long) (1000 * calcTurnWeight(inEdge, viaNode, outEdge));
if (isVirtualNode(viaNode))
// see calcTurnWeight
return 0;
else {
// we want the turn time given by the actual weighting for the edges with minimum weight
// (the same ones that would be selected when routing)
Result result = getMinWeightAndOriginalEdges(inEdge, viaNode, outEdge);
return weighting.calcTurnMillis(result.origInEdge, viaNode, result.origOutEdge);
}
}

@Override
Expand Down Expand Up @@ -146,4 +164,10 @@ private boolean isVirtualNode(int node) {
private boolean isVirtualEdge(int edge) {
return edge >= firstVirtualEdgeId;
}

private static class Result {
int origInEdge = -1;
int origOutEdge = -1;
double minTurnWeight = Double.POSITIVE_INFINITY;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// to use this custom model you need to set the following option in the config.yml
// graph.elevation.provider: srtm # enables elevation
// graph.encoded_values: bike_priority, bike_access, roundabout, bike_average_speed, average_slope
// profiles:
// - name: bike
// custom_model_files: [bike.json, bike_elevation.json]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// to use this custom model you need to set the following option in the config.yml
// graph.encoded_values: max_weight, max_width, max_height, bus_access, road_class, car_average_speed
// profiles:
// - name: bus
// custom_model_files: [bus.json]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// to use this custom model you need to set the following option in the config.yml
// graph.encoded_values: car_access, car_average_speed
// profiles:
// - name: car
// turn_costs:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// to use this custom model you need to set the following option in the config.yml
// graph.encoded_values: car_access, car_average_speed, track_type
// profiles:
// - name: car4wd
// custom_model_files: [car4wd.json]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// to use this custom model you need to set the following option in the config.yml
// graph.elevation.provider: srtm # enables elevation
// graph.encoded_values: foot_access, hike_rating, foot_priority, foot_average_speed, average_slope
// profiles:
// - name: foot
// custom_model_files: [foot.json, foot_elevation.json]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// to use this custom model you set the following option in the config.yml:
// graph.elevation.provider: srtm # enables elevation
// graph.encoded_values: foot_access, hike_rating, foot_priority, foot_network, foot_average_speed, average_slope
// profiles:
// - name: hike
// custom_model_files: [hike.json, foot_elevation.json]
Expand Down
Loading

0 comments on commit 00a5383

Please sign in to comment.