Search in sources :

Example 31 with QueryGraph

use of com.graphhopper.routing.querygraph.QueryGraph in project graphhopper by graphhopper.

the class QueryRoutingCHGraphTest method getTurnCost.

@Test
public void getTurnCost() {
    // /-----\
    // 0-x-1-x-2
    // 3   4
    na.setNode(0, 50.00, 10.00);
    na.setNode(1, 50.00, 10.10);
    na.setNode(2, 50.00, 10.20);
    EdgeIteratorState edge1 = addEdge(graph, 0, 1);
    EdgeIteratorState edge2 = addEdge(graph, 1, 2);
    DecimalEncodedValue turnCostEnc = encodingManager.getDecimalEncodedValue(TurnCost.key(encoder.toString()));
    graph.getTurnCostStorage().set(turnCostEnc, 0, 1, 1, 5);
    graph.freeze();
    CHConfig chConfig = CHConfig.edgeBased("x", weighting);
    CHStorage chStore = graph.createCHStorage(chConfig);
    RoutingCHGraph routingCHGraph = graph.createCHGraph(chStore, chConfig);
    CHStorageBuilder chBuilder = new CHStorageBuilder(chStore);
    chBuilder.setIdentityLevels();
    chBuilder.addShortcutEdgeBased(0, 2, PrepareEncoder.getScFwdDir(), 20, 0, 1, 0, 1);
    // without virtual nodes
    assertEquals(5, routingCHGraph.getTurnWeight(0, 1, 1));
    // with virtual nodes
    Snap snap1 = new Snap(50.00, 10.05);
    snap1.setClosestEdge(edge1);
    snap1.setWayIndex(0);
    snap1.setSnappedPosition(Snap.Position.EDGE);
    snap1.calcSnappedPoint(DistancePlaneProjection.DIST_PLANE);
    Snap snap2 = new Snap(50.00, 10.15);
    snap2.setClosestEdge(edge2);
    snap2.setWayIndex(0);
    snap2.setSnappedPosition(Snap.Position.EDGE);
    snap2.calcSnappedPoint(DistancePlaneProjection.DIST_PLANE);
    QueryGraph queryGraph = QueryGraph.create(graph, Arrays.asList(snap1, snap2));
    QueryRoutingCHGraph queryCHGraph = new QueryRoutingCHGraph(routingCHGraph, queryGraph);
    assertEquals(5, queryCHGraph.getTurnWeight(0, 1, 1));
    // take a look at edges 3->1 and 1->4, their original edge ids are 3 and 4 (not 4 and 5)
    assertNodesConnected(queryCHGraph, 3, 1, true);
    assertNodesConnected(queryCHGraph, 1, 4, true);
    int expectedEdge31 = 3;
    int expectedEdge14 = 4;
    RoutingCHEdgeIterator iter = queryCHGraph.createOutEdgeExplorer().setBaseNode(3);
    assertNextEdge(iter, 3, 0, 2);
    assertNextEdge(iter, 3, 1, expectedEdge31);
    assertEnd(iter);
    iter = queryCHGraph.createOutEdgeExplorer().setBaseNode(1);
    assertNextEdge(iter, 1, 3, 3);
    assertNextEdge(iter, 1, 4, expectedEdge14);
    assertEnd(iter);
    // check the turn weight between these edges
    assertEquals(5, queryCHGraph.getTurnWeight(expectedEdge31, 1, expectedEdge14));
}
Also used : EdgeIteratorState(com.graphhopper.util.EdgeIteratorState) DecimalEncodedValue(com.graphhopper.routing.ev.DecimalEncodedValue) QueryRoutingCHGraph(com.graphhopper.routing.querygraph.QueryRoutingCHGraph) QueryRoutingCHGraph(com.graphhopper.routing.querygraph.QueryRoutingCHGraph) Snap(com.graphhopper.storage.index.Snap) QueryGraph(com.graphhopper.routing.querygraph.QueryGraph) Test(org.junit.jupiter.api.Test)

Example 32 with QueryGraph

use of com.graphhopper.routing.querygraph.QueryGraph 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));
        }
    }
}
Also used : PrepareContractionHierarchies(com.graphhopper.routing.ch.PrepareContractionHierarchies) QueryRoutingCHGraph(com.graphhopper.routing.querygraph.QueryRoutingCHGraph) ArrayList(java.util.ArrayList) PMap(com.graphhopper.util.PMap) QueryRoutingCHGraph(com.graphhopper.routing.querygraph.QueryRoutingCHGraph) Snap(com.graphhopper.storage.index.Snap) LocationIndexTree(com.graphhopper.storage.index.LocationIndexTree) FastestWeighting(com.graphhopper.routing.weighting.FastestWeighting) Weighting(com.graphhopper.routing.weighting.Weighting) CHRoutingAlgorithmFactory(com.graphhopper.routing.ch.CHRoutingAlgorithmFactory) QueryGraph(com.graphhopper.routing.querygraph.QueryGraph)

