use of com.graphhopper.routing.weighting.Weighting in project graphhopper by graphhopper.
the class CHPreparationGraph method buildTurnCostFunctionFromTurnCostStorage.
/**
* Builds a turn cost function for a given graph('s turn cost storage) and a weighting.
* The trivial implementation would be simply returning {@link Weighting#calcTurnWeight}. However, it turned out
* that reading all turn costs for the current encoder and then storing them in separate arrays upfront speeds up
* edge-based CH preparation by about 25%. See #2084
*/
public static TurnCostFunction buildTurnCostFunctionFromTurnCostStorage(Graph graph, Weighting weighting) {
FlagEncoder encoder = weighting.getFlagEncoder();
String key = TurnCost.key(encoder.toString());
if (!encoder.hasEncodedValue(key))
return (inEdge, viaNode, outEdge) -> 0;
DecimalEncodedValue turnCostEnc = encoder.getDecimalEncodedValue(key);
TurnCostStorage turnCostStorage = graph.getTurnCostStorage();
// we maintain a list of inEdge/outEdge/turn-cost triples (we use two arrays for this) that is sorted by nodes
LongArrayList turnCostEdgePairs = new LongArrayList();
DoubleArrayList turnCosts = new DoubleArrayList();
// for each node we store the index of the first turn cost entry/triple in the list
final int[] turnCostNodes = new int[graph.getNodes() + 1];
TurnCostStorage.TurnRelationIterator tcIter = turnCostStorage.getAllTurnRelations();
int lastNode = -1;
while (tcIter.next()) {
int viaNode = tcIter.getViaNode();
if (viaNode < lastNode)
throw new IllegalStateException();
long edgePair = BitUtil.LITTLE.combineIntsToLong(tcIter.getFromEdge(), tcIter.getToEdge());
// note that as long as we only use OSM turn restrictions all the turn costs are infinite anyway
double turnCost = tcIter.getCost(turnCostEnc);
int index = turnCostEdgePairs.size();
turnCostEdgePairs.add(edgePair);
turnCosts.add(turnCost);
if (viaNode != lastNode) {
for (int i = lastNode + 1; i <= viaNode; i++) {
turnCostNodes[i] = index;
}
}
lastNode = viaNode;
}
for (int i = lastNode + 1; i <= turnCostNodes.length - 1; i++) {
turnCostNodes[i] = turnCostEdgePairs.size();
}
turnCostNodes[turnCostNodes.length - 1] = turnCostEdgePairs.size();
// currently the u-turn costs are the same for all junctions, so for now we just get them for one of them
double uTurnCosts = weighting.calcTurnWeight(1, 0, 1);
return (inEdge, viaNode, outEdge) -> {
if (!EdgeIterator.Edge.isValid(inEdge) || !EdgeIterator.Edge.isValid(outEdge))
return 0;
else if (inEdge == outEdge)
return uTurnCosts;
// traverse all turn cost entries we have for this viaNode and return the turn costs if we find a match
for (int i = turnCostNodes[viaNode]; i < turnCostNodes[viaNode + 1]; i++) {
long l = turnCostEdgePairs.get(i);
if (inEdge == BitUtil.LITTLE.getIntLow(l) && outEdge == BitUtil.LITTLE.getIntHigh(l))
return turnCosts.get(i);
}
return 0;
};
}
use of com.graphhopper.routing.weighting.Weighting in project graphhopper by graphhopper.
the class LowLevelAPIExample method useContractionHierarchiesToMakeQueriesFaster.
public static void useContractionHierarchiesToMakeQueriesFaster() {
// Creating and saving the graph
FlagEncoder encoder = new CarFlagEncoder();
EncodingManager em = EncodingManager.create(encoder);
Weighting weighting = new FastestWeighting(encoder);
CHConfig chConfig = CHConfig.nodeBased("my_profile", weighting);
GraphHopperStorage graph = new GraphBuilder(em).setRAM(graphLocation, true).create();
graph.flush();
// Set node coordinates and build location index
NodeAccess na = graph.getNodeAccess();
graph.edge(0, 1).set(encoder.getAccessEnc(), true).set(encoder.getAverageSpeedEnc(), 10).setDistance(1020);
na.setNode(0, 15.15, 20.20);
na.setNode(1, 15.25, 20.21);
// Prepare the graph for fast querying ...
graph.freeze();
PrepareContractionHierarchies pch = PrepareContractionHierarchies.fromGraphHopperStorage(graph, chConfig);
PrepareContractionHierarchies.Result pchRes = pch.doWork();
RoutingCHGraph chGraph = graph.createCHGraph(pchRes.getCHStorage(), pchRes.getCHConfig());
// create location index
LocationIndexTree index = new LocationIndexTree(graph, graph.getDirectory());
index.prepareIndex();
// calculate a path with location index
Snap fromSnap = index.findClosest(15.15, 20.20, EdgeFilter.ALL_EDGES);
Snap toSnap = index.findClosest(15.25, 20.21, EdgeFilter.ALL_EDGES);
QueryGraph queryGraph = QueryGraph.create(graph, fromSnap, toSnap);
BidirRoutingAlgorithm algo = new CHRoutingAlgorithmFactory(chGraph, queryGraph).createAlgo(new PMap());
Path path = algo.calcPath(fromSnap.getClosestNode(), toSnap.getClosestNode());
assert Helper.round(path.getDistance(), -2) == 1000;
}
use of com.graphhopper.routing.weighting.Weighting in project graphhopper by graphhopper.
the class LowLevelAPIExample method createAndSaveGraph.
public static void createAndSaveGraph() {
FlagEncoder encoder = new CarFlagEncoder();
EncodingManager em = EncodingManager.create(encoder);
GraphHopperStorage graph = new GraphBuilder(em).setRAM(graphLocation, true).create();
// Make a weighted edge between two nodes and set average speed to 50km/h
EdgeIteratorState edge = graph.edge(0, 1).setDistance(1234).set(encoder.getAverageSpeedEnc(), 50);
// Set node coordinates and build location index
NodeAccess na = graph.getNodeAccess();
graph.edge(0, 1).set(encoder.getAccessEnc(), true).set(encoder.getAverageSpeedEnc(), 10).setDistance(1530);
na.setNode(0, 15.15, 20.20);
na.setNode(1, 15.25, 20.21);
LocationIndexTree index = new LocationIndexTree(graph, graph.getDirectory());
index.prepareIndex();
// Flush the graph and location index to disk
graph.flush();
index.flush();
graph.close();
index.close();
// Load the graph ... can be also in a different code location
graph = new GraphBuilder(em).setRAM(graphLocation, true).build();
graph.loadExisting();
// Load the location index
index = new LocationIndexTree(graph.getBaseGraph(), graph.getDirectory());
if (!index.loadExisting())
throw new IllegalStateException("location index cannot be loaded!");
// calculate with location index
Snap fromSnap = index.findClosest(15.15, 20.20, EdgeFilter.ALL_EDGES);
Snap toSnap = index.findClosest(15.25, 20.21, EdgeFilter.ALL_EDGES);
QueryGraph queryGraph = QueryGraph.create(graph, fromSnap, toSnap);
Weighting weighting = new FastestWeighting(encoder);
Path path = new Dijkstra(queryGraph, weighting, TraversalMode.NODE_BASED).calcPath(fromSnap.getClosestNode(), toSnap.getClosestNode());
assert Helper.round(path.getDistance(), -2) == 1500;
// calculate without location index (get the fromId and toId nodes from other code parts)
path = new Dijkstra(graph, weighting, TraversalMode.NODE_BASED).calcPath(0, 1);
assert Helper.round(path.getDistance(), -2) == 1500;
}
use of com.graphhopper.routing.weighting.Weighting in project graphhopper by graphhopper.
the class RoutingAlgorithmTest method testTwoWeightsPerEdge2.
@ParameterizedTest
@ArgumentsSource(FixtureProvider.class)
public void testTwoWeightsPerEdge2(Fixture f) {
// other direction should be different!
Weighting fakeWeighting = new Weighting() {
private final Weighting tmpW = new FastestWeighting(f.carEncoder);
@Override
public FlagEncoder getFlagEncoder() {
return f.carEncoder;
}
@Override
public double getMinWeight(double distance) {
return 0.8 * distance;
}
@Override
public final double calcEdgeWeight(EdgeIteratorState edgeState, boolean reverse) {
int adj = edgeState.getAdjNode();
int base = edgeState.getBaseNode();
if (reverse) {
int tmp = base;
base = adj;
adj = tmp;
}
// a 'hill' at node 6
if (adj == 6)
return 3 * edgeState.getDistance();
else if (base == 6)
return edgeState.getDistance() * 0.9;
else if (adj == 4)
return 2 * edgeState.getDistance();
return edgeState.getDistance() * 0.8;
}
@Override
public final long calcEdgeMillis(EdgeIteratorState edgeState, boolean reverse) {
return tmpW.calcEdgeMillis(edgeState, reverse);
}
@Override
public double calcTurnWeight(int inEdge, int viaNode, int outEdge) {
return tmpW.calcTurnWeight(inEdge, viaNode, outEdge);
}
@Override
public long calcTurnMillis(int inEdge, int viaNode, int outEdge) {
return tmpW.calcTurnMillis(inEdge, viaNode, outEdge);
}
@Override
public boolean hasTurnCosts() {
return tmpW.hasTurnCosts();
}
@Override
public String getName() {
return "custom";
}
@Override
public String toString() {
return tmpW.getFlagEncoder().toString() + "_" + getName();
}
};
GraphHopperStorage graph = f.createGHStorage(true);
initEleGraph(graph, f.carEncoder, 60);
Path p = f.calcPath(graph, 0, 10);
assertEquals(nodes(0, 4, 6, 10), p.calcNodes());
graph = f.createGHStorage(true);
initEleGraph(graph, f.carEncoder, 60);
p = f.calcPath(graph, fakeWeighting, 3, 0, 10, 9);
assertEquals(nodes(12, 0, 1, 2, 11, 7, 10, 13), p.calcNodes());
assertEquals(37009621, p.getTime());
assertEquals(616827, p.getDistance(), 1);
assertEquals(493462, p.getWeight(), 1);
}
use of com.graphhopper.routing.weighting.Weighting in project graphhopper by graphhopper.
the class RandomCHRoutingTest method runRandomTest.
private void runRandomTest(Fixture f, Random rnd, int numVirtualNodes) {
LocationIndexTree locationIndex = new LocationIndexTree(f.graph, f.dir);
locationIndex.prepareIndex();
f.freeze();
PrepareContractionHierarchies pch = PrepareContractionHierarchies.fromGraphHopperStorage(f.graph, f.chConfig);
PrepareContractionHierarchies.Result res = pch.doWork();
RoutingCHGraph chGraph = f.graph.createCHGraph(res.getCHStorage(), res.getCHConfig());
int numQueryGraph = 25;
for (int j = 0; j < numQueryGraph; j++) {
// add virtual nodes and edges, because they can change the routing behavior and/or produce bugs, e.g.
// when via-points are used
List<Snap> snaps = createRandomSnaps(f.graph.getBounds(), locationIndex, rnd, numVirtualNodes, false, EdgeFilter.ALL_EDGES);
QueryGraph queryGraph = QueryGraph.create(f.graph, snaps);
int numQueries = 100;
int numPathsNotFound = 0;
List<String> strictViolations = new ArrayList<>();
for (int i = 0; i < numQueries; i++) {
int from = rnd.nextInt(queryGraph.getNodes());
int to = rnd.nextInt(queryGraph.getNodes());
Weighting w = queryGraph.wrapWeighting(f.weighting);
// using plain dijkstra instead of bidirectional, because of #1592
RoutingAlgorithm refAlgo = new Dijkstra(queryGraph, w, f.traversalMode);
Path refPath = refAlgo.calcPath(from, to);
double refWeight = refPath.getWeight();
QueryRoutingCHGraph routingCHGraph = new QueryRoutingCHGraph(chGraph, queryGraph);
RoutingAlgorithm algo = new CHRoutingAlgorithmFactory(routingCHGraph).createAlgo(new PMap().putObject("stall_on_demand", true));
Path path = algo.calcPath(from, to);
if (refPath.isFound() && !path.isFound())
fail("path not found for " + from + "->" + to + ", expected weight: " + refWeight);
assertEquals(refPath.isFound(), path.isFound());
if (!path.isFound()) {
numPathsNotFound++;
continue;
}
double weight = path.getWeight();
if (Math.abs(refWeight - weight) > 1.e-2) {
LOGGER.warn("expected: " + refPath.calcNodes());
LOGGER.warn("given: " + path.calcNodes());
fail("wrong weight: " + from + "->" + to + ", dijkstra: " + refWeight + " vs. ch: " + path.getWeight());
}
if (Math.abs(path.getDistance() - refPath.getDistance()) > 1.e-1) {
strictViolations.add("wrong distance " + from + "->" + to + ", expected: " + refPath.getDistance() + ", given: " + path.getDistance());
}
if (Math.abs(path.getTime() - refPath.getTime()) > 50) {
strictViolations.add("wrong time " + from + "->" + to + ", expected: " + refPath.getTime() + ", given: " + path.getTime());
}
}
if (numPathsNotFound > 0.9 * numQueries) {
fail("Too many paths not found: " + numPathsNotFound + "/" + numQueries);
}
if (strictViolations.size() > 0.05 * numQueries) {
fail("Too many strict violations: " + strictViolations.size() + "/" + numQueries + "\n" + Helper.join("\n", strictViolations));
}
}
}
Aggregations