EccentricityStorage.java

  1. /*
  2.  *  Licensed to GraphHopper GmbH under one or more contributor
  3.  *  license agreements. See the NOTICE file distributed with this work for
  4.  *  additional information regarding copyright ownership.
  5.  *
  6.  *  GraphHopper GmbH licenses this file to you under the Apache License,
  7.  *  Version 2.0 (the "License"); you may not use this file except in
  8.  *  compliance with the License. You may obtain a copy of the License at
  9.  *
  10.  *       http://www.apache.org/licenses/LICENSE-2.0
  11.  *
  12.  *  Unless required by applicable law or agreed to in writing, software
  13.  *  distributed under the License is distributed on an "AS IS" BASIS,
  14.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15.  *  See the License for the specific language governing permissions and
  16.  *  limitations under the License.
  17.  */
  18. package org.heigit.ors.fastisochrones.storage;

  19. import com.carrotsearch.hppc.IntLongHashMap;
  20. import com.carrotsearch.hppc.cursors.IntLongCursor;
  21. import com.graphhopper.routing.weighting.Weighting;
  22. import com.graphhopper.storage.DataAccess;
  23. import com.graphhopper.storage.Directory;
  24. import com.graphhopper.storage.Storable;
  25. import org.heigit.ors.fastisochrones.partitioning.storage.IsochroneNodeStorage;
  26. import org.heigit.ors.util.FileUtility;

  27. import static org.heigit.ors.fastisochrones.storage.ByteConversion.byteArrayToLong;
  28. import static org.heigit.ors.fastisochrones.storage.ByteConversion.longToByteArray;

  29. /**
  30.  * Stores eccentricities of cell border nodes for fast isochrones. Eccentricities are weighting dependent, therefore they are stored separately from cells.
  31.  *
  32.  * @author Hendrik Leuschner
  33.  */
  34. public class EccentricityStorage implements Storable<EccentricityStorage> {
  35.     private final DataAccess eccentricities;
  36.     private final int eccentricityBytes;
  37.     private final int mapBytes;
  38.     private final int eccentricityPosition;
  39.     private final int nodeCount;
  40.     private final Weighting weighting;
  41.     private final IsochroneNodeStorage isochroneNodeStorage;
  42.     private int borderNodeIndexOffset;
  43.     private int borderNodePointer;
  44.     private IntLongHashMap borderNodeToPointerMap;
  45.     private int borderNodeCount;

  46.     /**
  47.      * Instantiates a new Eccentricity storage.
  48.      *
  49.      * @param dir                  the dir
  50.      * @param weighting            the weighting
  51.      * @param isochroneNodeStorage the isochrone node storage
  52.      */
  53.     public EccentricityStorage(Directory dir, Weighting weighting, IsochroneNodeStorage isochroneNodeStorage, int nodeCount) {
  54.         //A map of nodeId to pointer is stored in the first block.
  55.         //The second block stores 2 values for each pointer, full reachability and eccentricity
  56.         final String name = FileUtility.weightingToFileName(weighting);
  57.         eccentricities = dir.find("eccentricities_" + name);
  58.         this.weighting = weighting;
  59.         this.isochroneNodeStorage = isochroneNodeStorage;
  60.         this.nodeCount = nodeCount;
  61.         //  2 ints per node, first is fully reachable, second is eccentricity
  62.         this.eccentricityBytes = 8;
  63.         this.mapBytes = 12;
  64.         this.eccentricityPosition = 4;
  65.     }

  66.     public boolean loadExisting() {
  67.         if (eccentricities.loadExisting()) {
  68.             borderNodeCount = eccentricities.getHeader(0);
  69.             borderNodeIndexOffset = borderNodeCount * mapBytes;
  70.             borderNodePointer = borderNodeIndexOffset;
  71.             borderNodeToPointerMap = new IntLongHashMap(borderNodeCount);
  72.             loadBorderNodeToPointerMap();
  73.             return true;
  74.         }
  75.         return false;
  76.     }

  77.     /**
  78.      * Init.
  79.      */
  80.     public void init() {
  81.         eccentricities.create(1000);
  82.         borderNodeCount = getNumBorderNodes();
  83.         eccentricities.setHeader(0, borderNodeCount);
  84.         borderNodeIndexOffset = borderNodeCount * mapBytes;
  85.         borderNodePointer = borderNodeIndexOffset;
  86.         borderNodeToPointerMap = new IntLongHashMap();
  87.         generateBorderNodeToPointerMap();
  88.         eccentricities.ensureCapacity((long) borderNodeIndexOffset + (long) borderNodeCount * eccentricityBytes);
  89.     }

  90.     private int getNumBorderNodes() {
  91.         int count = 0;
  92.         for (int node = 0; node < nodeCount; node++) {
  93.             if (isochroneNodeStorage.getBorderness(node)) {
  94.                 count++;
  95.             }
  96.         }
  97.         return count;
  98.     }

  99.     private void generateBorderNodeToPointerMap() {
  100.         for (int node = 0; node < nodeCount; node++) {
  101.             if (isochroneNodeStorage.getBorderness(node)) {
  102.                 borderNodeToPointerMap.put(node, borderNodePointer);
  103.                 borderNodePointer += (long) eccentricityBytes;
  104.             }
  105.         }
  106.     }

  107.     /**
  108.      * Sets eccentricity.
  109.      *
  110.      * @param node         the node
  111.      * @param eccentricity the eccentricity
  112.      */
  113.     public void setEccentricity(int node, double eccentricity) {
  114.         eccentricities.setInt(borderNodeToPointerMap.get(node) + eccentricityPosition, (int) Math.ceil(eccentricity));
  115.     }

  116.     /**
  117.      * Gets eccentricity.
  118.      *
  119.      * @param node the node
  120.      * @return the eccentricity
  121.      */
  122.     public int getEccentricity(int node) {
  123.         long index = borderNodeToPointerMap.get(node);
  124.         if (index == 0)
  125.             throw new IllegalArgumentException("Requested node is not a border node");
  126.         return eccentricities.getInt(index + eccentricityPosition);
  127.     }

  128.     /**
  129.      * Sets fully reachable.
  130.      *
  131.      * @param node             the node
  132.      * @param isFullyReachable the is fully reachable
  133.      */
  134.     public void setFullyReachable(int node, boolean isFullyReachable) {
  135.         if (isFullyReachable)
  136.             eccentricities.setInt(borderNodeToPointerMap.get(node), 1);
  137.         else
  138.             eccentricities.setInt(borderNodeToPointerMap.get(node), 0);
  139.     }

  140.     /**
  141.      * Gets fully reachable.
  142.      *
  143.      * @param node the node
  144.      * @return the fully reachable
  145.      */
  146.     public boolean getFullyReachable(int node) {
  147.         int isFullyReachable = eccentricities.getInt(borderNodeToPointerMap.get(node));
  148.         return isFullyReachable == 1;
  149.     }

  150.     /**
  151.      * Store border node to pointer map.
  152.      */
  153.     public void storeBorderNodeToPointerMap() {
  154.         long listPointer = 0;
  155.         long nodePointer;
  156.         for (IntLongCursor borderNode : borderNodeToPointerMap) {
  157.             eccentricities.setInt(listPointer, borderNode.key);
  158.             listPointer = listPointer + 4;
  159.             nodePointer = borderNode.value;
  160.             eccentricities.setBytes(listPointer, longToByteArray(nodePointer), 8);
  161.             listPointer = listPointer + 8;
  162.         }
  163.     }

  164.     private void loadBorderNodeToPointerMap() {
  165.         byte[] buffer = new byte[8];
  166.         long listPointer = 0;
  167.         for (int i = 0; i < borderNodeCount; i++) {
  168.             int borderNode = eccentricities.getInt(listPointer);
  169.             listPointer = listPointer + 4;
  170.             eccentricities.getBytes(listPointer, buffer, 8);
  171.             long nodePointer = byteArrayToLong(buffer);
  172.             listPointer = listPointer + (long) 8;
  173.             borderNodeToPointerMap.put(borderNode, nodePointer);
  174.         }
  175.     }

  176.     public EccentricityStorage create(long byteCount) {
  177.         throw new IllegalStateException("Do not call EccentricityStorage.create directly");
  178.     }

  179.     public void flush() {
  180.         eccentricities.flush();
  181.     }

  182.     @Override
  183.     public void close() {
  184.         eccentricities.close();
  185.     }

  186.     @Override
  187.     public boolean isClosed() {
  188.         return eccentricities.isClosed();
  189.     }

  190.     public long getCapacity() {
  191.         return eccentricities.getCapacity();
  192.     }

  193.     /**
  194.      * Gets weighting.
  195.      *
  196.      * @return the weighting
  197.      */
  198.     public Weighting getWeighting() {
  199.         return weighting;
  200.     }

  201.     public boolean hasWeighting(Weighting weighting) {
  202.         return getWeighting().getName() != null
  203.                 && getWeighting().getName().equals(weighting.getName())
  204.                 && getWeighting().getFlagEncoder().toString() != null
  205.                 && getWeighting().getFlagEncoder().toString().equals(weighting.getFlagEncoder().toString());
  206.     }
  207. }