Search in sources :

Example 1 with GHIntObjectHashMap

use of com.graphhopper.coll.GHIntObjectHashMap 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 2 with GHIntObjectHashMap

use of com.graphhopper.coll.GHIntObjectHashMap in project graphhopper by graphhopper.

the class QueryOverlayBuilder method buildVirtualEdges.

/**
 * For all specified snaps calculate the snapped point and if necessary set the closest node
 * to a virtual one and reverse the closest edge. Additionally the wayIndex can change if an edge is
 * swapped.
 */
private void buildVirtualEdges(List<Snap> snaps) {
    GHIntObjectHashMap<List<Snap>> edge2res = new GHIntObjectHashMap<>(snaps.size());
    // calculate snapped point and swap direction of closest edge if necessary
    for (Snap snap : snaps) {
        // Do not create virtual node for a snap if it is directly on a tower node or not found
        if (snap.getSnappedPosition() == Snap.Position.TOWER)
            continue;
        EdgeIteratorState closestEdge = snap.getClosestEdge();
        if (closestEdge == null)
            throw new IllegalStateException("Do not call QueryGraph.create with invalid Snap " + snap);
        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(FetchMode.PILLAR_ONLY);
            if (pl.size() > 1)
                doReverse = pl.getLat(0) > pl.getLat(pl.size() - 1);
        }
        if (doReverse) {
            closestEdge = closestEdge.detach(true);
            PointList fullPL = closestEdge.fetchWayGeometry(FetchMode.ALL);
            snap.setClosestEdge(closestEdge);
            if (snap.getSnappedPosition() == Snap.Position.PILLAR)
                // ON pillar node
                snap.setWayIndex(fullPL.size() - snap.getWayIndex() - 1);
            else
                // for case "OFF pillar node"
                snap.setWayIndex(fullPL.size() - snap.getWayIndex() - 2);
            if (snap.getWayIndex() < 0)
                throw new IllegalStateException("Problem with wayIndex while reversing closest edge:" + closestEdge + ", " + snap);
        }
        // find multiple results on same edge
        int edgeId = closestEdge.getEdge();
        List<Snap> list = edge2res.get(edgeId);
        if (list == null) {
            list = new ArrayList<>(5);
            edge2res.put(edgeId, list);
        }
        list.add(snap);
    }
    // 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<Snap>>() {

        @Override
        public boolean apply(int edgeId, List<Snap> results) {
            // we can expect at least one entry in the results
            EdgeIteratorState closestEdge = results.get(0).getClosestEdge();
            final PointList fullPL = closestEdge.fetchWayGeometry(FetchMode.ALL);
            int baseNode = closestEdge.getBaseNode();
            Collections.sort(results, new Comparator<Snap>() {

                @Override
                public int compare(Snap o1, Snap o2) {
                    int diff = Integer.compare(o1.getWayIndex(), o2.getWayIndex());
                    if (diff == 0) {
                        return Double.compare(distanceOfSnappedPointToPillarNode(o1), distanceOfSnappedPointToPillarNode(o2));
                    } else {
                        return diff;
                    }
                }

                private double distanceOfSnappedPointToPillarNode(Snap o) {
                    GHPoint snappedPoint = o.getSnappedPoint();
                    double fromLat = fullPL.getLat(o.getWayIndex());
                    double fromLon = fullPL.getLon(o.getWayIndex());
                    return DistancePlaneProjection.DIST_PLANE.calcNormalizedDist(fromLat, fromLon, snappedPoint.lat, snappedPoint.lon);
                }
            });
            GHPoint3D prevPoint = fullPL.get(0);
            int adjNode = closestEdge.getAdjNode();
            int origEdgeKey = closestEdge.getEdgeKey();
            int origRevEdgeKey = GHUtility.reverseEdgeKey(origEdgeKey);
            int prevWayIndex = 1;
            int prevNodeId = baseNode;
            int virtNodeId = queryOverlay.getVirtualNodes().size() + firstVirtualNodeId;
            boolean addedEdges = false;
            // fullPL into the right pieces.
            for (Snap res : results) {
                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;
                }
                queryOverlay.getClosestEdges().add(res.getClosestEdge().getEdge());
                boolean isPillar = res.getSnappedPosition() == Snap.Position.PILLAR;
                createEdges(origEdgeKey, origRevEdgeKey, prevPoint, prevWayIndex, isPillar, res.getSnappedPoint(), res.getWayIndex(), fullPL, closestEdge, prevNodeId, virtNodeId);
                queryOverlay.getVirtualNodes().add(currSnapped.lat, currSnapped.lon, currSnapped.ele);
                // add edges again to set adjacent edges for newVirtNodeId
                if (addedEdges) {
                    queryOverlay.addVirtualEdge(queryOverlay.getVirtualEdge(queryOverlay.getNumVirtualEdges() - 2));
                    queryOverlay.addVirtualEdge(queryOverlay.getVirtualEdge(queryOverlay.getNumVirtualEdges() - 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(origEdgeKey, origRevEdgeKey, prevPoint, prevWayIndex, false, fullPL.get(fullPL.size() - 1), fullPL.size() - 2, fullPL, closestEdge, virtNodeId - 1, adjNode);
            return true;
        }
    });
}
Also used : GHIntObjectHashMap(com.graphhopper.coll.GHIntObjectHashMap) GHPoint3D(com.graphhopper.util.shapes.GHPoint3D) Snap(com.graphhopper.storage.index.Snap) GHPoint(com.graphhopper.util.shapes.GHPoint) Comparator(java.util.Comparator) List(java.util.List) ArrayList(java.util.ArrayList) GHPoint(com.graphhopper.util.shapes.GHPoint)

