FastIsochroneAlgorithm.java
- /* This file is part of Openrouteservice.
- *
- * Openrouteservice is free software; you can redistribute it and/or modify it under the terms of the
- * GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- * You should have received a copy of the GNU Lesser General Public License along with this library;
- * if not, see <https://www.gnu.org/licenses/>.
- */
- package org.heigit.ors.fastisochrones;
- import com.carrotsearch.hppc.IntObjectMap;
- import com.carrotsearch.hppc.cursors.IntObjectCursor;
- import com.graphhopper.coll.GHIntObjectHashMap;
- import com.graphhopper.routing.SPTEntry;
- import com.graphhopper.routing.util.EdgeFilter;
- import com.graphhopper.routing.util.TraversalMode;
- import com.graphhopper.routing.weighting.Weighting;
- import com.graphhopper.storage.Graph;
- import org.heigit.ors.fastisochrones.partitioning.storage.CellStorage;
- import org.heigit.ors.fastisochrones.partitioning.storage.IsochroneNodeStorage;
- import org.heigit.ors.fastisochrones.storage.BorderNodeDistanceStorage;
- import org.heigit.ors.fastisochrones.storage.EccentricityStorage;
- import org.heigit.ors.routing.graphhopper.extensions.edgefilters.EdgeFilterSequence;
- import java.util.*;
- /**
- * Implementation of Fast Isochrones
- * <p>
- *
- * @author Hendrik Leuschner
- */
- public class FastIsochroneAlgorithm extends AbstractIsochroneAlgorithm {
- private static final String NAME = "FastIsochrone";
- protected IntObjectMap<SPTEntry> startCellMap;
- protected Set<Integer> activeBorderNodes;
- protected Set<Integer> inactiveBorderNodes;
- protected Set<Integer> fullyReachableCells;
- protected Map<Integer, Map<Integer, Double>> upAndCoreGraphDistMap;
- protected Map<Integer, IntObjectMap<SPTEntry>> activeCellMaps;
- int from;
- int fromNonVirtual;
- public FastIsochroneAlgorithm(Graph graph,
- Weighting weighting,
- TraversalMode tMode,
- CellStorage cellStorage,
- IsochroneNodeStorage isochroneNodeStorage,
- EccentricityStorage eccentricityStorage,
- BorderNodeDistanceStorage borderNodeDistanceStorage,
- EdgeFilter additionalEdgeFilter) {
- super(graph, weighting, tMode, cellStorage, isochroneNodeStorage, eccentricityStorage, borderNodeDistanceStorage, additionalEdgeFilter);
- }
- @Override
- protected void initCollections(int size) {
- startCellMap = new GHIntObjectHashMap<>(size);
- }
- @Override
- public void init(int from, int fromNonVirtual, double isochroneLimit) {
- this.from = from;
- this.fromNonVirtual = fromNonVirtual;
- this.isochroneLimit = isochroneLimit;
- activeBorderNodes = new HashSet<>();
- inactiveBorderNodes = new HashSet<>();
- fullyReachableCells = new HashSet<>();
- upAndCoreGraphDistMap = new HashMap<>();
- }
- @Override
- void runStartCellPhase() {
- int startCell = isochroneNodeStorage.getCellId(fromNonVirtual);
- CoreRangeDijkstra coreRangeDijkstra = new CoreRangeDijkstra(graph, weighting, isochroneNodeStorage, borderNodeDistanceStorage);
- EdgeFilterSequence edgeFilterSequence = new EdgeFilterSequence();
- if (additionalEdgeFilter != null)
- edgeFilterSequence.add(additionalEdgeFilter);
- edgeFilterSequence.add(
- new CellAndBorderNodeFilter(isochroneNodeStorage,
- startCell,
- graph.getNodes())
- );
- coreRangeDijkstra.setEdgeFilter(edgeFilterSequence);
- coreRangeDijkstra.setIsochroneLimit(isochroneLimit);
- coreRangeDijkstra.initFrom(from);
- coreRangeDijkstra.runAlgo();
- startCellMap = coreRangeDijkstra.getFromMap();
- findFullyReachableCells(startCellMap);
- for (int inactiveBorderNode : inactiveBorderNodes) {
- startCellMap.remove(inactiveBorderNode);
- activeBorderNodes.remove(inactiveBorderNode);
- }
- for (int sweepEndNode : activeBorderNodes) {
- double dist = coreRangeDijkstra.fromMap.get(sweepEndNode).getWeightOfVisitedPath();
- int cell = isochroneNodeStorage.getCellId(sweepEndNode);
- if (cell == startCell)
- continue;
- if (!upAndCoreGraphDistMap.containsKey(cell))
- upAndCoreGraphDistMap.put(cell, new HashMap<>());
- upAndCoreGraphDistMap.get(cell).put(sweepEndNode, dist);
- startCellMap.remove(sweepEndNode);
- }
- }
- @Override
- public boolean finishedStartCellPhase() {
- return true;
- }
- /**
- * Run the ALT algo in the core
- */
- @Override
- void runBorderNodePhase() {
- //This implementation combines running in the start cell and running on the border nodes in one phase
- }
- @Override
- public boolean finishedBorderNodePhase() {
- //This implementation combines running in the start cell and running on the border nodes in one phase
- return true;
- }
- @Override
- void runActiveCellPhase() {
- activeCellMaps = new HashMap<>(upAndCoreGraphDistMap.entrySet().size());
- activeCellMaps.put(isochroneNodeStorage.getCellId(fromNonVirtual), startCellMap);
- for (Map.Entry<Integer, Map<Integer, Double>> entry : upAndCoreGraphDistMap.entrySet()) {
- ActiveCellDijkstra activeCellDijkstra = new ActiveCellDijkstra(graph, weighting, isochroneNodeStorage, entry.getKey());
- activeCellDijkstra.setIsochroneLimit(isochroneLimit);
- //Add all the start points with their respective already visited weight
- for (int nodeId : entry.getValue().keySet()) {
- activeCellDijkstra.addInitialBordernode(nodeId, entry.getValue().get(nodeId));
- }
- activeCellDijkstra.init();
- activeCellDijkstra.runAlgo();
- activeCellMaps.put(entry.getKey(), activeCellDijkstra.getFromMap());
- }
- }
- @Override
- public boolean finishedActiveCellPhase() {
- return false;
- }
- private void findFullyReachableCells(IntObjectMap<SPTEntry> entryMap) {
- for (IntObjectCursor<SPTEntry> entry : entryMap) {
- int baseNode = entry.key;
- if (!isochroneNodeStorage.getBorderness(baseNode))
- continue;
- SPTEntry sptEntry = entry.value;
- int baseCell = isochroneNodeStorage.getCellId(baseNode);
- int eccentricity = eccentricityStorage.getEccentricity(baseNode);
- if (isWithinLimit(sptEntry, eccentricity)
- && eccentricityStorage.getFullyReachable(baseNode)) {
- addFullyReachableCell(baseCell);
- addInactiveBorderNode(baseNode);
- } else {
- if (!getFullyReachableCells().contains(baseCell)) {
- addActiveBorderNode(baseNode);
- }
- }
- }
- }
- /**
- * Consider all active cells that have a percentage of *approximation* of their nodes visited to be fully reachable.
- *
- * @param approximation factor of approximation. 1 means all nodes must be found, 0 means no nodes have to be found.
- */
- public void approximateActiveCells(double approximation) {
- Iterator<Map.Entry<Integer, IntObjectMap<SPTEntry>>> activeCellIterator = getActiveCellMaps().entrySet().iterator();
- while (activeCellIterator.hasNext()) {
- Map.Entry<Integer, IntObjectMap<SPTEntry>> activeCell = activeCellIterator.next();
- if (activeCell.getValue().size() / (double) cellStorage.getNodesOfCell(activeCell.getKey()).size() > approximation) {
- activeCellIterator.remove();
- getFullyReachableCells().add(activeCell.getKey());
- }
- }
- }
- private boolean isWithinLimit(SPTEntry sptEntry, int eccentricity) {
- return sptEntry.getWeightOfVisitedPath() + eccentricity <= isochroneLimit;
- }
- private void addFullyReachableCell(int cellId) {
- fullyReachableCells.add(cellId);
- }
- protected void addActiveBorderNode(int nodeId) {
- activeBorderNodes.add(nodeId);
- }
- protected void addInactiveBorderNode(int nodeId) {
- inactiveBorderNodes.add(nodeId);
- }
- public Set<Integer> getFullyReachableCells() {
- return fullyReachableCells;
- }
- public IntObjectMap<SPTEntry> getStartCellMap() {
- return startCellMap;
- }
- public String getName() {
- return NAME;
- }
- public Map<Integer, IntObjectMap<SPTEntry>> getActiveCellMaps() {
- return activeCellMaps;
- }
- }