Search in sources :

Example 1 with SparseIntIntArray

use of com.graphhopper.coll.SparseIntIntArray 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);
    }
    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)

Aggregations

GHBitSet (com.graphhopper.coll.GHBitSet)1 GHBitSetImpl (com.graphhopper.coll.GHBitSetImpl)1 SparseIntIntArray (com.graphhopper.coll.SparseIntIntArray)1 Logger (org.slf4j.Logger)1