Example 33 with QueryGraph

use of com.graphhopper.routing.querygraph.QueryGraph in project graphhopper by graphhopper.

the class CHTurnCostTest method testRouteViaVirtualNode.

@ParameterizedTest
@ValueSource(strings = { DIJKSTRA_BI, ASTAR_BI })
public void testRouteViaVirtualNode(String algo) {
    // 3
    // 0-x-1-2
    GHUtility.setSpeed(60, true, false, encoder, graph.edge(0, 1).setDistance(0));
    GHUtility.setSpeed(60, true, false, encoder, graph.edge(1, 2).setDistance(0));
    updateDistancesFor(graph, 0, 0.00, 0.00);
    updateDistancesFor(graph, 1, 0.02, 0.02);
    updateDistancesFor(graph, 2, 0.03, 0.03);
    graph.freeze();
    automaticPrepareCH();
    LocationIndexTree index = new LocationIndexTree(graph, new RAMDirectory());
    index.prepareIndex();
    Snap snap = index.findClosest(0.01, 0.01, EdgeFilter.ALL_EDGES);
    QueryGraph queryGraph = QueryGraph.create(graph, snap);
    assertEquals(3, snap.getClosestNode());
    assertEquals(0, snap.getClosestEdge().getEdge());
    RoutingAlgorithm chAlgo = new CHRoutingAlgorithmFactory(chGraph, queryGraph).createAlgo(new PMap().putObject(ALGORITHM, algo));
    Path path = chAlgo.calcPath(0, 2);
    assertTrue(path.isFound(), "it should be possible to route via a virtual node, but no path found");
    assertEquals(IntArrayList.from(0, 3, 1, 2), path.calcNodes());
    assertEquals(DistancePlaneProjection.DIST_PLANE.calcDist(0.00, 0.00, 0.03, 0.03), path.getDistance(), 1.e-1);
}
Also used : RoutingAlgorithm(com.graphhopper.routing.RoutingAlgorithm) Path(com.graphhopper.routing.Path) Snap(com.graphhopper.storage.index.Snap) QueryGraph(com.graphhopper.routing.querygraph.QueryGraph) LocationIndexTree(com.graphhopper.storage.index.LocationIndexTree) ValueSource(org.junit.jupiter.params.provider.ValueSource) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest)

Example 34 with QueryGraph

use of com.graphhopper.routing.querygraph.QueryGraph in project graphhopper by graphhopper.

the class CHTurnCostTest method testRouteViaVirtualNode_withAlternative.

@ParameterizedTest
@ValueSource(strings = { DIJKSTRA_BI, ASTAR_BI })
public void testRouteViaVirtualNode_withAlternative(String algo) {
    // 3
    // 0-x-1
    // \  |
    // \-2
    GHUtility.setSpeed(60, true, true, encoder, graph.edge(0, 1).setDistance(1));
    GHUtility.setSpeed(60, true, true, encoder, graph.edge(1, 2).setDistance(1));
    GHUtility.setSpeed(60, true, true, encoder, graph.edge(2, 0).setDistance(1));
    updateDistancesFor(graph, 0, 0.01, 0.00);
    updateDistancesFor(graph, 1, 0.01, 0.02);
    updateDistancesFor(graph, 2, 0.00, 0.02);
    graph.freeze();
    automaticPrepareCH();
    LocationIndexTree index = new LocationIndexTree(graph, new RAMDirectory());
    index.prepareIndex();
    Snap snap = index.findClosest(0.01, 0.01, EdgeFilter.ALL_EDGES);
    QueryGraph queryGraph = QueryGraph.create(graph, snap);
    assertEquals(3, snap.getClosestNode());
    assertEquals(0, snap.getClosestEdge().getEdge());
    QueryRoutingCHGraph routingCHGraph = new QueryRoutingCHGraph(chGraph, queryGraph);
    RoutingAlgorithm chAlgo = new CHRoutingAlgorithmFactory(routingCHGraph).createAlgo(new PMap().putObject(ALGORITHM, algo));
    Path path = chAlgo.calcPath(1, 0);
    assertEquals(IntArrayList.from(1, 3, 0), path.calcNodes());
}
Also used : RoutingAlgorithm(com.graphhopper.routing.RoutingAlgorithm) Path(com.graphhopper.routing.Path) QueryRoutingCHGraph(com.graphhopper.routing.querygraph.QueryRoutingCHGraph) Snap(com.graphhopper.storage.index.Snap) QueryGraph(com.graphhopper.routing.querygraph.QueryGraph) LocationIndexTree(com.graphhopper.storage.index.LocationIndexTree) ValueSource(org.junit.jupiter.params.provider.ValueSource) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest)

