Search in sources :

Example 11 with QueryResult

use of com.graphhopper.storage.index.QueryResult in project graphhopper by graphhopper.

the class QueryGraphTest method testTurnCostsProperlyPropagated_Issue282.

@Test
public void testTurnCostsProperlyPropagated_Issue282() {
    TurnCostExtension turnExt = new TurnCostExtension();
    FlagEncoder encoder = new CarFlagEncoder(5, 5, 15);
    GraphHopperStorage graphWithTurnCosts = new GraphHopperStorage(new RAMDirectory(), new EncodingManager(encoder), false, turnExt).create(100);
    NodeAccess na = graphWithTurnCosts.getNodeAccess();
    na.setNode(0, .00, .00);
    na.setNode(1, .00, .01);
    na.setNode(2, .01, .01);
    EdgeIteratorState edge0 = graphWithTurnCosts.edge(0, 1, 10, true);
    EdgeIteratorState edge1 = graphWithTurnCosts.edge(2, 1, 10, true);
    QueryGraph qGraph = new QueryGraph(graphWithTurnCosts);
    FastestWeighting weighting = new FastestWeighting(encoder);
    TurnWeighting turnWeighting = new TurnWeighting(weighting, (TurnCostExtension) qGraph.getExtension());
    assertEquals(0, turnWeighting.calcTurnWeight(edge0.getEdge(), 1, edge1.getEdge()), .1);
    // now use turn costs and QueryGraph
    turnExt.addTurnInfo(edge0.getEdge(), 1, edge1.getEdge(), encoder.getTurnFlags(false, 10));
    assertEquals(10, turnWeighting.calcTurnWeight(edge0.getEdge(), 1, edge1.getEdge()), .1);
    QueryResult res1 = createLocationResult(0.000, 0.005, edge0, 0, QueryResult.Position.EDGE);
    QueryResult res2 = createLocationResult(0.005, 0.010, edge1, 0, QueryResult.Position.EDGE);
    qGraph.lookup(Arrays.asList(res1, res2));
    int fromQueryEdge = GHUtility.getEdge(qGraph, res1.getClosestNode(), 1).getEdge();
    int toQueryEdge = GHUtility.getEdge(qGraph, res2.getClosestNode(), 1).getEdge();
    assertEquals(10, turnWeighting.calcTurnWeight(fromQueryEdge, 1, toQueryEdge), .1);
    graphWithTurnCosts.close();
}
Also used : TurnWeighting(com.graphhopper.routing.weighting.TurnWeighting) GHPoint(com.graphhopper.util.shapes.GHPoint) QueryResult(com.graphhopper.storage.index.QueryResult) FastestWeighting(com.graphhopper.routing.weighting.FastestWeighting) Test(org.junit.Test)

Example 12 with QueryResult

use of com.graphhopper.storage.index.QueryResult in project graphhopper by graphhopper.

the class GraphHopperStorageCHTest method testQueryGraph.

@Test
public void testQueryGraph() {
    graph = createGHStorage();
    CHGraph chGraph = getGraph(graph);
    NodeAccess na = chGraph.getNodeAccess();
    na.setNode(0, 1.00, 1.00);
    na.setNode(1, 1.02, 1.00);
    na.setNode(2, 1.04, 1.00);
    EdgeIteratorState edge1 = chGraph.edge(0, 1);
    chGraph.edge(1, 2);
    graph.freeze();
    chGraph.shortcut(0, 1);
    QueryGraph qGraph = new QueryGraph(chGraph);
    QueryResult fromRes = createQR(1.004, 1.01, 0, edge1);
    QueryResult toRes = createQR(1.019, 1.00, 0, edge1);
    qGraph.lookup(fromRes, toRes);
    Graph baseGraph = qGraph.getBaseGraph();
    EdgeExplorer explorer = baseGraph.createEdgeExplorer();
    assertTrue(chGraph.getNodes() < qGraph.getNodes());
    assertTrue(baseGraph.getNodes() == qGraph.getNodes());
    // traverse virtual edges and normal edges but no shortcuts!
    assertEquals(GHUtility.asSet(fromRes.getClosestNode()), GHUtility.getNeighbors(explorer.setBaseNode(0)));
    assertEquals(GHUtility.asSet(toRes.getClosestNode(), 2), GHUtility.getNeighbors(explorer.setBaseNode(1)));
    // get neighbors from virtual nodes
    assertEquals(GHUtility.asSet(0, toRes.getClosestNode()), GHUtility.getNeighbors(explorer.setBaseNode(fromRes.getClosestNode())));
    assertEquals(GHUtility.asSet(1, fromRes.getClosestNode()), GHUtility.getNeighbors(explorer.setBaseNode(toRes.getClosestNode())));
}
Also used : QueryResult(com.graphhopper.storage.index.QueryResult) QueryGraph(com.graphhopper.routing.QueryGraph) QueryGraph(com.graphhopper.routing.QueryGraph) Test(org.junit.Test)

