Search in sources :

Example 6 with GHBitSet

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

the class BaseGraph method inPlaceNodeRemove.

/**
 * This methods disconnects all edges from removed nodes. It does no edge compaction. Then it
 * moves the last nodes into the deleted nodes, where it needs to update the node ids in every
 * edge.
 */
void inPlaceNodeRemove(int removeNodeCount) {
    // Prepare edge-update of nodes which are connected to deleted nodes
    int toMoveNodes = getNodes();
    int itemsToMove = 0;
    // sorted map when we access it via keyAt and valueAt - see below!
    final SparseIntIntArray oldToNewMap = new SparseIntIntArray(removeNodeCount);
    GHBitSet toRemoveSet = new GHBitSetImpl(removeNodeCount);
    removedNodes.copyTo(toRemoveSet);
    Logger logger = LoggerFactory.getLogger(getClass());
    if (removeNodeCount > getNodes() / 2.0)
        logger.warn("More than a half of the network should be removed!? " + "Nodes:" + getNodes() + ", remove:" + removeNodeCount);
    EdgeExplorer delExplorer = createEdgeExplorer();
    // create map of old node ids pointing to new ids
    for (int removeNode = removedNodes.next(0); removeNode >= 0; removeNode = removedNodes.next(removeNode + 1)) {
        EdgeIterator delEdgesIter = delExplorer.setBaseNode(removeNode);
        while (delEdgesIter.next()) {
            toRemoveSet.add(delEdgesIter.getAdjNode());
        }
        toMoveNodes--;
        for (; toMoveNodes >= 0; toMoveNodes--) {
            if (!removedNodes.contains(toMoveNodes))
                break;
        }
        if (toMoveNodes >= removeNode)
            oldToNewMap.put(toMoveNodes, removeNode);
        itemsToMove++;
    }
    EdgeIterable adjNodesToDelIter = (EdgeIterable) createEdgeExplorer();
    // all deleted nodes could be connected to existing. remove the connections
    for (int removeNode = toRemoveSet.next(0); removeNode >= 0; removeNode = toRemoveSet.next(removeNode + 1)) {
        // remove all edges connected to the deleted nodes
        adjNodesToDelIter.setBaseNode(removeNode);
        long prev = EdgeIterator.NO_EDGE;
        while (adjNodesToDelIter.next()) {
            int nodeId = adjNodesToDelIter.getAdjNode();
            // already invalidated
            if (nodeId != EdgeAccess.NO_NODE && removedNodes.contains(nodeId)) {
                int edgeToRemove = adjNodesToDelIter.getEdge();
                long edgeToRemovePointer = edgeAccess.toPointer(edgeToRemove);
                edgeAccess.internalEdgeDisconnect(edgeToRemove, prev, removeNode, nodeId);
                edgeAccess.invalidateEdge(edgeToRemovePointer);
            } else {
                prev = adjNodesToDelIter.edgePointer;
            }
        }
    }
    GHBitSet toMoveSet = new GHBitSetImpl(removeNodeCount * 3);
    EdgeExplorer movedEdgeExplorer = createEdgeExplorer();
    // marks connected nodes to rewrite the edges
    for (int i = 0; i < itemsToMove; i++) {
        int oldI = oldToNewMap.keyAt(i);
        EdgeIterator movedEdgeIter = movedEdgeExplorer.setBaseNode(oldI);
        while (movedEdgeIter.next()) {
            int nodeId = movedEdgeIter.getAdjNode();
            if (nodeId == EdgeAccess.NO_NODE)
                continue;
            if (removedNodes.contains(nodeId))
                throw new IllegalStateException("shouldn't happen the edge to the node " + nodeId + " should be already deleted. " + oldI);
            toMoveSet.add(nodeId);
        }
    }
    // move nodes into deleted nodes
    for (int i = 0; i < itemsToMove; i++) {
        int oldI = oldToNewMap.keyAt(i);
        int newI = oldToNewMap.valueAt(i);
        long newOffset = (long) newI * nodeEntryBytes;
        long oldOffset = (long) oldI * nodeEntryBytes;
        for (long j = 0; j < nodeEntryBytes; j += 4) {
            nodes.setInt(newOffset + j, nodes.getInt(oldOffset + j));
        }
    }
    // *rewrites* all edges connected to moved nodes
    // go through all edges and pick the necessary <- this is easier to implement than
    // a more efficient (?) breadth-first search
    EdgeIterator iter = getAllEdges();
    while (iter.next()) {
        int nodeA = iter.getBaseNode();
        int nodeB = iter.getAdjNode();
        if (!toMoveSet.contains(nodeA) && !toMoveSet.contains(nodeB))
            continue;
        // now overwrite exiting edge with new node ids
        // also flags and links could have changed due to different node order
        int updatedA = oldToNewMap.get(nodeA);
        if (updatedA < 0)
            updatedA = nodeA;
        int updatedB = oldToNewMap.get(nodeB);
        if (updatedB < 0)
            updatedB = nodeB;
        int edgeId = iter.getEdge();
        long edgePointer = edgeAccess.toPointer(edgeId);
        int linkA = edgeAccess.getEdgeRef(nodeA, nodeB, edgePointer);
        int linkB = edgeAccess.getEdgeRef(nodeB, nodeA, edgePointer);
        long flags = edgeAccess.getFlags_(edgePointer, false);
        edgeAccess.writeEdge(edgeId, updatedA, updatedB, linkA, linkB);
        edgeAccess.setFlags_(edgePointer, updatedA > updatedB, flags);
        if (updatedA < updatedB != nodeA < nodeB)
            setWayGeometry_(fetchWayGeometry_(edgePointer, true, 0, -1, -1), edgePointer, false);
    }
    // clear N_EDGE_REF
    initNodeRefs((nodeCount - removeNodeCount) * nodeEntryBytes, nodeCount * nodeEntryBytes);
    if (removeNodeCount >= nodeCount)
        throw new IllegalStateException("graph is empty after in-place removal but was " + removeNodeCount);
    // we do not remove the invalid edges => edgeCount stays the same!
    nodeCount -= removeNodeCount;
    // health check
    if (isTestingEnabled()) {
        EdgeExplorer explorer = createEdgeExplorer();
        iter = getAllEdges();
        while (iter.next()) {
            int base = iter.getBaseNode();
            int adj = iter.getAdjNode();
            String str = iter.getEdge() + ", r.contains(" + base + "):" + removedNodes.contains(base) + ", r.contains(" + adj + "):" + removedNodes.contains(adj) + ", tr.contains(" + base + "):" + toRemoveSet.contains(base) + ", tr.contains(" + adj + "):" + toRemoveSet.contains(adj) + ", base:" + base + ", adj:" + adj + ", nodeCount:" + nodeCount;
            if (adj >= nodeCount)
                throw new RuntimeException("Adj.node problem with edge " + str);
            if (base >= nodeCount)
                throw new RuntimeException("Base node problem with edge " + str);
            try {
                explorer.setBaseNode(adj).toString();
            } catch (Exception ex) {
                org.slf4j.LoggerFactory.getLogger(getClass()).error("adj:" + adj);
            }
            try {
                explorer.setBaseNode(base).toString();
            } catch (Exception ex) {
                org.slf4j.LoggerFactory.getLogger(getClass()).error("base:" + base);
            }
        }
        // access last node -> no error
        explorer.setBaseNode(nodeCount - 1).toString();
    }
    removedNodes = null;
}
Also used : GHBitSet(com.graphhopper.coll.GHBitSet) Logger(org.slf4j.Logger) GHBitSetImpl(com.graphhopper.coll.GHBitSetImpl) SparseIntIntArray(com.graphhopper.coll.SparseIntIntArray)