Example 35 with QueryGraph

use of com.graphhopper.routing.querygraph.QueryGraph in project graphhopper by graphhopper.

the class PrepareContractionHierarchiesTest method testStallOnDemandViaVirtuaNode_issue1574.

@Test
public void testStallOnDemandViaVirtuaNode_issue1574() {
    // this test reproduces the issue that appeared in issue1574
    // the problem is very intricate and a combination of all these things:
    // * contraction hierarchies
    // * stall-on-demand (without sod there is no problem, at least in this test)
    // * shortcuts weight rounding
    // * via nodes/virtual edges and the associated weight precision (without virtual nodes between source and target
    // there is no problem, but this can happen for via routes
    // * the fact that the CHLevelEdgeFilter always accepts virtual nodes
    // here we will construct a special case where a connection is not found without the fix in #1574.
    g = createGHStorage();
    // use fastest weighting in this test to be able to fine-tune some weights via the speed (see below)
    Weighting fastestWeighting = new FastestWeighting(carEncoder);
    CHConfig chConfig = CHConfig.nodeBased("c", fastestWeighting);
    // the following graph reproduces the issue. note that we will use the node ids as ch levels, so there will
    // be a shortcut 3->2 visible at node 2 and another one 3->4 visible at node 3.
    // we will fine-tune the edge-speeds such that without the fix node 4 will be stalled and node 5 will not get
    // discovered. consequently, no path will be found, because only the forward search runs (from 0 to 7 the
    // shortest path is strictly upward). node 4 is only stalled when node 2 gets stalled before, which in turn will
    // happen due to the virtual node between 3 and 1.
    // 
    // start 0 - 3 - x - 1 - 2
    // \         |
    // sc ---- 4 - 5 - 6 - 7 finish
    GHUtility.setSpeed(60, true, true, carEncoder, g.edge(0, 3).setDistance(1));
    EdgeIteratorState edge31 = GHUtility.setSpeed(60, true, true, carEncoder, g.edge(3, 1).setDistance(1));
    GHUtility.setSpeed(60, true, true, carEncoder, g.edge(1, 2).setDistance(1));
    EdgeIteratorState edge24 = GHUtility.setSpeed(60, true, true, carEncoder, g.edge(2, 4).setDistance(1));
    GHUtility.setSpeed(60, true, true, carEncoder, g.edge(4, 5).setDistance(1));
    GHUtility.setSpeed(60, true, true, carEncoder, g.edge(5, 6).setDistance(1));
    GHUtility.setSpeed(60, true, true, carEncoder, g.edge(6, 7).setDistance(1));
    updateDistancesFor(g, 0, 0.001, 0.0000);
    updateDistancesFor(g, 3, 0.001, 0.0001);
    updateDistancesFor(g, 1, 0.001, 0.0002);
    updateDistancesFor(g, 2, 0.001, 0.0003);
    updateDistancesFor(g, 4, 0.000, 0.0003);
    updateDistancesFor(g, 5, 0.000, 0.0004);
    updateDistancesFor(g, 6, 0.000, 0.0005);
    updateDistancesFor(g, 7, 0.000, 0.0006);
    // we use the speed to fine tune some weights:
    // the weight of edge 3-1 is chosen such that node 2 gets stalled in the forward search via the incoming shortcut
    // at node 2 coming from 3. this happens because due to the virtual node x between 3 and 1, the weight of the
    // spt entry at 2 is different to the sum of the weights of the spt entry at node 3 and the shortcut edge. this
    // is due to different floating point rounding arithmetic of shortcuts and virtual edges on the query graph.
    edge31.set(carEncoder.getAverageSpeedEnc(), 12, 12);
    // just stalling node 2 alone would not lead to connection not found, because the shortcut 3-4 still finds node
    // 4. however, we can choose the weight of edge 2-4 such that node 4 also gets stalled via node 2.
    // it is important that node 2 gets stalled before otherwise node 4 would have already be discovered.
    // note that without the virtual node between 3 and 1 node 2 would not even be explored in the forward search,
    // but because of the virtual node the strict upward search is modified and goes like 0-3-x-1-2.
    edge24.set(carEncoder.getAverageSpeedEnc(), 27.5, 27.5);
    // prepare ch, use node ids as levels
    PrepareContractionHierarchies pch = createPrepareContractionHierarchies(g, chConfig);
    PrepareContractionHierarchies.Result res = pch.useFixedNodeOrdering(NodeOrderingProvider.identity(g.getNodes())).doWork();
    RoutingCHGraph routingCHGraph = g.createCHGraph(res.getCHStorage(), res.getCHConfig());
    assertEquals(2, routingCHGraph.getEdges() - g.getEdges(), "there should be exactly two (bidirectional) shortcuts (2-3) and (3-4)");
    // insert virtual node and edges
    Snap snap = new Snap(0.0001, 0.0015);
    snap.setClosestEdge(edge31);
    snap.setSnappedPosition(Snap.Position.EDGE);
    snap.setClosestNode(8);
    snap.setWayIndex(0);
    snap.calcSnappedPoint(new DistanceCalcEuclidean());
    QueryGraph queryGraph = QueryGraph.create(g, snap);
    // we make sure our weight fine tunings do what they are supposed to
    double weight03 = getWeight(queryGraph, fastestWeighting, 0, 3, false);
    double scWeight23 = weight03 + getEdge(routingCHGraph, 2, 3, true).getWeight(false);
    double scWeight34 = weight03 + getEdge(routingCHGraph, 3, 4, false).getWeight(false);
    double sptWeight2 = weight03 + getWeight(queryGraph, fastestWeighting, 3, 8, false) + getWeight(queryGraph, fastestWeighting, 8, 1, false) + getWeight(queryGraph, fastestWeighting, 1, 2, false);
    double sptWeight4 = sptWeight2 + getWeight(queryGraph, fastestWeighting, 2, 4, false);
    assertTrue(scWeight23 < sptWeight2, "incoming shortcut weight 3->2 should be smaller than sptWeight at node 2 to make sure 2 gets stalled");
    assertTrue(sptWeight4 < scWeight34, "sptWeight at node 4 should be smaller than shortcut weight 3->4 to make sure node 4 gets stalled");
    Path path = new CHRoutingAlgorithmFactory(routingCHGraph, queryGraph).createAlgo(new PMap()).calcPath(0, 7);
    assertEquals(IntArrayList.from(0, 3, 8, 1, 2, 4, 5, 6, 7), path.calcNodes(), "wrong or no path found");
}
Also used : Path(com.graphhopper.routing.Path) Snap(com.graphhopper.storage.index.Snap) FastestWeighting(com.graphhopper.routing.weighting.FastestWeighting) Weighting(com.graphhopper.routing.weighting.Weighting) ShortestWeighting(com.graphhopper.routing.weighting.ShortestWeighting) FastestWeighting(com.graphhopper.routing.weighting.FastestWeighting) QueryGraph(com.graphhopper.routing.querygraph.QueryGraph) Test(org.junit.jupiter.api.Test)