Example 13 with QueryResult

use of com.graphhopper.storage.index.QueryResult in project graphhopper by graphhopper.

the class GraphHopper method calcPaths.

/**
 * This method calculates the alternative path list using the low level Path objects.
 */
public List<Path> calcPaths(GHRequest request, GHResponse ghRsp) {
    if (ghStorage == null || !fullyLoaded)
        throw new IllegalStateException("Do a successful call to load or importOrLoad before routing");
    if (ghStorage.isClosed())
        throw new IllegalStateException("You need to create a new GraphHopper instance as it is already closed");
    // default handling
    String vehicle = request.getVehicle();
    if (vehicle.isEmpty()) {
        vehicle = getDefaultVehicle().toString();
        request.setVehicle(vehicle);
    }
    Lock readLock = readWriteLock.readLock();
    readLock.lock();
    try {
        if (!encodingManager.supports(vehicle))
            throw new IllegalArgumentException("Vehicle " + vehicle + " unsupported. " + "Supported are: " + getEncodingManager());
        HintsMap hints = request.getHints();
        String tModeStr = hints.get("traversal_mode", traversalMode.toString());
        TraversalMode tMode = TraversalMode.fromString(tModeStr);
        if (hints.has(Routing.EDGE_BASED))
            tMode = hints.getBool(Routing.EDGE_BASED, false) ? TraversalMode.EDGE_BASED_2DIR : TraversalMode.NODE_BASED;
        FlagEncoder encoder = encodingManager.getEncoder(vehicle);
        boolean disableCH = hints.getBool(CH.DISABLE, false);
        if (!chFactoryDecorator.isDisablingAllowed() && disableCH)
            throw new IllegalArgumentException("Disabling CH not allowed on the server-side");
        boolean disableLM = hints.getBool(Landmark.DISABLE, false);
        if (!lmFactoryDecorator.isDisablingAllowed() && disableLM)
            throw new IllegalArgumentException("Disabling LM not allowed on the server-side");
        String algoStr = request.getAlgorithm();
        if (algoStr.isEmpty())
            algoStr = chFactoryDecorator.isEnabled() && !disableCH ? DIJKSTRA_BI : ASTAR_BI;
        List<GHPoint> points = request.getPoints();
        // TODO Maybe we should think about a isRequestValid method that checks all that stuff that we could do to fail fast
        // For example see #734
        checkIfPointsAreInBounds(points);
        RoutingTemplate routingTemplate;
        if (ROUND_TRIP.equalsIgnoreCase(algoStr))
            routingTemplate = new RoundTripRoutingTemplate(request, ghRsp, locationIndex, maxRoundTripRetries);
        else if (ALT_ROUTE.equalsIgnoreCase(algoStr))
            routingTemplate = new AlternativeRoutingTemplate(request, ghRsp, locationIndex);
        else
            routingTemplate = new ViaRoutingTemplate(request, ghRsp, locationIndex);
        List<Path> altPaths = null;
        int maxRetries = routingTemplate.getMaxRetries();
        Locale locale = request.getLocale();
        Translation tr = trMap.getWithFallBack(locale);
        for (int i = 0; i < maxRetries; i++) {
            StopWatch sw = new StopWatch().start();
            List<QueryResult> qResults = routingTemplate.lookup(points, encoder);
            ghRsp.addDebugInfo("idLookup:" + sw.stop().getSeconds() + "s");
            if (ghRsp.hasErrors())
                return Collections.emptyList();
            RoutingAlgorithmFactory tmpAlgoFactory = getAlgorithmFactory(hints);
            Weighting weighting;
            QueryGraph queryGraph;
            if (chFactoryDecorator.isEnabled() && !disableCH) {
                boolean forceCHHeading = hints.getBool(CH.FORCE_HEADING, false);
                if (!forceCHHeading && request.hasFavoredHeading(0))
                    throw new IllegalArgumentException("Heading is not (fully) supported for CHGraph. See issue #483");
                // if LM is enabled we have the LMFactory with the CH algo!
                RoutingAlgorithmFactory chAlgoFactory = tmpAlgoFactory;
                if (tmpAlgoFactory instanceof LMAlgoFactoryDecorator.LMRAFactory)
                    chAlgoFactory = ((LMAlgoFactoryDecorator.LMRAFactory) tmpAlgoFactory).getDefaultAlgoFactory();
                if (chAlgoFactory instanceof PrepareContractionHierarchies)
                    weighting = ((PrepareContractionHierarchies) chAlgoFactory).getWeighting();
                else
                    throw new IllegalStateException("Although CH was enabled a non-CH algorithm factory was returned " + tmpAlgoFactory);
                tMode = getCHFactoryDecorator().getNodeBase();
                queryGraph = new QueryGraph(ghStorage.getGraph(CHGraph.class, weighting));
                queryGraph.lookup(qResults);
            } else {
                checkNonChMaxWaypointDistance(points);
                queryGraph = new QueryGraph(ghStorage);
                queryGraph.lookup(qResults);
                weighting = createWeighting(hints, encoder, queryGraph);
                ghRsp.addDebugInfo("tmode:" + tMode.toString());
            }
            int maxVisitedNodesForRequest = hints.getInt(Routing.MAX_VISITED_NODES, maxVisitedNodes);
            if (maxVisitedNodesForRequest > maxVisitedNodes)
                throw new IllegalArgumentException("The max_visited_nodes parameter has to be below or equal to:" + maxVisitedNodes);
            weighting = createTurnWeighting(queryGraph, weighting, tMode);
            AlgorithmOptions algoOpts = AlgorithmOptions.start().algorithm(algoStr).traversalMode(tMode).weighting(weighting).maxVisitedNodes(maxVisitedNodesForRequest).hints(hints).build();
            altPaths = routingTemplate.calcPaths(queryGraph, tmpAlgoFactory, algoOpts);
            boolean tmpEnableInstructions = hints.getBool(Routing.INSTRUCTIONS, enableInstructions);
            boolean tmpCalcPoints = hints.getBool(Routing.CALC_POINTS, calcPoints);
            double wayPointMaxDistance = hints.getDouble(Routing.WAY_POINT_MAX_DISTANCE, 1d);
            DouglasPeucker peucker = new DouglasPeucker().setMaxDistance(wayPointMaxDistance);
            PathMerger pathMerger = new PathMerger().setCalcPoints(tmpCalcPoints).setDouglasPeucker(peucker).setEnableInstructions(tmpEnableInstructions).setPathDetailsBuilders(pathBuilderFactory, request.getPathDetails()).setSimplifyResponse(simplifyResponse && wayPointMaxDistance > 0);
            if (request.hasFavoredHeading(0))
                pathMerger.setFavoredHeading(request.getFavoredHeading(0));
            if (routingTemplate.isReady(pathMerger, tr))
                break;
        }
        return altPaths;
    } catch (IllegalArgumentException ex) {
        ghRsp.addError(ex);
        return Collections.emptyList();
    } finally {
        readLock.unlock();
    }
}
Also used : AlternativeRoutingTemplate(com.graphhopper.routing.template.AlternativeRoutingTemplate) RoundTripRoutingTemplate(com.graphhopper.routing.template.RoundTripRoutingTemplate) RoutingTemplate(com.graphhopper.routing.template.RoutingTemplate) ViaRoutingTemplate(com.graphhopper.routing.template.ViaRoutingTemplate) AlternativeRoutingTemplate(com.graphhopper.routing.template.AlternativeRoutingTemplate) ViaRoutingTemplate(com.graphhopper.routing.template.ViaRoutingTemplate) QueryResult(com.graphhopper.storage.index.QueryResult) RoundTripRoutingTemplate(com.graphhopper.routing.template.RoundTripRoutingTemplate) PrepareContractionHierarchies(com.graphhopper.routing.ch.PrepareContractionHierarchies) GHPoint(com.graphhopper.util.shapes.GHPoint) ReentrantReadWriteLock(java.util.concurrent.locks.ReentrantReadWriteLock) ReadWriteLock(java.util.concurrent.locks.ReadWriteLock) Lock(java.util.concurrent.locks.Lock) GHPoint(com.graphhopper.util.shapes.GHPoint)