Example 7 with GHBitSet

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

the class Location2IDQuadtree method findClosest.

@Override
public QueryResult findClosest(final double queryLat, final double queryLon, final EdgeFilter edgeFilter) {
    if (isClosed())
        throw new IllegalStateException("You need to create a new LocationIndex instance as it is already closed");
    if (edgeFilter != EdgeFilter.ALL_EDGES)
        throw new UnsupportedOperationException("edge filters are not yet implemented for " + Location2IDQuadtree.class.getSimpleName());
    // The following cases (e.g. dead ends or motorways crossing a normal way) could be problematic:
    // |     |
    // |  P  |
    // |  |  |< --- maxRasterWidth reached
    // \-----/
    /*
         * Problem: use additionally the 8 surrounding quadrants: There an error due to the raster
         * width. Because this index does not cover 100% of the graph you'll need to traverse the
         * graph until you find the real matching point or if you reach the raster width limit. And
         * there is a problem when using the raster limit as 'not found' indication and if you have
         * arbitrary requests e.g. from other systems (where points do not match exactly): Although
         * P is the closest point to the request one it could be that the raster limit is too short
         * to reach it via graph traversal:
         */
    long key = keyAlgo.encode(queryLat, queryLon);
    final int id = index.getInt(key * 4);
    double mainLat = nodeAccess.getLatitude(id);
    double mainLon = nodeAccess.getLongitude(id);
    final QueryResult res = new QueryResult(queryLat, queryLon);
    res.setClosestNode(id);
    res.setQueryDistance(distCalc.calcNormalizedDist(queryLat, queryLon, mainLat, mainLon));
    goFurtherHook(id);
    new BreadthFirstSearch() {

        @Override
        protected GHBitSet createBitSet() {
            return new GHTBitSet(10);
        }

        @Override
        protected boolean goFurther(int baseNode) {
            if (baseNode == id)
                return true;
            goFurtherHook(baseNode);
            double currLat = nodeAccess.getLatitude(baseNode);
            double currLon = nodeAccess.getLongitude(baseNode);
            double currNormedDist = distCalc.calcNormalizedDist(queryLat, queryLon, currLat, currLon);
            if (currNormedDist < res.getQueryDistance()) {
                res.setQueryDistance(currNormedDist);
                res.setClosestNode(baseNode);
                return true;
            }
            return currNormedDist < maxRasterWidth2InMeterNormed;
        }
    }.start(graph.createEdgeExplorer(), id);
    // denormalize distance
    res.setQueryDistance(distCalc.calcDenormalizedDist(res.getQueryDistance()));
    return res;
}
Also used : GHTBitSet(com.graphhopper.coll.GHTBitSet) BreadthFirstSearch(com.graphhopper.util.BreadthFirstSearch) GHBitSet(com.graphhopper.coll.GHBitSet) GHPoint(com.graphhopper.util.shapes.GHPoint)