Aggregations

QueryGraph (com.graphhopper.routing.querygraph.QueryGraph)37 Snap (com.graphhopper.storage.index.Snap)32 Test (org.junit.jupiter.api.Test)18 QueryRoutingCHGraph (com.graphhopper.routing.querygraph.QueryRoutingCHGraph)17 LocationIndexTree (com.graphhopper.storage.index.LocationIndexTree)16 EdgeIteratorState (com.graphhopper.util.EdgeIteratorState)11 Path (com.graphhopper.routing.Path)9 Weighting (com.graphhopper.routing.weighting.Weighting)9 ParameterizedTest (org.junit.jupiter.params.ParameterizedTest)7 RoutingAlgorithm (com.graphhopper.routing.RoutingAlgorithm)6 FastestWeighting (com.graphhopper.routing.weighting.FastestWeighting)6 PMap (com.graphhopper.util.PMap)6 ArrayList (java.util.ArrayList)6 GraphHopper (com.graphhopper.GraphHopper)5 GHPoint (com.graphhopper.util.shapes.GHPoint)5 ValueSource (org.junit.jupiter.params.provider.ValueSource)5 Graph (com.graphhopper.storage.Graph)4 LocationIndex (com.graphhopper.storage.index.LocationIndex)4 GHResponse (com.graphhopper.GHResponse)3 ResponsePath (com.graphhopper.ResponsePath)3