Example 14 with QueryResult

use of com.graphhopper.storage.index.QueryResult in project graphhopper by graphhopper.

the class QueryGraph method lookup.

/**
 * For all specified query results calculate snapped point and if necessary set closest node
 * to a virtual one and reverse closest edge. Additionally the wayIndex can change if an edge is
 * swapped.
 *
 * @see QueryGraph
 */
public void lookup(List<QueryResult> resList) {
    if (isInitialized())
        throw new IllegalStateException("Call lookup only once. Otherwise you'll have problems for queries sharing the same edge.");
    // initialize all none-final variables
    virtualEdges = new ArrayList<VirtualEdgeIteratorState>(resList.size() * 2);
    virtualNodes = new PointList(resList.size(), mainNodeAccess.is3D());
    queryResults = new ArrayList<QueryResult>(resList.size());
    baseGraph.virtualEdges = virtualEdges;
    baseGraph.virtualNodes = virtualNodes;
    baseGraph.queryResults = queryResults;
    GHIntObjectHashMap<List<QueryResult>> edge2res = new GHIntObjectHashMap<List<QueryResult>>(resList.size());
    // calculate snapped point and swap direction of closest edge if necessary
    for (QueryResult res : resList) {
        // Do not create virtual node for a query result if it is directly on a tower node or not found
        if (res.getSnappedPosition() == QueryResult.Position.TOWER)
            continue;
        EdgeIteratorState closestEdge = res.getClosestEdge();
        if (closestEdge == null)
            throw new IllegalStateException("Do not call QueryGraph.lookup with invalid QueryResult " + res);
        int base = closestEdge.getBaseNode();
        // Force the identical direction for all closest edges.
        // It is important to sort multiple results for the same edge by its wayIndex
        boolean doReverse = base > closestEdge.getAdjNode();
        if (base == closestEdge.getAdjNode()) {
            // check for special case #162 where adj == base and force direction via latitude comparison
            PointList pl = closestEdge.fetchWayGeometry(0);
            if (pl.size() > 1)
                doReverse = pl.getLatitude(0) > pl.getLatitude(pl.size() - 1);
        }
        if (doReverse) {
            closestEdge = closestEdge.detach(true);
            PointList fullPL = closestEdge.fetchWayGeometry(3);
            res.setClosestEdge(closestEdge);
            if (res.getSnappedPosition() == QueryResult.Position.PILLAR)
                // ON pillar node
                res.setWayIndex(fullPL.getSize() - res.getWayIndex() - 1);
            else
                // for case "OFF pillar node"
                res.setWayIndex(fullPL.getSize() - res.getWayIndex() - 2);
            if (res.getWayIndex() < 0)
                throw new IllegalStateException("Problem with wayIndex while reversing closest edge:" + closestEdge + ", " + res);
        }
        // find multiple results on same edge
        int edgeId = closestEdge.getEdge();
        List<QueryResult> list = edge2res.get(edgeId);
        if (list == null) {
            list = new ArrayList<QueryResult>(5);
            edge2res.put(edgeId, list);
        }
        list.add(res);
    }
    // Phase 2 - now it is clear which points cut one edge
    // 1. create point lists
    // 2. create virtual edges between virtual nodes and its neighbor (virtual or normal nodes)
    edge2res.forEach(new IntObjectPredicate<List<QueryResult>>() {

        @Override
        public boolean apply(int edgeId, List<QueryResult> results) {
            // we can expect at least one entry in the results
            EdgeIteratorState closestEdge = results.get(0).getClosestEdge();
            final PointList fullPL = closestEdge.fetchWayGeometry(3);
            int baseNode = closestEdge.getBaseNode();
            // sort results on the same edge by the wayIndex and if equal by distance to pillar node
            Collections.sort(results, new Comparator<QueryResult>() {

                @Override
                public int compare(QueryResult o1, QueryResult o2) {
                    int diff = o1.getWayIndex() - o2.getWayIndex();
                    if (diff == 0) {
                        // sort by distance from snappedPoint to fullPL.get(wayIndex) if wayIndex is identical
                        GHPoint p1 = o1.getSnappedPoint();
                        GHPoint p2 = o2.getSnappedPoint();
                        if (p1.equals(p2))
                            return 0;
                        double fromLat = fullPL.getLatitude(o1.getWayIndex());
                        double fromLon = fullPL.getLongitude(o1.getWayIndex());
                        if (Helper.DIST_PLANE.calcNormalizedDist(fromLat, fromLon, p1.lat, p1.lon) > Helper.DIST_PLANE.calcNormalizedDist(fromLat, fromLon, p2.lat, p2.lon))
                            return 1;
                        return -1;
                    }
                    return diff;
                }
            });
            GHPoint3D prevPoint = fullPL.toGHPoint(0);
            int adjNode = closestEdge.getAdjNode();
            int origTraversalKey = GHUtility.createEdgeKey(baseNode, adjNode, closestEdge.getEdge(), false);
            int origRevTraversalKey = GHUtility.createEdgeKey(baseNode, adjNode, closestEdge.getEdge(), true);
            long reverseFlags = closestEdge.detach(true).getFlags();
            int prevWayIndex = 1;
            int prevNodeId = baseNode;
            int virtNodeId = virtualNodes.getSize() + mainNodes;
            boolean addedEdges = false;
            // fullPL into the right pieces.
            for (int counter = 0; counter < results.size(); counter++) {
                QueryResult res = results.get(counter);
                if (res.getClosestEdge().getBaseNode() != baseNode)
                    throw new IllegalStateException("Base nodes have to be identical but were not: " + closestEdge + " vs " + res.getClosestEdge());
                GHPoint3D currSnapped = res.getSnappedPoint();
                // no new virtual nodes if exactly the same snapped point
                if (prevPoint.equals(currSnapped)) {
                    res.setClosestNode(prevNodeId);
                    continue;
                }
                queryResults.add(res);
                createEdges(origTraversalKey, origRevTraversalKey, prevPoint, prevWayIndex, res.getSnappedPoint(), res.getWayIndex(), fullPL, closestEdge, prevNodeId, virtNodeId, reverseFlags);
                virtualNodes.add(currSnapped.lat, currSnapped.lon, currSnapped.ele);
                // add edges again to set adjacent edges for newVirtNodeId
                if (addedEdges) {
                    virtualEdges.add(virtualEdges.get(virtualEdges.size() - 2));
                    virtualEdges.add(virtualEdges.get(virtualEdges.size() - 2));
                }
                addedEdges = true;
                res.setClosestNode(virtNodeId);
                prevNodeId = virtNodeId;
                prevWayIndex = res.getWayIndex() + 1;
                prevPoint = currSnapped;
                virtNodeId++;
            }
            // two edges between last result and adjacent node are still missing if not all points skipped
            if (addedEdges)
                createEdges(origTraversalKey, origRevTraversalKey, prevPoint, prevWayIndex, fullPL.toGHPoint(fullPL.getSize() - 1), fullPL.getSize() - 2, fullPL, closestEdge, virtNodeId - 1, adjNode, reverseFlags);
            return true;
        }
    });
}
Also used : GHIntObjectHashMap(com.graphhopper.coll.GHIntObjectHashMap) GHPoint3D(com.graphhopper.util.shapes.GHPoint3D) GHPoint(com.graphhopper.util.shapes.GHPoint) QueryResult(com.graphhopper.storage.index.QueryResult) IntArrayList(com.carrotsearch.hppc.IntArrayList) GHPoint(com.graphhopper.util.shapes.GHPoint)