Example 3 with GHIntObjectHashMap

use of com.graphhopper.coll.GHIntObjectHashMap in project graphhopper by graphhopper.

the class QueryGraph method createUncachedEdgeExplorer.

private EdgeExplorer createUncachedEdgeExplorer(EdgeFilter edgeFilter) {
    // Iteration over virtual nodes needs to be thread safe if done from different explorer
    // so we need to create the mapping on EVERY call!
    // This needs to be a HashMap (and cannot be an array) as we also need to tweak edges for some mainNodes!
    // The more query points we have the more inefficient this map could be. Hmmh.
    final IntObjectMap<VirtualEdgeIterator> node2EdgeMap = new GHIntObjectHashMap<VirtualEdgeIterator>(queryResults.size() * 3);
    final EdgeExplorer mainExplorer = mainGraph.createEdgeExplorer(edgeFilter);
    final GHIntHashSet towerNodesToChange = new GHIntHashSet(queryResults.size());
    // 1. virtualEdges should also get fresh EdgeIterators on every createEdgeExplorer call!
    for (int i = 0; i < queryResults.size(); i++) {
        // create outgoing edges
        VirtualEdgeIterator virtEdgeIter = new VirtualEdgeIterator(2);
        EdgeIteratorState baseRevEdge = virtualEdges.get(i * 4 + VE_BASE_REV);
        if (edgeFilter.accept(baseRevEdge))
            virtEdgeIter.add(baseRevEdge);
        EdgeIteratorState adjEdge = virtualEdges.get(i * 4 + VE_ADJ);
        if (edgeFilter.accept(adjEdge))
            virtEdgeIter.add(adjEdge);
        int virtNode = mainNodes + i;
        node2EdgeMap.put(virtNode, virtEdgeIter);
        // replace edge list of neighboring tower nodes:
        // add virtual edges only and collect tower nodes where real edges will be added in step 2.
        // 
        // base node
        int towerNode = baseRevEdge.getAdjNode();
        if (!isVirtualNode(towerNode)) {
            towerNodesToChange.add(towerNode);
            addVirtualEdges(node2EdgeMap, edgeFilter, true, towerNode, i);
        }
        // adj node
        towerNode = adjEdge.getAdjNode();
        if (!isVirtualNode(towerNode)) {
            towerNodesToChange.add(towerNode);
            addVirtualEdges(node2EdgeMap, edgeFilter, false, towerNode, i);
        }
    }
    // 2. the connected tower nodes from mainGraph need fresh EdgeIterators with possible fakes
    // where 'fresh' means independent of previous call and respecting the edgeFilter
    // -> setup fake iterators of detected tower nodes (virtual edges are already added)
    towerNodesToChange.forEach(new IntProcedure() {

        @Override
        public void apply(int value) {
            fillVirtualEdges(node2EdgeMap, value, mainExplorer);
        }
    });
    return new EdgeExplorer() {

        @Override
        public EdgeIterator setBaseNode(int baseNode) {
            VirtualEdgeIterator iter = node2EdgeMap.get(baseNode);
            if (iter != null)
                return iter.reset();
            return mainExplorer.setBaseNode(baseNode);
        }
    };
}
Also used : GHIntHashSet(com.graphhopper.coll.GHIntHashSet) GHIntObjectHashMap(com.graphhopper.coll.GHIntObjectHashMap) IntProcedure(com.carrotsearch.hppc.procedures.IntProcedure) GHPoint(com.graphhopper.util.shapes.GHPoint)

Aggregations

GHIntObjectHashMap (com.graphhopper.coll.GHIntObjectHashMap)3 GHPoint (com.graphhopper.util.shapes.GHPoint)3 GHPoint3D (com.graphhopper.util.shapes.GHPoint3D)2 IntArrayList (com.carrotsearch.hppc.IntArrayList)1 IntProcedure (com.carrotsearch.hppc.procedures.IntProcedure)1 GHIntHashSet (com.graphhopper.coll.GHIntHashSet)1 QueryResult (com.graphhopper.storage.index.QueryResult)1 Snap (com.graphhopper.storage.index.Snap)1 ArrayList (java.util.ArrayList)1 Comparator (java.util.Comparator)1 List (java.util.List)1