/*
* 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.ch;
import com.carrotsearch.hppc.IntIndexedContainer;
import com.graphhopper.routing.*;
import com.graphhopper.routing.ch.PrepareContractionHierarchies.Shortcut;
import com.graphhopper.routing.util.BikeFlagEncoder;
import com.graphhopper.routing.util.CarFlagEncoder;
import com.graphhopper.routing.util.EncodingManager;
import com.graphhopper.routing.util.TraversalMode;
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.util.*;
import org.junit.Before;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import static com.graphhopper.util.Parameters.Algorithms.DIJKSTRA_BI;
import static org.junit.Assert.*;
/**
* @author Peter Karich
*/
public class PrepareContractionHierarchiesTest {
private final CarFlagEncoder carEncoder = new CarFlagEncoder();
private final EncodingManager encodingManager = new EncodingManager(carEncoder);
private final Weighting weighting = new ShortestWeighting(carEncoder);
private final TraversalMode tMode = TraversalMode.NODE_BASED;
private Directory dir;
// 0-1-.....-9-10
// | ^ \
// | | |
// 17-16-...-11<-/
public static void initDirected2(Graph g) {
g.edge(0, 1, 1, true);
g.edge(1, 2, 1, true);
g.edge(2, 3, 1, true);
g.edge(3, 4, 1, true);
g.edge(4, 5, 1, true);
g.edge(5, 6, 1, true);
g.edge(6, 7, 1, true);
g.edge(7, 8, 1, true);
g.edge(8, 9, 1, true);
g.edge(9, 10, 1, true);
g.edge(10, 11, 1, false);
g.edge(11, 12, 1, true);
g.edge(11, 9, 3, false);
g.edge(12, 13, 1, true);
g.edge(13, 14, 1, true);
g.edge(14, 15, 1, true);
g.edge(15, 16, 1, true);
g.edge(16, 17, 1, true);
g.edge(17, 0, 1, true);
}
// 8
// |
// 6->0->1->3->7
// | |
// | v
//10<-2---4<---5
// 9
public static void initDirected1(Graph g) {
g.edge(0, 8, 1, true);
g.edge(0, 1, 1, false);
g.edge(1, 3, 1, false);
g.edge(3, 7, 1, false);
g.edge(3, 5, 1, false);
g.edge(5, 4, 1, false);
g.edge(4, 2, 1, true);
g.edge(2, 9, 1, false);
g.edge(2, 10, 1, false);
g.edge(2, 6, 1, true);
g.edge(6, 0, 1, false);
}
// prepare-routing.svg
public static Graph initShortcutsGraph(Graph g) {
g.edge(0, 1, 1, true);
g.edge(0, 2, 1, true);
g.edge(1, 2, 1, true);
g.edge(2, 3, 1.5, true);
g.edge(1, 4, 1, true);
g.edge(2, 9, 1, true);
g.edge(9, 3, 1, true);
g.edge(10, 3, 1, true);
g.edge(4, 5, 1, true);
g.edge(5, 6, 1, true);
g.edge(6, 7, 1, true);
g.edge(7, 8, 1, true);
g.edge(8, 9, 1, true);
g.edge(4, 11, 1, true);
g.edge(9, 14, 1, true);
g.edge(10, 14, 1, true);
g.edge(11, 12, 1, true);
g.edge(12, 15, 1, true);
g.edge(12, 13, 1, true);
g.edge(13, 16, 1, true);
g.edge(15, 16, 2, true);
g.edge(14, 16, 1, true);
return g;
}
GraphHopperStorage createGHStorage() {
return new GraphBuilder(encodingManager).setCHGraph(weighting).create();
}
GraphHopperStorage createExampleGraph() {
GraphHopperStorage g = createGHStorage();
//5-1-----2
// \ __/|
// 0 |
// / |
// 4-----3
//
g.edge(0, 1, 1, true);
g.edge(0, 2, 1, true);
g.edge(0, 4, 3, true);
g.edge(1, 2, 2, true);
g.edge(2, 3, 1, true);
g.edge(4, 3, 2, true);
g.edge(5, 1, 2, true);
return g;
}
@Before
public void setUp() {
dir = new GHDirectory("", DAType.RAM_INT);
}
@Test
public void testShortestPathSkipNode() {
GraphHopperStorage g = createExampleGraph();
double normalDist = new Dijkstra(g, weighting, tMode).calcPath(4, 2).getDistance();
DijkstraOneToMany algo = new DijkstraOneToMany(g, weighting, tMode);
CHGraph lg = g.getGraph(CHGraph.class);
PrepareContractionHierarchies prepare = new PrepareContractionHierarchies(dir, g, lg,
weighting, tMode);
prepare.initFromGraph().prepareNodes();
algo.setEdgeFilter(new PrepareContractionHierarchies.IgnoreNodeFilter(lg, g.getNodes() + 1).setAvoidNode(3));
algo.setWeightLimit(100);
int nodeEntry = algo.findEndNode(4, 2);
assertTrue(algo.getWeight(nodeEntry) > normalDist);
algo.clear();
algo.setMaxVisitedNodes(1);
nodeEntry = algo.findEndNode(4, 2);
assertEquals(-1, nodeEntry);
}
@Test
public void testShortestPathSkipNode2() {
GraphHopperStorage g = createExampleGraph();
CHGraph lg = g.getGraph(CHGraph.class);
double normalDist = new Dijkstra(g, weighting, tMode).calcPath(4, 2).getDistance();
assertEquals(3, normalDist, 1e-5);
DijkstraOneToMany algo = new DijkstraOneToMany(g, weighting, tMode);
PrepareContractionHierarchies prepare = new PrepareContractionHierarchies(dir, g, lg, weighting, tMode);
prepare.initFromGraph().prepareNodes();
algo.setEdgeFilter(new PrepareContractionHierarchies.IgnoreNodeFilter(lg, g.getNodes() + 1).setAvoidNode(3));
algo.setWeightLimit(10);
int nodeEntry = algo.findEndNode(4, 2);
assertEquals(4, algo.getWeight(nodeEntry), 1e-5);
nodeEntry = algo.findEndNode(4, 1);
assertEquals(4, algo.getWeight(nodeEntry), 1e-5);
}
@Test
public void testShortestPathLimit() {
GraphHopperStorage g = createExampleGraph();
CHGraph lg = g.getGraph(CHGraph.class);
DijkstraOneToMany algo = new DijkstraOneToMany(g, weighting, tMode);
PrepareContractionHierarchies prepare = new PrepareContractionHierarchies(dir, g, lg, weighting, tMode);
prepare.initFromGraph().prepareNodes();
algo.setEdgeFilter(new PrepareContractionHierarchies.IgnoreNodeFilter(lg, g.getNodes() + 1).setAvoidNode(0));
algo.setWeightLimit(2);
int endNode = algo.findEndNode(4, 1);
// did not reach endNode
assertNotEquals(1, endNode);
}
@Test
public void testAddShortcuts() {
GraphHopperStorage g = createExampleGraph();
CHGraph lg = g.getGraph(CHGraph.class);
int old = lg.getAllEdges().getMaxId();
PrepareContractionHierarchies prepare = new PrepareContractionHierarchies(dir, g, lg, weighting, tMode);
prepare.doWork();
assertEquals(old + 1, lg.getAllEdges().getMaxId());
}
@Test
public void testMoreComplexGraph() {
GraphHopperStorage g = createGHStorage();
CHGraph lg = g.getGraph(CHGraph.class);
initShortcutsGraph(lg);
int oldCount = g.getAllEdges().getMaxId();
PrepareContractionHierarchies prepare = new PrepareContractionHierarchies(dir, g, lg, weighting, tMode);
prepare.doWork();
assertEquals(oldCount, g.getAllEdges().getMaxId());
assertEquals(oldCount + 7, lg.getAllEdges().getMaxId());
}
@Test
public void testDirectedGraph() {
GraphHopperStorage g = createGHStorage();
CHGraph lg = g.getGraph(CHGraph.class);
g.edge(5, 4, 3, false);
g.edge(4, 5, 10, false);
g.edge(2, 4, 1, false);
g.edge(5, 2, 1, false);
g.edge(3, 5, 1, false);
g.edge(4, 3, 1, false);
g.freeze();
int oldCount = GHUtility.count(lg.getAllEdges());
assertEquals(6, oldCount);
PrepareContractionHierarchies prepare = new PrepareContractionHierarchies(dir, g, lg, weighting, tMode);
prepare.doWork();
assertEquals(2, prepare.getShortcuts());
assertEquals(oldCount + 2, GHUtility.count(lg.getAllEdges()));
RoutingAlgorithm algo = prepare.createAlgo(lg, new AlgorithmOptions(DIJKSTRA_BI, weighting, tMode));
Path p = algo.calcPath(4, 2);
assertEquals(3, p.getDistance(), 1e-6);
assertEquals(Helper.createTList(4, 3, 5, 2), p.calcNodes());
}
@Test
public void testDirectedGraph2() {
GraphHopperStorage g = createGHStorage();
CHGraph lg = g.getGraph(CHGraph.class);
initDirected2(g);
int oldCount = GHUtility.count(g.getAllEdges());
assertEquals(19, oldCount);
PrepareContractionHierarchies prepare = new PrepareContractionHierarchies(dir, g, lg, weighting, tMode);
prepare.doWork();
// PrepareTowerNodesShortcutsTest.printEdges(g);
assertEquals(oldCount, g.getAllEdges().getMaxId());
assertEquals(oldCount, GHUtility.count(g.getAllEdges()));
assertEquals(9, prepare.getShortcuts());
assertEquals(oldCount + 9, lg.getAllEdges().getMaxId());
assertEquals(oldCount + 9, GHUtility.count(lg.getAllEdges()));
RoutingAlgorithm algo = prepare.createAlgo(lg, new AlgorithmOptions(DIJKSTRA_BI, weighting, tMode));
Path p = algo.calcPath(0, 10);
assertEquals(10, p.getDistance(), 1e-6);
assertEquals(Helper.createTList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10), p.calcNodes());
}
@Test
public void testDirectedGraph3() {
GraphHopperStorage g = createGHStorage();
CHGraphImpl lg = (CHGraphImpl) g.getGraph(CHGraph.class);
//5 6 7
// \|/
//4-3_1<-\ 10
// \_|/
// 0___2_11
g.edge(0, 2, 2, true);
g.edge(10, 2, 2, true);
g.edge(11, 2, 2, true);
// create a longer one directional edge => no longish one-dir shortcut should be created
g.edge(2, 1, 2, true);
g.edge(2, 1, 10, false);
g.edge(1, 3, 2, true);
g.edge(3, 4, 2, true);
g.edge(3, 5, 2, true);
g.edge(3, 6, 2, true);
g.edge(3, 7, 2, true);
PrepareContractionHierarchies prepare = new PrepareContractionHierarchies(dir, g, lg, weighting, tMode);
prepare.initFromGraph();
prepare.prepareNodes();
// find all shortcuts if we contract node 1
Collection<Shortcut> scs = prepare.testFindShortcuts(1);
assertEquals(2, scs.size());
Iterator<Shortcut> iter = scs.iterator();
Shortcut sc1 = iter.next();
Shortcut sc2 = iter.next();
if (sc1.weight > sc2.weight) {
Shortcut tmp = sc1;
sc1 = sc2;
sc2 = tmp;
}
// both dirs
assertTrue(sc1.toString(), sc1.from == 3 && sc1.to == 2);
assertTrue(sc1.toString(), carEncoder.isForward(sc1.flags) && carEncoder.isBackward(sc1.flags));
// directed
assertTrue(sc2.toString(), sc2.from == 2 && sc2.to == 3);
assertTrue(sc2.toString(), carEncoder.isForward(sc2.flags));
assertEquals(sc1.toString(), 4, sc1.weight, 1e-4);
assertEquals(sc2.toString(), 12, sc2.weight, 1e-4);
}
void initRoundaboutGraph(Graph g) {
// roundabout:
//16-0-9-10--11 12<-13
// \ \ / \
// 17 \| 7-8-..
// -15-1--2--3--4 / /
// / \-5->6/ /
// -14 \________/
g.edge(16, 0, 1, true);
g.edge(0, 9, 1, true);
g.edge(0, 17, 1, true);
g.edge(9, 10, 1, true);
g.edge(10, 11, 1, true);
g.edge(11, 28, 1, true);
g.edge(28, 29, 1, true);
g.edge(29, 30, 1, true);
g.edge(30, 31, 1, true);
g.edge(31, 4, 1, true);
g.edge(17, 1, 1, true);
g.edge(15, 1, 1, true);
g.edge(14, 1, 1, true);
g.edge(14, 18, 1, true);
g.edge(18, 19, 1, true);
g.edge(19, 20, 1, true);
g.edge(20, 15, 1, true);
g.edge(19, 21, 1, true);
g.edge(21, 16, 1, true);
g.edge(1, 2, 1, true);
g.edge(2, 3, 1, true);
g.edge(3, 4, 1, true);
g.edge(4, 5, 1, false);
g.edge(5, 6, 1, false);
g.edge(6, 7, 1, false);
g.edge(7, 13, 1, false);
g.edge(13, 12, 1, false);
g.edge(12, 4, 1, false);
g.edge(7, 8, 1, true);
g.edge(8, 22, 1, true);
g.edge(22, 23, 1, true);
g.edge(23, 24, 1, true);
g.edge(24, 25, 1, true);
g.edge(25, 27, 1, true);
g.edge(27, 5, 1, true);
g.edge(25, 26, 1, false);
g.edge(26, 25, 1, false);
}
@Test
public void testRoundaboutUnpacking() {
GraphHopperStorage g = createGHStorage();
CHGraph lg = g.getGraph(CHGraph.class);
initRoundaboutGraph(g);
int oldCount = g.getAllEdges().getMaxId();
PrepareContractionHierarchies prepare = new PrepareContractionHierarchies(dir, g, lg, weighting, tMode);
prepare.doWork();
assertEquals(oldCount, g.getAllEdges().getMaxId());
assertEquals(oldCount + 23, lg.getAllEdges().getMaxId());
RoutingAlgorithm algo = prepare.createAlgo(lg, new AlgorithmOptions(DIJKSTRA_BI, weighting, tMode));
Path p = algo.calcPath(4, 7);
assertEquals(Helper.createTList(4, 5, 6, 7), p.calcNodes());
}
@Test
public void testFindShortcuts_Roundabout() {
GraphHopperStorage ghStorage = createGHStorage();
CHGraph lg = ghStorage.getGraph(CHGraph.class);
EdgeIteratorState iter1_3 = ghStorage.edge(1, 3, 1, true);
EdgeIteratorState iter3_4 = ghStorage.edge(3, 4, 1, true);
EdgeIteratorState iter4_5 = ghStorage.edge(4, 5, 1, false);
EdgeIteratorState iter5_6 = ghStorage.edge(5, 6, 1, false);
EdgeIteratorState iter6_8 = ghStorage.edge(6, 8, 2, false);
EdgeIteratorState iter8_4 = ghStorage.edge(8, 4, 1, false);
ghStorage.edge(6, 7, 1, true);
ghStorage.freeze();
PrepareContractionHierarchies prepare = new PrepareContractionHierarchies(dir, ghStorage, lg,
weighting, tMode);
CHEdgeIteratorState tmp = lg.shortcut(1, 4);
tmp.setFlags(PrepareEncoder.getScDirMask());
tmp.setWeight(2);
tmp.setSkippedEdges(iter1_3.getEdge(), iter3_4.getEdge());
long f = PrepareEncoder.getScFwdDir();
tmp = lg.shortcut(4, 6);
tmp.setFlags(f);
tmp.setWeight(2);
tmp.setSkippedEdges(iter4_5.getEdge(), iter5_6.getEdge());
tmp = lg.shortcut(6, 4);
tmp.setFlags(f);
tmp.setWeight(3);
tmp.setSkippedEdges(iter6_8.getEdge(), iter8_4.getEdge());
prepare.initFromGraph();
prepare.prepareNodes();
lg.setLevel(3, 3);
lg.setLevel(5, 5);
lg.setLevel(7, 7);
lg.setLevel(8, 8);
// there should be two different shortcuts for both directions!
Collection<Shortcut> sc = prepare.testFindShortcuts(4);
assertEquals(2, sc.size());
Iterator<Shortcut> iter = sc.iterator();
Shortcut sc1 = iter.next();
Shortcut sc2 = iter.next();
if (sc1.from > sc2.from) {
Shortcut tmpSc = sc1;
sc1 = sc2;
sc2 = tmpSc;
}
assertEquals("1->6, weight:4.0 (7,8)", sc1.toString());
assertEquals("6->1, weight:5.0 (9,7)", sc2.toString());
}
void initUnpackingGraph(GraphHopperStorage ghStorage, CHGraph g, Weighting w) {
final long flags = carEncoder.setProperties(30, true, false);
double dist = 1;
g.edge(10, 0).setDistance(dist).setFlags(flags);
EdgeIteratorState edgeState01 = g.edge(0, 1);
edgeState01.setDistance(dist).setFlags(flags);
EdgeIteratorState edgeState12 = g.edge(1, 2).setDistance(dist).setFlags(flags);
EdgeIteratorState edgeState23 = g.edge(2, 3).setDistance(dist).setFlags(flags);
EdgeIteratorState edgeState34 = g.edge(3, 4).setDistance(dist).setFlags(flags);
EdgeIteratorState edgeState45 = g.edge(4, 5).setDistance(dist).setFlags(flags);
EdgeIteratorState edgeState56 = g.edge(5, 6).setDistance(dist).setFlags(flags);
long oneDirFlags = PrepareEncoder.getScFwdDir();
int tmpEdgeId = edgeState01.getEdge();
ghStorage.freeze();
CHEdgeIteratorState sc0_2 = g.shortcut(0, 2);
int x = EdgeIterator.NO_EDGE;
sc0_2.setWeight(w.calcWeight(edgeState01, false, x) + w.calcWeight(edgeState12, false, x)).setDistance(2 * dist).setFlags(oneDirFlags);
sc0_2.setSkippedEdges(tmpEdgeId, edgeState12.getEdge());
tmpEdgeId = sc0_2.getEdge();
CHEdgeIteratorState sc0_3 = g.shortcut(0, 3);
sc0_3.setWeight(sc0_2.getWeight() + w.calcWeight(edgeState23, false, x)).setDistance(3 * dist).setFlags(oneDirFlags);
sc0_3.setSkippedEdges(tmpEdgeId, edgeState23.getEdge());
tmpEdgeId = sc0_3.getEdge();
CHEdgeIteratorState sc0_4 = g.shortcut(0, 4);
sc0_4.setWeight(sc0_3.getWeight() + w.calcWeight(edgeState34, false, x)).setDistance(4).setFlags(oneDirFlags);
sc0_4.setSkippedEdges(tmpEdgeId, edgeState34.getEdge());
tmpEdgeId = sc0_4.getEdge();
CHEdgeIteratorState sc0_5 = g.shortcut(0, 5);
sc0_5.setWeight(sc0_4.getWeight() + w.calcWeight(edgeState45, false, x)).setDistance(5).setFlags(oneDirFlags);
sc0_5.setSkippedEdges(tmpEdgeId, edgeState45.getEdge());
tmpEdgeId = sc0_5.getEdge();
CHEdgeIteratorState sc0_6 = g.shortcut(0, 6);
sc0_6.setWeight(sc0_5.getWeight() + w.calcWeight(edgeState56, false, x)).setDistance(6).setFlags(oneDirFlags);
sc0_6.setSkippedEdges(tmpEdgeId, edgeState56.getEdge());
g.setLevel(0, 10);
g.setLevel(6, 9);
g.setLevel(5, 8);
g.setLevel(4, 7);
g.setLevel(3, 6);
g.setLevel(2, 5);
g.setLevel(1, 4);
g.setLevel(10, 3);
}
@Test
public void testUnpackingOrder() {
GraphHopperStorage ghStorage = createGHStorage();
CHGraph lg = ghStorage.getGraph(CHGraph.class);
initUnpackingGraph(ghStorage, lg, weighting);
PrepareContractionHierarchies prepare = new PrepareContractionHierarchies(dir, ghStorage, lg, weighting, tMode);
RoutingAlgorithm algo = prepare.createAlgo(lg, new AlgorithmOptions(DIJKSTRA_BI, weighting, tMode));
Path p = algo.calcPath(10, 6);
assertEquals(7, p.getDistance(), 1e-5);
assertEquals(Helper.createTList(10, 0, 1, 2, 3, 4, 5, 6), p.calcNodes());
}
@Test
public void testUnpackingOrder_Fastest() {
GraphHopperStorage ghStorage = createGHStorage();
CHGraph lg = ghStorage.getGraph(CHGraph.class);
Weighting w = new FastestWeighting(carEncoder);
initUnpackingGraph(ghStorage, lg, w);
PrepareContractionHierarchies prepare = new PrepareContractionHierarchies(dir, ghStorage, lg, weighting, tMode);
RoutingAlgorithm algo = prepare.createAlgo(lg, new AlgorithmOptions(DIJKSTRA_BI, weighting, tMode));
Path p = algo.calcPath(10, 6);
assertEquals(7, p.getDistance(), 1e-1);
assertEquals(Helper.createTList(10, 0, 1, 2, 3, 4, 5, 6), p.calcNodes());
}
@Test
public void testCircleBug() {
GraphHopperStorage g = createGHStorage();
CHGraph lg = g.getGraph(CHGraph.class);
// /--1
// -0--/
// |
g.edge(0, 1, 10, true);
g.edge(0, 1, 4, true);
g.edge(0, 2, 10, true);
g.edge(0, 3, 10, true);
PrepareContractionHierarchies prepare = new PrepareContractionHierarchies(dir, g, lg, weighting, tMode);
prepare.doWork();
assertEquals(0, prepare.getShortcuts());
}
@Test
public void testBug178() {
// 5--------6__
// | | \
// 0-1->-2--3--4
// \-<-/
//
GraphHopperStorage g = createGHStorage();
CHGraph lg = g.getGraph(CHGraph.class);
g.edge(1, 2, 1, false);
g.edge(2, 1, 1, false);
g.edge(5, 0, 1, true);
g.edge(5, 6, 1, true);
g.edge(0, 1, 1, true);
g.edge(2, 3, 1, true);
g.edge(3, 4, 1, true);
g.edge(6, 3, 1, true);
PrepareContractionHierarchies prepare = new PrepareContractionHierarchies(dir, g, lg, weighting, tMode);
prepare.doWork();
assertEquals(2, prepare.getShortcuts());
}
// 0-1-2-3-4
// | / |
// | 8 |
// \ / /
// 7-6-5-/
void initBiGraph(Graph graph) {
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, 25, true);
graph.edge(5, 6, 25, 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);
}
// public static void printEdges(CHGraph g) {
// RawEdgeIterator iter = g.getAllEdges();
// while (iter.next()) {
// EdgeSkipIterator single = g.getEdgeProps(iter.edge(), iter.nodeB());
// System.out.println(iter.nodeA() + "<->" + iter.nodeB() + " \\"
// + single.skippedEdge1() + "," + single.skippedEdge2() + " (" + iter.edge() + ")"
// + ", dist: " + (float) iter.weight()
// + ", level:" + g.getLevel(iter.nodeA()) + "<->" + g.getLevel(iter.nodeB())
// + ", bothDir:" + CarFlagEncoder.isBoth(iter.setProperties()));
// }
// System.out.println("---");
// }
@Test
public void testBits() {
int fromNode = Integer.MAX_VALUE / 3 * 2;
int endNode = Integer.MAX_VALUE / 37 * 17;
long edgeId = (long) fromNode << 32 | endNode;
assertEquals((BitUtil.BIG.toBitString(edgeId)),
BitUtil.BIG.toLastBitString(fromNode, 32) + BitUtil.BIG.toLastBitString(endNode, 32));
}
@Test
public void testMultiplePreparationsIdenticalView() {
CarFlagEncoder tmpCarEncoder = new CarFlagEncoder();
BikeFlagEncoder tmpBikeEncoder = new BikeFlagEncoder();
EncodingManager tmpEncodingManager = new EncodingManager(tmpCarEncoder, tmpBikeEncoder);
// FastestWeighting would lead to different shortcuts due to different default speeds for bike and car
Weighting carWeighting = new ShortestWeighting(tmpCarEncoder);
Weighting bikeWeighting = new ShortestWeighting(tmpBikeEncoder);
List<Weighting> chWeightings = Arrays.asList(carWeighting, bikeWeighting);
GraphHopperStorage ghStorage = new GraphHopperStorage(chWeightings, dir, tmpEncodingManager, false, new GraphExtension.NoOpExtension()).create(1000);
initShortcutsGraph(ghStorage);
ghStorage.freeze();
for (Weighting w : chWeightings) {
checkPath(ghStorage, w, 7, 5, Helper.createTList(3, 9, 14, 16, 13, 12));
}
}
@Test
public void testMultiplePreparationsDifferentView() {
CarFlagEncoder tmpCarEncoder = new CarFlagEncoder();
BikeFlagEncoder tmpBikeEncoder = new BikeFlagEncoder();
EncodingManager tmpEncodingManager = new EncodingManager(tmpCarEncoder, tmpBikeEncoder);
Weighting carWeighting = new FastestWeighting(tmpCarEncoder);
Weighting bikeWeighting = new FastestWeighting(tmpBikeEncoder);
List<Weighting> chWeightings = Arrays.asList(carWeighting, bikeWeighting);
GraphHopperStorage ghStorage = new GraphHopperStorage(chWeightings, dir, tmpEncodingManager, false, new GraphExtension.NoOpExtension()).create(1000);
initShortcutsGraph(ghStorage);
EdgeIteratorState edge = GHUtility.getEdge(ghStorage, 9, 14);
edge.setFlags(tmpBikeEncoder.setAccess(edge.getFlags(), false, false));
ghStorage.freeze();
checkPath(ghStorage, carWeighting, 7, 5, Helper.createTList(3, 9, 14, 16, 13, 12));
// detour around blocked 9,14
checkPath(ghStorage, bikeWeighting, 9, 5, Helper.createTList(3, 10, 14, 16, 13, 12));
}
void checkPath(GraphHopperStorage ghStorage, Weighting w, int expShortcuts, double expDistance, IntIndexedContainer expNodes) {
CHGraph lg = ghStorage.getGraph(CHGraph.class, w);
PrepareContractionHierarchies prepare = new PrepareContractionHierarchies(dir, ghStorage, lg, w, tMode);
prepare.doWork();
assertEquals(w.toString(), expShortcuts, prepare.getShortcuts());
RoutingAlgorithm algo = prepare.createAlgo(lg, new AlgorithmOptions(DIJKSTRA_BI, w, tMode));
Path p = algo.calcPath(3, 12);
assertEquals(w.toString(), expDistance, p.getDistance(), 1e-5);
assertEquals(w.toString(), expNodes, p.calcNodes());
}
@Test
public void testShortcutMergeBug() {
// We refer to this real world situation http://www.openstreetmap.org/#map=19/52.71205/-1.77326
// assume the following graph:
//
// ---1---->----2-----3
// \--------/
//
// where there are two roads from 1 to 2 and the directed road has a smaller weight
// leading to two shortcuts sc1 (unidir) and sc2 (bidir) where the second should NOT be rejected due to the larger weight
GraphHopperStorage g = createGHStorage();
g.edge(1, 2, 1, true);
g.edge(1, 2, 1, false);
g.edge(2, 3, 1, true);
CHGraph lg = g.getGraph(CHGraph.class);
PrepareContractionHierarchies prepare = new PrepareContractionHierarchies(dir, g, lg, weighting, tMode);
prepare.initFromGraph();
// order is important here
Shortcut sc1 = new Shortcut(1, 3, 6.81620625, 121.18);
Shortcut sc2 = new Shortcut(1, 3, 6.82048125, 121.25);
sc2.flags = PrepareEncoder.getScDirMask();
List<Shortcut> list = Arrays.asList(sc1, sc2);
assertEquals(2, prepare.addShortcuts(list));
}
}