Example 15 with QueryResult

use of com.graphhopper.storage.index.QueryResult in project graphhopper by graphhopper.

the class ViaRoutingTemplate method calcPaths.

@Override
public List<Path> calcPaths(QueryGraph queryGraph, RoutingAlgorithmFactory algoFactory, AlgorithmOptions algoOpts) {
    long visitedNodesSum = 0L;
    boolean viaTurnPenalty = ghRequest.getHints().getBool(Routing.PASS_THROUGH, false);
    int pointCounts = ghRequest.getPoints().size();
    pathList = new ArrayList<>(pointCounts - 1);
    QueryResult fromQResult = queryResults.get(0);
    StopWatch sw;
    for (int placeIndex = 1; placeIndex < pointCounts; placeIndex++) {
        if (placeIndex == 1) {
            // enforce start direction
            queryGraph.enforceHeading(fromQResult.getClosestNode(), ghRequest.getFavoredHeading(0), false);
        } else if (viaTurnPenalty) {
            // enforce straight start after via stop
            Path prevRoute = pathList.get(placeIndex - 2);
            if (prevRoute.getEdgeCount() > 0) {
                EdgeIteratorState incomingVirtualEdge = prevRoute.getFinalEdge();
                queryGraph.unfavorVirtualEdgePair(fromQResult.getClosestNode(), incomingVirtualEdge.getEdge());
            }
        }
        QueryResult toQResult = queryResults.get(placeIndex);
        // enforce end direction
        queryGraph.enforceHeading(toQResult.getClosestNode(), ghRequest.getFavoredHeading(placeIndex), true);
        sw = new StopWatch().start();
        RoutingAlgorithm algo = algoFactory.createAlgo(queryGraph, algoOpts);
        String debug = ", algoInit:" + sw.stop().getSeconds() + "s";
        sw = new StopWatch().start();
        List<Path> tmpPathList = algo.calcPaths(fromQResult.getClosestNode(), toQResult.getClosestNode());
        debug += ", " + algo.getName() + "-routing:" + sw.stop().getSeconds() + "s";
        if (tmpPathList.isEmpty())
            throw new IllegalStateException("At least one path has to be returned for " + fromQResult + " -> " + toQResult);
        int idx = 0;
        for (Path path : tmpPathList) {
            if (path.getTime() < 0)
                throw new RuntimeException("Time was negative " + path.getTime() + " for index " + idx + ". Please report as bug and include:" + ghRequest);
            pathList.add(path);
            debug += ", " + path.getDebugInfo();
            idx++;
        }
        altResponse.addDebugInfo(debug);
        // reset all direction enforcements in queryGraph to avoid influencing next path
        queryGraph.clearUnfavoredStatus();
        if (algo.getVisitedNodes() >= algoOpts.getMaxVisitedNodes())
            throw new IllegalArgumentException("No path found due to maximum nodes exceeded " + algoOpts.getMaxVisitedNodes());
        visitedNodesSum += algo.getVisitedNodes();
        fromQResult = toQResult;
    }
    ghResponse.getHints().put("visited_nodes.sum", visitedNodesSum);
    ghResponse.getHints().put("visited_nodes.average", (float) visitedNodesSum / (pointCounts - 1));
    return pathList;
}
Also used : GHPoint(com.graphhopper.util.shapes.GHPoint) StopWatch(com.graphhopper.util.StopWatch) QueryResult(com.graphhopper.storage.index.QueryResult) EdgeIteratorState(com.graphhopper.util.EdgeIteratorState)

