/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.routing;
import com.carrotsearch.hppc.IntIndexedContainer;
import com.graphhopper.routing.util.*;
import com.graphhopper.routing.weighting.FastestWeighting;
import com.graphhopper.routing.weighting.ShortestWeighting;
import com.graphhopper.routing.weighting.Weighting;
import com.graphhopper.storage.*;
import com.graphhopper.storage.index.LocationIndex;
import com.graphhopper.storage.index.LocationIndexTree;
import com.graphhopper.storage.index.QueryResult;
import com.graphhopper.util.*;
import org.junit.Before;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import static com.graphhopper.util.Parameters.Algorithms.DIJKSTRA_BI;
import static org.junit.Assert.*;
/**
* @author Peter Karich
*/
public abstract class AbstractRoutingAlgorithmTester {
protected static final EncodingManager encodingManager = new EncodingManager("car,foot");
private static final DistanceCalc distCalc = new DistanceCalcEarth();
protected FlagEncoder carEncoder;
protected FlagEncoder footEncoder;
protected AlgorithmOptions defaultOpts;
// 0-1-2-3-4
// | / |
// | 8 |
// \ / |
// 7-6----5
public static Graph initBiGraph(Graph graph) {
// distance will be overwritten in second step as we need to calculate it from lat,lon
graph.edge(0, 1, 1, true);
graph.edge(1, 2, 1, true);
graph.edge(2, 3, 1, true);
graph.edge(3, 4, 1, true);
graph.edge(4, 5, 1, true);
graph.edge(5, 6, 1, true);
graph.edge(6, 7, 1, true);
graph.edge(7, 0, 1, true);
graph.edge(3, 8, 1, true);
graph.edge(8, 6, 1, true);
// we need lat,lon for edge precise queries because the distances of snapped point
// to adjacent nodes is calculated from lat,lon of the necessary points
updateDistancesFor(graph, 0, 0.001, 0);
updateDistancesFor(graph, 1, 0.100, 0.0005);
updateDistancesFor(graph, 2, 0.010, 0.0010);
updateDistancesFor(graph, 3, 0.001, 0.0011);
updateDistancesFor(graph, 4, 0.001, 0.00111);
updateDistancesFor(graph, 8, 0.0005, 0.0011);
updateDistancesFor(graph, 7, 0, 0);
updateDistancesFor(graph, 6, 0, 0.001);
updateDistancesFor(graph, 5, 0, 0.004);
return graph;
}
public static void updateDistancesFor(Graph g, int node, double lat, double lon) {
NodeAccess na = g.getNodeAccess();
na.setNode(node, lat, lon);
EdgeIterator iter = g.createEdgeExplorer().setBaseNode(node);
while (iter.next()) {
iter.setDistance(iter.fetchWayGeometry(3).calcDistance(distCalc));
// System.out.println(node + "->" + adj + ": " + iter.getDistance());
}
}
protected static GraphHopperStorage createMatrixAlikeGraph(GraphHopperStorage tmpGraph) {
int WIDTH = 10;
int HEIGHT = 15;
int[][] matrix = new int[WIDTH][HEIGHT];
int counter = 0;
Random rand = new Random(12);
boolean print = false;
for (int h = 0; h < HEIGHT; h++) {
if (print) {
for (int w = 0; w < WIDTH; w++) {
System.out.print(" |\t ");
}
System.out.println();
}
for (int w = 0; w < WIDTH; w++) {
matrix[w][h] = counter++;
if (h > 0) {
float dist = 5 + Math.abs(rand.nextInt(5));
if (print)
System.out.print(" " + (int) dist + "\t ");
tmpGraph.edge(matrix[w][h], matrix[w][h - 1], dist, true);
}
}
if (print) {
System.out.println();
if (h > 0) {
for (int w = 0; w < WIDTH; w++) {
System.out.print(" |\t ");
}
System.out.println();
}
}
for (int w = 0; w < WIDTH; w++) {
if (w > 0) {
float dist = 5 + Math.abs(rand.nextInt(5));
if (print)
System.out.print("-- " + (int) dist + "\t-- ");
tmpGraph.edge(matrix[w][h], matrix[w - 1][h], dist, true);
}
if (print)
System.out.print("(" + matrix[w][h] + ")\t");
}
if (print)
System.out.println();
}
return tmpGraph;
}
@Before
public void setUp() {
carEncoder = (CarFlagEncoder) encodingManager.getEncoder("car");
footEncoder = (FootFlagEncoder) encodingManager.getEncoder("foot");
defaultOpts = AlgorithmOptions.start().
weighting(new ShortestWeighting(carEncoder)).build();
}
protected Graph getGraph(GraphHopperStorage ghStorage, Weighting weighting) {
return ghStorage.getGraph(Graph.class, weighting);
}
protected GraphHopperStorage createGHStorage(EncodingManager em, List<? extends Weighting> weightings, boolean is3D) {
return new GraphBuilder(em).set3D(is3D).create();
}
protected GraphHopperStorage createGHStorage(boolean is3D) {
return createGHStorage(encodingManager, Arrays.asList(defaultOpts.getWeighting()), is3D);
}
protected final RoutingAlgorithm createAlgo(GraphHopperStorage g) {
return createAlgo(g, defaultOpts);
}
protected final RoutingAlgorithm createAlgo(GraphHopperStorage ghStorage, AlgorithmOptions opts) {
return createFactory(ghStorage, opts).createAlgo(getGraph(ghStorage, opts.getWeighting()), opts);
}
public abstract RoutingAlgorithmFactory createFactory(GraphHopperStorage ghStorage, AlgorithmOptions opts);
@Test
public void testCalcShortestPath() {
GraphHopperStorage ghStorage = createTestStorage();
RoutingAlgorithm algo = createAlgo(ghStorage);
Path p = algo.calcPath(0, 7);
assertEquals(p.toString(), Helper.createTList(0, 4, 5, 7), p.calcNodes());
assertEquals(p.toString(), 62.1, p.getDistance(), .1);
}
// see calc-fastest-graph.svg
@Test
public void testCalcFastestPath() {
GraphHopperStorage graphShortest = createGHStorage(false);
initDirectedAndDiffSpeed(graphShortest, carEncoder);
Path p1 = createAlgo(graphShortest, defaultOpts).
calcPath(0, 3);
assertEquals(Helper.createTList(0, 1, 5, 2, 3), p1.calcNodes());
assertEquals(p1.toString(), 402.3, p1.getDistance(), .1);
assertEquals(p1.toString(), 144823, p1.getTime());
AlgorithmOptions opts = AlgorithmOptions.start().
weighting(new FastestWeighting(carEncoder)).build();
GraphHopperStorage graphFastest = createGHStorage(encodingManager, Arrays.asList(opts.getWeighting()), false);
initDirectedAndDiffSpeed(graphFastest, carEncoder);
Path p2 = createAlgo(graphFastest, opts).
calcPath(0, 3);
assertEquals(Helper.createTList(0, 4, 6, 7, 5, 3), p2.calcNodes());
assertEquals(p2.toString(), 1261.7, p2.getDistance(), 0.1);
assertEquals(p2.toString(), 111442, p2.getTime());
}
// 0-1-2-3
// |/|/ /|
// 4-5-- |
// |/ \--7
// 6----/
protected void initDirectedAndDiffSpeed(Graph graph, FlagEncoder enc) {
graph.edge(0, 1).setFlags(enc.setProperties(10, true, false));
graph.edge(0, 4).setFlags(enc.setProperties(100, true, false));
graph.edge(1, 4).setFlags(enc.setProperties(10, true, true));
graph.edge(1, 5).setFlags(enc.setProperties(10, true, true));
EdgeIteratorState edge12 = graph.edge(1, 2).setFlags(enc.setProperties(10, true, true));
graph.edge(5, 2).setFlags(enc.setProperties(10, true, false));
graph.edge(2, 3).setFlags(enc.setProperties(10, true, false));
EdgeIteratorState edge53 = graph.edge(5, 3).setFlags(enc.setProperties(20, true, false));
graph.edge(3, 7).setFlags(enc.setProperties(10, true, false));
graph.edge(4, 6).setFlags(enc.setProperties(100, true, false));
graph.edge(5, 4).setFlags(enc.setProperties(10, true, false));
graph.edge(5, 6).setFlags(enc.setProperties(10, true, false));
graph.edge(7, 5).setFlags(enc.setProperties(100, true, false));
graph.edge(6, 7).setFlags(enc.setProperties(100, true, true));
updateDistancesFor(graph, 0, 0.002, 0);
updateDistancesFor(graph, 1, 0.002, 0.001);
updateDistancesFor(graph, 2, 0.002, 0.002);
updateDistancesFor(graph, 3, 0.002, 0.003);
updateDistancesFor(graph, 4, 0.0015, 0);
updateDistancesFor(graph, 5, 0.0015, 0.001);
updateDistancesFor(graph, 6, 0, 0);
updateDistancesFor(graph, 7, 0.001, 0.003);
edge12.setDistance(edge12.getDistance() * 2);
edge53.setDistance(edge53.getDistance() * 2);
}
@Test
public void testCalcFootPath() {
AlgorithmOptions opts = AlgorithmOptions.start().
weighting(new ShortestWeighting(footEncoder)).build();
GraphHopperStorage ghStorage = createGHStorage(encodingManager, Arrays.asList(opts.getWeighting()), false);
initFootVsCar(ghStorage);
Path p1 = createAlgo(ghStorage, opts).
calcPath(0, 7);
assertEquals(p1.toString(), 17000, p1.getDistance(), 1e-6);
assertEquals(p1.toString(), 12240 * 1000, p1.getTime());
assertEquals(Helper.createTList(0, 4, 5, 7), p1.calcNodes());
}
protected void initFootVsCar(Graph graph) {
graph.edge(0, 1).setDistance(7000).setFlags(footEncoder.setProperties(5, true, true) | carEncoder.setProperties(10, true, false));
graph.edge(0, 4).setDistance(5000).setFlags(footEncoder.setProperties(5, true, true) | carEncoder.setProperties(20, true, false));
graph.edge(1, 4).setDistance(7000).setFlags(carEncoder.setProperties(10, true, true));
graph.edge(1, 5).setDistance(7000).setFlags(carEncoder.setProperties(10, true, true));
graph.edge(1, 2).setDistance(20000).setFlags(footEncoder.setProperties(5, true, true) | carEncoder.setProperties(10, true, true));
graph.edge(5, 2).setDistance(5000).setFlags(carEncoder.setProperties(10, true, false));
graph.edge(2, 3).setDistance(5000).setFlags(footEncoder.setProperties(5, true, true) | carEncoder.setProperties(10, true, false));
graph.edge(5, 3).setDistance(11000).setFlags(carEncoder.setProperties(20, true, false));
graph.edge(3, 7).setDistance(7000).setFlags(footEncoder.setProperties(5, true, true) | carEncoder.setProperties(10, true, false));
graph.edge(4, 6).setDistance(5000).setFlags(carEncoder.setProperties(20, true, false));
graph.edge(5, 4).setDistance(7000).setFlags(footEncoder.setProperties(5, true, true) | carEncoder.setProperties(10, true, false));
graph.edge(5, 6).setDistance(7000).setFlags(carEncoder.setProperties(10, true, false));
graph.edge(7, 5).setDistance(5000).setFlags(footEncoder.setProperties(5, true, true) | carEncoder.setProperties(20, true, false));
graph.edge(6, 7).setDistance(5000).setFlags(carEncoder.setProperties(20, true, true));
}
// see test-graph.svg !
protected GraphHopperStorage createTestStorage() {
GraphHopperStorage graph = createGHStorage(false);
graph.edge(0, 1, 7, true);
graph.edge(0, 4, 6, true);
graph.edge(1, 4, 2, true);
graph.edge(1, 5, 8, true);
graph.edge(1, 2, 2, true);
graph.edge(2, 5, 5, true);
graph.edge(2, 3, 2, true);
graph.edge(3, 5, 2, true);
graph.edge(3, 7, 10, true);
graph.edge(4, 6, 4, true);
graph.edge(4, 5, 7, true);
graph.edge(5, 6, 2, true);
graph.edge(5, 7, 1, true);
EdgeIteratorState edge6_7 = graph.edge(6, 7, 5, true);
updateDistancesFor(graph, 0, 0.0010, 0.00001);
updateDistancesFor(graph, 1, 0.0008, 0.0000);
updateDistancesFor(graph, 2, 0.0005, 0.0001);
updateDistancesFor(graph, 3, 0.0006, 0.0002);
updateDistancesFor(graph, 4, 0.0009, 0.0001);
updateDistancesFor(graph, 5, 0.0007, 0.0001);
updateDistancesFor(graph, 6, 0.0009, 0.0002);
updateDistancesFor(graph, 7, 0.0008, 0.0003);
edge6_7.setDistance(5 * edge6_7.getDistance());
return graph;
}
@Test
public void testNoPathFound() {
GraphHopperStorage graph = createGHStorage(false);
graph.edge(100, 101);
assertFalse(createAlgo(graph).calcPath(0, 1).isFound());
graph = createGHStorage(false);
graph.edge(100, 101);
// two disconnected areas
graph.edge(0, 1, 7, true);
graph.edge(5, 6, 2, true);
graph.edge(5, 7, 1, true);
graph.edge(5, 8, 1, true);
graph.edge(7, 8, 1, true);
RoutingAlgorithm algo = createAlgo(graph);
assertFalse(algo.calcPath(0, 5).isFound());
// assertEquals(3, algo.getVisitedNodes());
// disconnected as directed graph
graph = createGHStorage(false);
graph.edge(0, 1, 1, false);
graph.edge(0, 2, 1, true);
assertFalse(createAlgo(graph).calcPath(1, 2).isFound());
}
@Test
public void testWikipediaShortestPath() {
GraphHopperStorage ghStorage = createWikipediaTestGraph();
Path p = createAlgo(ghStorage).calcPath(0, 4);
assertEquals(p.toString(), 20, p.getDistance(), 1e-4);
assertEquals(p.toString(), 4, p.calcNodes().size());
}
@Test
public void testCalcIf1EdgeAway() {
Path p = createAlgo(createTestStorage()).calcPath(1, 2);
assertEquals(Helper.createTList(1, 2), p.calcNodes());
assertEquals(p.toString(), 35.1, p.getDistance(), .1);
}
// see wikipedia-graph.svg !
protected GraphHopperStorage createWikipediaTestGraph() {
GraphHopperStorage graph = createGHStorage(false);
graph.edge(0, 1, 7, true);
graph.edge(0, 2, 9, true);
graph.edge(0, 5, 14, true);
graph.edge(1, 2, 10, true);
graph.edge(1, 3, 15, true);
graph.edge(2, 5, 2, true);
graph.edge(2, 3, 11, true);
graph.edge(3, 4, 6, true);
graph.edge(4, 5, 9, true);
return graph;
}
@Test
public void testBidirectional() {
GraphHopperStorage graph = createGHStorage(false);
initBiGraph(graph);
// PrepareTowerNodesShortcutsTest.printEdges((CHGraph) graph);
Path p = createAlgo(graph).calcPath(0, 4);
// PrepareTowerNodesShortcutsTest.printEdges((CHGraph) graph);
assertEquals(p.toString(), Helper.createTList(0, 7, 6, 8, 3, 4), p.calcNodes());
assertEquals(p.toString(), 335.8, p.getDistance(), .1);
p = createAlgo(graph).calcPath(1, 2);
// the other way around is even larger as 0-1 is already 11008.452
assertEquals(p.toString(), Helper.createTList(1, 2), p.calcNodes());
assertEquals(p.toString(), 10007.7, p.getDistance(), .1);
}
@Test
public void testMaxVisitedNodes() {
GraphHopperStorage graph = createGHStorage(false);
initBiGraph(graph);
RoutingAlgorithm algo = createAlgo(graph);
Path p = algo.calcPath(0, 4);
assertTrue(p.isFound());
algo = createAlgo(graph);
algo.setMaxVisitedNodes(3);
p = algo.calcPath(0, 4);
assertFalse(p.isFound());
}
// 1-2-3-4-5
// | / |
// | 9 |
// \ / /
// 8-7-6-/
@Test
public void testBidirectional2() {
GraphHopperStorage graph = createGHStorage(false);
graph.edge(0, 1, 100, true);
graph.edge(1, 2, 1, true);
graph.edge(2, 3, 1, true);
graph.edge(3, 4, 1, true);
graph.edge(4, 5, 20, true);
graph.edge(5, 6, 10, true);
graph.edge(6, 7, 5, true);
graph.edge(7, 0, 5, true);
graph.edge(3, 8, 20, true);
graph.edge(8, 6, 20, true);
Path p = createAlgo(graph).calcPath(0, 4);
assertEquals(p.toString(), 40, p.getDistance(), 1e-4);
assertEquals(p.toString(), 5, p.calcNodes().size());
assertEquals(Helper.createTList(0, 7, 6, 5, 4), p.calcNodes());
}
@Test
public void testRekeyBugOfIntBinHeap() {
// using Dijkstra + IntBinHeap then rekey loops endlessly
GraphHopperStorage matrixGraph = createMatrixGraph();
Path p = createAlgo(matrixGraph).calcPath(36, 91);
assertEquals(12, p.calcNodes().size());
IntIndexedContainer list = p.calcNodes();
if (!Helper.createTList(36, 46, 56, 66, 76, 86, 85, 84, 94, 93, 92, 91).equals(list)
&& !Helper.createTList(36, 46, 56, 66, 76, 86, 85, 84, 83, 82, 92, 91).equals(list)) {
assertTrue("wrong locations: " + list.toString(), false);
}
assertEquals(66f, p.getDistance(), 1e-3);
testBug1(matrixGraph);
testCorrectWeight(matrixGraph);
}
public void testBug1(GraphHopperStorage g) {
Path p = createAlgo(g).calcPath(34, 36);
assertEquals(Helper.createTList(34, 35, 36), p.calcNodes());
assertEquals(3, p.calcNodes().size());
assertEquals(17, p.getDistance(), 1e-5);
}
public void testCorrectWeight(GraphHopperStorage g) {
Path p = createAlgo(g).calcPath(45, 72);
assertEquals(Helper.createTList(45, 44, 54, 64, 74, 73, 72), p.calcNodes());
assertEquals(38f, p.getDistance(), 1e-3);
}
@Test
public void testCannotCalculateSP() {
GraphHopperStorage graph = createGHStorage(false);
graph.edge(0, 1, 1, false);
graph.edge(1, 2, 1, false);
Path p = createAlgo(graph).calcPath(0, 2);
assertEquals(p.toString(), 3, p.calcNodes().size());
}
@Test
public void testDirectedGraphBug1() {
GraphHopperStorage graph = createGHStorage(false);
graph.edge(0, 1, 3, false);
graph.edge(1, 2, 2.99, false);
graph.edge(0, 3, 2, false);
graph.edge(3, 4, 3, false);
graph.edge(4, 2, 1, false);
Path p = createAlgo(graph).calcPath(0, 2);
assertEquals(Helper.createTList(0, 1, 2), p.calcNodes());
assertEquals(p.toString(), 5.99, p.getDistance(), 1e-4);
assertEquals(p.toString(), 3, p.calcNodes().size());
}
@Test
public void testDirectedGraphBug2() {
GraphHopperStorage graph = createGHStorage(false);
graph.edge(0, 1, 1, false);
graph.edge(1, 2, 1, false);
graph.edge(2, 3, 1, false);
graph.edge(3, 1, 4, true);
Path p = createAlgo(graph).calcPath(0, 3);
assertEquals(Helper.createTList(0, 1, 2, 3), p.calcNodes());
}
// a-b-0-c-1
// | | _/\
// | / / |
// d-2--3-e-4
@Test
public void testWithCoordinates() {
Weighting weighting = new ShortestWeighting(carEncoder);
GraphHopperStorage graph = createGHStorage(encodingManager, Arrays.asList(weighting), false);
graph.edge(0, 1, 2, true).setWayGeometry(Helper.createPointList(1.5, 1));
graph.edge(2, 3, 2, true).setWayGeometry(Helper.createPointList(0, 1.5));
graph.edge(3, 4, 2, true).setWayGeometry(Helper.createPointList(0, 2));
// duplicate but the second edge is longer
graph.edge(0, 2, 1.2, true);
graph.edge(0, 2, 1.5, true).setWayGeometry(Helper.createPointList(0.5, 0));
graph.edge(1, 3, 1.3, true).setWayGeometry(Helper.createPointList(0.5, 1.5));
graph.edge(1, 4, 1, true);
updateDistancesFor(graph, 0, 1, 0.6);
updateDistancesFor(graph, 1, 1, 1.5);
updateDistancesFor(graph, 2, 0, 0);
updateDistancesFor(graph, 3, 0, 1);
updateDistancesFor(graph, 4, 0, 2);
AlgorithmOptions opts = new AlgorithmOptions(DIJKSTRA_BI, weighting);
RoutingAlgorithmFactory prepare = createFactory(graph, opts);
Path p = prepare.createAlgo(getGraph(graph, opts.getWeighting()), opts).calcPath(4, 0);
assertEquals(Helper.createTList(4, 1, 0), p.calcNodes());
assertEquals(Helper.createPointList(0, 2, 1, 1.5, 1.5, 1, 1, 0.6), p.calcPoints());
assertEquals(274128, p.calcPoints().calcDistance(new DistanceCalcEarth()), 1);
p = prepare.createAlgo(getGraph(graph, opts.getWeighting()), opts).calcPath(2, 1);
assertEquals(Helper.createTList(2, 0, 1), p.calcNodes());
assertEquals(Helper.createPointList(0, 0, 1, 0.6, 1.5, 1, 1, 1.5), p.calcPoints());
assertEquals(279482, p.calcPoints().calcDistance(new DistanceCalcEarth()), 1);
}
@Test
public void testCalcIfEmptyWay() {
Path p = createAlgo(createTestStorage()).calcPath(0, 0);
assertEquals(p.calcNodes().toString(), 1, p.calcNodes().size());
assertEquals(p.toString(), 0, p.getDistance(), 1e-4);
}
@Test
public void testViaEdges_FromEqualsTo() {
GraphHopperStorage ghStorage = createTestStorage();
// identical tower nodes
Path p = calcPathViaQuery(ghStorage, 0.001, 0.000, 0.001, 0.000);
assertTrue(p.isFound());
assertEquals(Helper.createTList(0), p.calcNodes());
// assertEquals(1, p.calcPoints().size());
assertEquals(p.toString(), 0, p.getDistance(), 1e-4);
// identical query points on edge
p = calcPath(ghStorage, 0, 1, 0, 1);
assertTrue(p.isFound());
assertEquals(Helper.createTList(8), p.calcNodes());
// assertEquals(1, p.calcPoints().size());
assertEquals(p.toString(), 0, p.getDistance(), 1e-4);
// very close
p = calcPathViaQuery(ghStorage, 0.00092, 0, 0.00091, 0);
assertEquals(Helper.createTList(8, 9), p.calcNodes());
assertEquals(p.toString(), 1.11, p.getDistance(), .1);
}
@Test
public void testViaEdges_BiGraph() {
GraphHopperStorage graph = createGHStorage(false);
initBiGraph(graph);
// 0-7 to 4-3
Path p = calcPathViaQuery(graph, 0.0009, 0, 0.001, 0.001105);
assertEquals(p.toString(), Helper.createTList(10, 7, 6, 8, 3, 9), p.calcNodes());
assertEquals(p.toString(), 324.11, p.getDistance(), 0.01);
// 0-1 to 2-3
p = calcPathViaQuery(graph, 0.001, 0.0001, 0.010, 0.0011);
assertEquals(p.toString(), Helper.createTList(0, 7, 6, 8, 3, 9), p.calcNodes());
assertEquals(p.toString(), 1335.35, p.getDistance(), 0.01);
}
@Test
public void testViaEdges_WithCoordinates() {
GraphHopperStorage ghStorage = createTestStorage();
Path p = calcPath(ghStorage, 0, 1, 2, 3);
assertEquals(Helper.createTList(8, 1, 2, 9), p.calcNodes());
assertEquals(p.toString(), 56.7, p.getDistance(), .1);
}
@Test
public void testViaEdges_SpecialCases() {
GraphHopperStorage graph = createGHStorage(false);
// 0->1\
// | 2
// 4<-3/
graph.edge(0, 1, 7, false);
graph.edge(1, 2, 7, true);
graph.edge(2, 3, 7, true);
graph.edge(3, 4, 7, false);
graph.edge(4, 0, 7, true);
updateDistancesFor(graph, 4, 0, 0);
updateDistancesFor(graph, 0, 0.00010, 0);
updateDistancesFor(graph, 1, 0.00010, 0.0001);
updateDistancesFor(graph, 2, 0.00005, 0.00015);
updateDistancesFor(graph, 3, 0, 0.0001);
// 0-1 to 3-4
Path p = calcPathViaQuery(graph, 0.00010, 0.00001, 0, 0.00009);
assertEquals(Helper.createTList(5, 1, 2, 3, 6), p.calcNodes());
assertEquals(p.toString(), 26.81, p.getDistance(), .1);
// overlapping edges: 2-3 and 3-2
p = calcPathViaQuery(graph, 0.000049, 0.00014, 0.00001, 0.0001);
assertEquals(Helper.createTList(5, 6), p.calcNodes());
assertEquals(p.toString(), 6.2, p.getDistance(), .1);
// 'from' and 'to' edge share one node '2': 1-2 to 3-2
p = calcPathViaQuery(graph, 0.00009, 0.00011, 0.00001, 0.00011);
assertEquals(p.toString(), Helper.createTList(6, 2, 5), p.calcNodes());
assertEquals(p.toString(), 12.57, p.getDistance(), .1);
}
@Test
public void testQueryGraphAndFastest() {
Weighting weighting = new FastestWeighting(carEncoder);
GraphHopperStorage graph = createGHStorage(encodingManager, Arrays.asList(weighting), false);
initDirectedAndDiffSpeed(graph, carEncoder);
Path p = calcPathViaQuery(weighting, graph, 0.002, 0.0005, 0.0017, 0.0031);
assertEquals(Helper.createTList(8, 1, 5, 3, 9), p.calcNodes());
assertEquals(602.98, p.getDistance(), 1e-1);
}
Path calcPathViaQuery(GraphHopperStorage ghStorage, double fromLat, double fromLon, double toLat, double toLon) {
return calcPathViaQuery(defaultOpts.getWeighting(), ghStorage, fromLat, fromLon, toLat, toLon);
}
Path calcPathViaQuery(Weighting weighting, GraphHopperStorage ghStorage, double fromLat, double fromLon, double toLat, double toLon) {
LocationIndex index = new LocationIndexTree(ghStorage, new RAMDirectory());
index.prepareIndex();
QueryResult from = index.findClosest(fromLat, fromLon, EdgeFilter.ALL_EDGES);
QueryResult to = index.findClosest(toLat, toLon, EdgeFilter.ALL_EDGES);
// correct order for CH: in factory do prepare and afterwards wrap in query graph
AlgorithmOptions opts = AlgorithmOptions.start().weighting(weighting).build();
RoutingAlgorithmFactory factory = createFactory(ghStorage, opts);
QueryGraph qGraph = new QueryGraph(getGraph(ghStorage, weighting)).lookup(from, to);
return factory.createAlgo(qGraph, opts).
calcPath(from.getClosestNode(), to.getClosestNode());
}
Path calcPath(GraphHopperStorage ghStorage, int fromNode1, int fromNode2, int toNode1, int toNode2) {
// lookup two edges: fromNode1-fromNode2 and toNode1-toNode2
QueryResult from = newQR(ghStorage, fromNode1, fromNode2);
QueryResult to = newQR(ghStorage, toNode1, toNode2);
RoutingAlgorithmFactory factory = createFactory(ghStorage, defaultOpts);
QueryGraph qGraph = new QueryGraph(getGraph(ghStorage, defaultOpts.getWeighting())).lookup(from, to);
return factory.createAlgo(qGraph, defaultOpts).calcPath(from.getClosestNode(), to.getClosestNode());
}
/**
* Creates query result on edge (node1-node2) very close to node1.
*/
QueryResult newQR(Graph graph, int node1, int node2) {
EdgeIteratorState edge = GHUtility.getEdge(graph, node1, node2);
if (edge == null)
throw new IllegalStateException("edge not found? " + node1 + "-" + node2);
NodeAccess na = graph.getNodeAccess();
double lat = na.getLatitude(edge.getBaseNode());
double lon = na.getLongitude(edge.getBaseNode());
double latAdj = na.getLatitude(edge.getAdjNode());
double lonAdj = na.getLongitude(edge.getAdjNode());
// calculate query point near the base node but not directly on it!
QueryResult res = new QueryResult(lat + (latAdj - lat) * .1, lon + (lonAdj - lon) * .1);
res.setClosestNode(edge.getBaseNode());
res.setClosestEdge(edge);
res.setWayIndex(0);
res.setSnappedPosition(QueryResult.Position.EDGE);
res.calcSnappedPoint(distCalc);
return res;
}
@Test
public void testTwoWeightsPerEdge() {
FlagEncoder encoder = new Bike2WeightFlagEncoder();
EncodingManager em = new EncodingManager(encoder);
AlgorithmOptions opts = AlgorithmOptions.start().
weighting(new FastestWeighting(encoder)).build();
GraphHopperStorage graph = createGHStorage(em, Arrays.asList(opts.getWeighting()), true);
initEleGraph(graph);
// force the other path
GHUtility.getEdge(graph, 0, 3).setFlags(encoder.setProperties(10, false, true));
// for two weights per edge it happened that Path (and also the Weighting) read the wrong side
// of the speed and read 0 => infinity weight => overflow of millis => negative millis!
Path p = createAlgo(graph, opts).
calcPath(0, 10);
assertEquals(85124371, p.getTime());
assertEquals(425622, p.getDistance(), 1);
assertEquals(85124.4, p.getWeight(), 1);
}
@Test
public void test0SpeedButUnblocked_Issue242() {
GraphHopperStorage graph = createGHStorage(false);
long flags = carEncoder.setAccess(carEncoder.setSpeed(0, 0), true, true);
graph.edge(0, 1).setFlags(flags).setDistance(10);
graph.edge(1, 2).setFlags(flags).setDistance(10);
RoutingAlgorithm algo = createAlgo(graph);
try {
Path p = algo.calcPath(0, 2);
assertTrue(false);
} catch (Exception ex) {
assertTrue(ex.getMessage(), ex.getMessage().startsWith("Speed cannot be 0"));
}
}
@Test
public void testTwoWeightsPerEdge2() {
// other direction should be different!
Weighting fakeWeighting = new Weighting() {
@Override
public FlagEncoder getFlagEncoder() {
return carEncoder;
}
@Override
public double getMinWeight(double distance) {
return 0.8 * distance;
}
@Override
public double calcWeight(EdgeIteratorState edgeState, boolean reverse, int prevOrNextEdgeId) {
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;
}
private final Weighting tmpW = new FastestWeighting(carEncoder);
@Override
public long calcMillis(EdgeIteratorState edgeState, boolean reverse, int prevOrNextEdgeId) {
return tmpW.calcMillis(edgeState, reverse, prevOrNextEdgeId);
}
@Override
public boolean matches(HintsMap map) {
throw new UnsupportedOperationException("Not supported");
}
@Override
public String getName() {
return "custom";
}
};
AlgorithmOptions opts = AlgorithmOptions.start().weighting(defaultOpts.getWeighting()).build();
GraphHopperStorage graph = createGHStorage(encodingManager, Arrays.asList(opts.getWeighting()), true);
initEleGraph(graph);
Path p = createAlgo(graph, opts).calcPath(0, 10);
// GHUtility.printEdgeInfo(graph, carEncoder);
assertEquals(Helper.createTList(0, 4, 6, 10), p.calcNodes());
AlgorithmOptions fakeOpts = AlgorithmOptions.start().weighting(fakeWeighting).build();
graph = createGHStorage(encodingManager, Arrays.asList(fakeOpts.getWeighting()), true);
initEleGraph(graph);
QueryResult from = newQR(graph, 3, 0);
QueryResult to = newQR(graph, 10, 9);
RoutingAlgorithmFactory factory = createFactory(graph, fakeOpts);
QueryGraph qGraph = new QueryGraph(getGraph(graph, fakeWeighting)).lookup(from, to);
p = factory.createAlgo(qGraph, fakeOpts).calcPath(from.getClosestNode(), to.getClosestNode());
assertEquals(Helper.createTList(12, 0, 1, 2, 11, 7, 10, 13), p.calcNodes());
assertEquals(37009621, p.getTime());
assertEquals(616827, p.getDistance(), 1);
assertEquals(493462, p.getWeight(), 1);
}
@Test
public void testMultipleVehicles_issue548() {
FastestWeighting footWeighting = new FastestWeighting(footEncoder);
AlgorithmOptions footOptions = AlgorithmOptions.start().
weighting(footWeighting).build();
FastestWeighting carWeighting = new FastestWeighting(carEncoder);
AlgorithmOptions carOptions = AlgorithmOptions.start().
weighting(carWeighting).build();
GraphHopperStorage ghStorage = createGHStorage(encodingManager,
Arrays.asList(footOptions.getWeighting(), carOptions.getWeighting()), false);
initFootVsCar(ghStorage);
// normal path would be 0-4-6-7 but block 4-6
GHUtility.getEdge(ghStorage, 4, 6).setFlags(carEncoder.setProperties(20, false, false));
RoutingAlgorithm algoFoot = createFactory(ghStorage, footOptions).
createAlgo(getGraph(ghStorage, footWeighting), footOptions);
RoutingAlgorithm algoCar = createFactory(ghStorage, carOptions).
createAlgo(getGraph(ghStorage, carWeighting), carOptions);
Path p1 = algoCar.calcPath(0, 7);
assertEquals(Helper.createTList(0, 1, 5, 6, 7), p1.calcNodes());
assertEquals(p1.toString(), 26000, p1.getDistance(), 1e-6);
}
// 0-1-2
// |\| |
// 3 4-11
// | | |
// 5-6-7
// | |\|
// 8-9-10
Graph initEleGraph(Graph g) {
g.edge(0, 1, 10, true);
g.edge(0, 4, 12, true);
g.edge(0, 3, 5, true);
g.edge(1, 2, 10, true);
g.edge(1, 4, 5, true);
g.edge(3, 5, 5, false);
g.edge(5, 6, 10, true);
g.edge(5, 8, 10, true);
g.edge(6, 4, 5, true);
g.edge(6, 7, 10, true);
g.edge(6, 10, 12, true);
g.edge(6, 9, 12, true);
g.edge(2, 11, 5, false);
g.edge(4, 11, 10, true);
g.edge(7, 11, 5, true);
g.edge(7, 10, 5, true);
g.edge(8, 9, 10, false);
g.edge(9, 8, 9, false);
g.edge(10, 9, 10, false);
updateDistancesFor(g, 0, 3, 0);
updateDistancesFor(g, 3, 2.5, 0);
updateDistancesFor(g, 5, 1, 0);
updateDistancesFor(g, 8, 0, 0);
updateDistancesFor(g, 1, 3, 1);
updateDistancesFor(g, 4, 2, 1);
updateDistancesFor(g, 6, 1, 1);
updateDistancesFor(g, 9, 0, 1);
updateDistancesFor(g, 2, 3, 2);
updateDistancesFor(g, 11, 2, 2);
updateDistancesFor(g, 7, 1, 2);
updateDistancesFor(g, 10, 0, 2);
return g;
}
protected GraphHopperStorage createMatrixGraph() {
return createMatrixAlikeGraph(createGHStorage(false));
}
}