EccentricityStorage.java
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.heigit.ors.fastisochrones.storage;
import com.carrotsearch.hppc.IntLongHashMap;
import com.carrotsearch.hppc.cursors.IntLongCursor;
import com.graphhopper.routing.weighting.Weighting;
import com.graphhopper.storage.DataAccess;
import com.graphhopper.storage.Directory;
import com.graphhopper.storage.Storable;
import org.heigit.ors.fastisochrones.partitioning.storage.IsochroneNodeStorage;
import org.heigit.ors.util.FileUtility;
import static org.heigit.ors.fastisochrones.storage.ByteConversion.byteArrayToLong;
import static org.heigit.ors.fastisochrones.storage.ByteConversion.longToByteArray;
/**
* Stores eccentricities of cell border nodes for fast isochrones. Eccentricities are weighting dependent, therefore they are stored separately from cells.
*
* @author Hendrik Leuschner
*/
public class EccentricityStorage implements Storable<EccentricityStorage> {
private final DataAccess eccentricities;
private final int eccentricityBytes;
private final int mapBytes;
private final int eccentricityPosition;
private final int nodeCount;
private final Weighting weighting;
private final IsochroneNodeStorage isochroneNodeStorage;
private int borderNodeIndexOffset;
private int borderNodePointer;
private IntLongHashMap borderNodeToPointerMap;
private int borderNodeCount;
/**
* Instantiates a new Eccentricity storage.
*
* @param dir the dir
* @param weighting the weighting
* @param isochroneNodeStorage the isochrone node storage
*/
public EccentricityStorage(Directory dir, Weighting weighting, IsochroneNodeStorage isochroneNodeStorage, int nodeCount) {
//A map of nodeId to pointer is stored in the first block.
//The second block stores 2 values for each pointer, full reachability and eccentricity
final String name = FileUtility.weightingToFileName(weighting);
eccentricities = dir.find("eccentricities_" + name);
this.weighting = weighting;
this.isochroneNodeStorage = isochroneNodeStorage;
this.nodeCount = nodeCount;
// 2 ints per node, first is fully reachable, second is eccentricity
this.eccentricityBytes = 8;
this.mapBytes = 12;
this.eccentricityPosition = 4;
}
public boolean loadExisting() {
if (eccentricities.loadExisting()) {
borderNodeCount = eccentricities.getHeader(0);
borderNodeIndexOffset = borderNodeCount * mapBytes;
borderNodePointer = borderNodeIndexOffset;
borderNodeToPointerMap = new IntLongHashMap(borderNodeCount);
loadBorderNodeToPointerMap();
return true;
}
return false;
}
/**
* Init.
*/
public void init() {
eccentricities.create(1000);
borderNodeCount = getNumBorderNodes();
eccentricities.setHeader(0, borderNodeCount);
borderNodeIndexOffset = borderNodeCount * mapBytes;
borderNodePointer = borderNodeIndexOffset;
borderNodeToPointerMap = new IntLongHashMap();
generateBorderNodeToPointerMap();
eccentricities.ensureCapacity((long) borderNodeIndexOffset + (long) borderNodeCount * eccentricityBytes);
}
private int getNumBorderNodes() {
int count = 0;
for (int node = 0; node < nodeCount; node++) {
if (isochroneNodeStorage.getBorderness(node)) {
count++;
}
}
return count;
}
private void generateBorderNodeToPointerMap() {
for (int node = 0; node < nodeCount; node++) {
if (isochroneNodeStorage.getBorderness(node)) {
borderNodeToPointerMap.put(node, borderNodePointer);
borderNodePointer += (long) eccentricityBytes;
}
}
}
/**
* Sets eccentricity.
*
* @param node the node
* @param eccentricity the eccentricity
*/
public void setEccentricity(int node, double eccentricity) {
eccentricities.setInt(borderNodeToPointerMap.get(node) + eccentricityPosition, (int) Math.ceil(eccentricity));
}
/**
* Gets eccentricity.
*
* @param node the node
* @return the eccentricity
*/
public int getEccentricity(int node) {
long index = borderNodeToPointerMap.get(node);
if (index == 0)
throw new IllegalArgumentException("Requested node is not a border node");
return eccentricities.getInt(index + eccentricityPosition);
}
/**
* Sets fully reachable.
*
* @param node the node
* @param isFullyReachable the is fully reachable
*/
public void setFullyReachable(int node, boolean isFullyReachable) {
if (isFullyReachable)
eccentricities.setInt(borderNodeToPointerMap.get(node), 1);
else
eccentricities.setInt(borderNodeToPointerMap.get(node), 0);
}
/**
* Gets fully reachable.
*
* @param node the node
* @return the fully reachable
*/
public boolean getFullyReachable(int node) {
int isFullyReachable = eccentricities.getInt(borderNodeToPointerMap.get(node));
return isFullyReachable == 1;
}
/**
* Store border node to pointer map.
*/
public void storeBorderNodeToPointerMap() {
long listPointer = 0;
long nodePointer;
for (IntLongCursor borderNode : borderNodeToPointerMap) {
eccentricities.setInt(listPointer, borderNode.key);
listPointer = listPointer + 4;
nodePointer = borderNode.value;
eccentricities.setBytes(listPointer, longToByteArray(nodePointer), 8);
listPointer = listPointer + 8;
}
}
private void loadBorderNodeToPointerMap() {
byte[] buffer = new byte[8];
long listPointer = 0;
for (int i = 0; i < borderNodeCount; i++) {
int borderNode = eccentricities.getInt(listPointer);
listPointer = listPointer + 4;
eccentricities.getBytes(listPointer, buffer, 8);
long nodePointer = byteArrayToLong(buffer);
listPointer = listPointer + (long) 8;
borderNodeToPointerMap.put(borderNode, nodePointer);
}
}
public EccentricityStorage create(long byteCount) {
throw new IllegalStateException("Do not call EccentricityStorage.create directly");
}
public void flush() {
eccentricities.flush();
}
@Override
public void close() {
eccentricities.close();
}
@Override
public boolean isClosed() {
return eccentricities.isClosed();
}
public long getCapacity() {
return eccentricities.getCapacity();
}
/**
* Gets weighting.
*
* @return the weighting
*/
public Weighting getWeighting() {
return weighting;
}
public boolean hasWeighting(Weighting weighting) {
return getWeighting().getName() != null
&& getWeighting().getName().equals(weighting.getName())
&& getWeighting().getFlagEncoder().toString() != null
&& getWeighting().getFlagEncoder().toString().equals(weighting.getFlagEncoder().toString());
}
}