Aggregations

QueryResult (com.graphhopper.storage.index.QueryResult)39 GHPoint (com.graphhopper.util.shapes.GHPoint)20 Test (org.junit.Test)20 FastestWeighting (com.graphhopper.routing.weighting.FastestWeighting)4 LocationIndex (com.graphhopper.storage.index.LocationIndex)4 Weighting (com.graphhopper.routing.weighting.Weighting)3 LocationIndexTree (com.graphhopper.storage.index.LocationIndexTree)3 GHRequest (com.graphhopper.GHRequest)2 GHResponse (com.graphhopper.GHResponse)2 EdgeFilter (com.graphhopper.routing.util.EdgeFilter)2 EdgeIteratorState (com.graphhopper.util.EdgeIteratorState)2 PointNotFoundException (com.graphhopper.util.exceptions.PointNotFoundException)2 GHPoint3D (com.graphhopper.util.shapes.GHPoint3D)2 IntArrayList (com.carrotsearch.hppc.IntArrayList)1 IntObjectMap (com.carrotsearch.hppc.IntObjectMap)1 Stop (com.conveyal.gtfs.model.Stop)1 ArrayNode (com.fasterxml.jackson.databind.node.ArrayNode)1 ObjectNode (com.fasterxml.jackson.databind.node.ObjectNode)1 GraphHopper (com.graphhopper.GraphHopper)1 GHIntObjectHashMap (com.graphhopper.coll.GHIntObjectHashMap)1