Example 8 with GHBitSet

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

the class Location2IDQuadtree method fillEmptyIndices.

private int fillEmptyIndices(GHBitSet filledIndices) {
    int len = latSize * lonSize;
    DataAccess indexCopy = new RAMDirectory().find("temp_index_copy");
    indexCopy.setSegmentSize(index.getSegmentSize()).create(index.getCapacity());
    GHBitSet indicesCopy = new GHBitSetImpl(len);
    int initializedCounter = filledIndices.getCardinality();
    // fan out initialized entries to avoid "nose-artifacts"
    // we 1. do not use the same index for check and set and iterate until all indices are set
    // and 2. use a taken-from array to decide which of the colliding should be preferred
    int[] takenFrom = new int[len];
    Arrays.fill(takenFrom, -1);
    for (int i = filledIndices.next(0); i >= 0; i = filledIndices.next(i + 1)) {
        takenFrom[i] = i;
    }
    if (initializedCounter == 0) {
        throw new IllegalStateException("at least one entry has to be != null, which should have happened in initIndex");
    }
    int tmp = initializedCounter;
    while (initializedCounter < len) {
        index.copyTo(indexCopy);
        filledIndices.copyTo(indicesCopy);
        initializedCounter = filledIndices.getCardinality();
        for (int i = 0; i < len; i++) {
            int to = -1, from = -1;
            if (indicesCopy.contains(i)) {
                // check change "initialized to empty"
                if ((i + 1) % lonSize != 0 && !indicesCopy.contains(i + 1)) {
                    // set right from current
                    from = i;
                    to = i + 1;
                } else if (i + lonSize < len && !indicesCopy.contains(i + lonSize)) {
                    // set below from current
                    from = i;
                    to = i + lonSize;
                }
            } else // check change "empty to initialized"
            if ((i + 1) % lonSize != 0 && indicesCopy.contains(i + 1)) {
                // set from right
                from = i + 1;
                to = i;
            } else if (i + lonSize < len && indicesCopy.contains(i + lonSize)) {
                // set from below
                from = i + lonSize;
                to = i;
            }
            if (to >= 0) {
                if (takenFrom[to] >= 0) {
                    // takenFrom[to] == to -> special case for normedDist == 0
                    if (takenFrom[to] == to || getNormedDist(from, to) >= getNormedDist(takenFrom[to], to)) {
                        continue;
                    }
                }
                index.setInt(to * 4, indexCopy.getInt(from * 4));
                takenFrom[to] = takenFrom[from];
                filledIndices.add(to);
                initializedCounter++;
            }
        }
    }
    return initializedCounter - tmp;
}
Also used : GHBitSetImpl(com.graphhopper.coll.GHBitSetImpl) GHBitSet(com.graphhopper.coll.GHBitSet) GHPoint(com.graphhopper.util.shapes.GHPoint)

Example 9 with GHBitSet

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

the class LocationIndexTree method findNClosest.

/**
 * Returns all edges that are within the specified radius around the queried position.
 * Searches at most 9 cells to avoid performance problems. Hence, if the radius is larger than
 * the cell width then not all edges might be returned.
 *
 * TODO: either clarify the method name and description (to only search e.g. 9 tiles) or
 * refactor so it can handle a radius larger than 9 tiles. Also remove reference to 'NClosest',
 * which is misleading, and don't always return at least one value. See map-matching #65.
 * TODO: tidy up logic - see comments in graphhopper #994.
 *
 * @param radius in meters
 */
public List<QueryResult> findNClosest(final double queryLat, final double queryLon, final EdgeFilter edgeFilter, double radius) {
    // Return ALL results which are very close and e.g. within the GPS signal accuracy.
    // Also important to get all edges if GPS point is close to a junction.
    final double returnAllResultsWithin = distCalc.calcNormalizedDist(radius);
    // implement a cheap priority queue via List, sublist and Collections.sort
    final List<QueryResult> queryResults = new ArrayList<QueryResult>();
    GHIntHashSet set = new GHIntHashSet();
    // Doing 2 iterations means searching 9 tiles.
    for (int iteration = 0; iteration < 2; iteration++) {
        // should we use the return value of earlyFinish?
        findNetworkEntries(queryLat, queryLon, set, iteration);
        final GHBitSet exploredNodes = new GHTBitSet(new GHIntHashSet(set));
        final EdgeExplorer explorer = graph.createEdgeExplorer(edgeFilter);
        set.forEach(new IntPredicate() {

            @Override
            public boolean apply(int node) {
                new XFirstSearchCheck(queryLat, queryLon, exploredNodes, edgeFilter) {

                    @Override
                    protected double getQueryDistance() {
                        // do not skip search if distance is 0 or near zero (equalNormedDelta)
                        return Double.MAX_VALUE;
                    }

                    @Override
                    protected boolean check(int node, double normedDist, int wayIndex, EdgeIteratorState edge, QueryResult.Position pos) {
                        if (normedDist < returnAllResultsWithin || queryResults.isEmpty() || queryResults.get(0).getQueryDistance() > normedDist) {
                            // TODO: refactor below:
                            // - should only add edges within search radius (below allows the
                            // returning of a candidate outside search radius if it's the only
                            // one). Removing this test would simplify it a lot and probably
                            // match the expected behaviour (see method description)
                            // - create QueryResult first and the add/set as required - clean up
                            // the index tracking business.
                            int index = -1;
                            for (int qrIndex = 0; qrIndex < queryResults.size(); qrIndex++) {
                                QueryResult qr = queryResults.get(qrIndex);
                                // overwrite older queryResults which are potentially more far away than returnAllResultsWithin
                                if (qr.getQueryDistance() > returnAllResultsWithin) {
                                    index = qrIndex;
                                    break;
                                }
                                // avoid duplicate edges
                                if (qr.getClosestEdge().getEdge() == edge.getEdge()) {
                                    if (qr.getQueryDistance() < normedDist) {
                                        // do not add current edge
                                        return true;
                                    } else {
                                        // overwrite old edge with current
                                        index = qrIndex;
                                        break;
                                    }
                                }
                            }
                            QueryResult qr = new QueryResult(queryLat, queryLon);
                            qr.setQueryDistance(normedDist);
                            qr.setClosestNode(node);
                            qr.setClosestEdge(edge.detach(false));
                            qr.setWayIndex(wayIndex);
                            qr.setSnappedPosition(pos);
                            if (index < 0) {
                                queryResults.add(qr);
                            } else {
                                queryResults.set(index, qr);
                            }
                        }
                        return true;
                    }
                }.start(explorer, node);
                return true;
            }
        });
    }
    // TODO: pass boolean argument for whether or not to sort? Can be expensive if not required.
    Collections.sort(queryResults, QR_COMPARATOR);
    for (QueryResult qr : queryResults) {
        if (qr.isValid()) {
            // denormalize distance
            qr.setQueryDistance(distCalc.calcDenormalizedDist(qr.getQueryDistance()));
            qr.calcSnappedPoint(distCalc);
        } else {
            throw new IllegalStateException("Invalid QueryResult should not happen here: " + qr);
        }
    }
    return queryResults;
}
Also used : GHIntHashSet(com.graphhopper.coll.GHIntHashSet) IntPredicate(com.carrotsearch.hppc.predicates.IntPredicate) GHBitSet(com.graphhopper.coll.GHBitSet) ArrayList(java.util.ArrayList) IntArrayList(com.carrotsearch.hppc.IntArrayList) GHPoint(com.graphhopper.util.shapes.GHPoint) GHTBitSet(com.graphhopper.coll.GHTBitSet)

Example 10 with GHBitSet

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

the class DepthFirstSearch method start.

/**
 * beginning with startNode add all following nodes to LIFO queue. If node has been already
 * explored before, skip reexploration.
 */
@Override
public void start(EdgeExplorer explorer, int startNode) {
    IntArrayDeque stack = new IntArrayDeque();
    GHBitSet explored = createBitSet();
    stack.addLast(startNode);
    int current;
    while (stack.size() > 0) {
        current = stack.removeLast();
        if (!explored.contains(current) && goFurther(current)) {
            EdgeIterator iter = explorer.setBaseNode(current);
            while (iter.next()) {
                int connectedId = iter.getAdjNode();
                if (checkAdjacent(iter)) {
                    stack.addLast(connectedId);
                }
            }
            explored.add(current);
        }
    }
}
Also used : GHBitSet(com.graphhopper.coll.GHBitSet) IntArrayDeque(com.carrotsearch.hppc.IntArrayDeque)

Aggregations

GHBitSet (com.graphhopper.coll.GHBitSet)14 GHBitSetImpl (com.graphhopper.coll.GHBitSetImpl)7 GHPoint (com.graphhopper.util.shapes.GHPoint)6 GHTBitSet (com.graphhopper.coll.GHTBitSet)3 IntArrayList (com.carrotsearch.hppc.IntArrayList)2 IntPredicate (com.carrotsearch.hppc.predicates.IntPredicate)2 GHIntArrayList (com.graphhopper.coll.GHIntArrayList)2 GHIntHashSet (com.graphhopper.coll.GHIntHashSet)2 ArrayList (java.util.ArrayList)2 IntArrayDeque (com.carrotsearch.hppc.IntArrayDeque)1 GraphHopper (com.graphhopper.GraphHopper)1 SparseIntIntArray (com.graphhopper.coll.SparseIntIntArray)1 DataReader (com.graphhopper.reader.DataReader)1 GraphHopperOSM (com.graphhopper.reader.osm.GraphHopperOSM)1 AllEdgesIterator (com.graphhopper.routing.util.AllEdgesIterator)1 FlagEncoder (com.graphhopper.routing.util.FlagEncoder)1 Weighting (com.graphhopper.routing.weighting.Weighting)1 CHGraph (com.graphhopper.storage.CHGraph)1 GraphHopperStorage (com.graphhopper.storage.GraphHopperStorage)1 BreadthFirstSearch (com.graphhopper.util.BreadthFirstSearch)1