GreenIndexGraphStorageBuilder.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.routing.graphhopper.extensions.storages.builders;
import com.graphhopper.GraphHopper;
import com.graphhopper.reader.ReaderWay;
import com.graphhopper.storage.GraphExtension;
import com.graphhopper.util.EdgeIteratorState;
import com.graphhopper.util.Helper;
import org.apache.log4j.Logger;
import org.heigit.ors.routing.graphhopper.extensions.storages.GreenIndexGraphStorage;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Created by lliu on 13/03/2017.
*/
public class GreenIndexGraphStorageBuilder extends AbstractGraphStorageBuilder {
private static final Logger LOGGER = Logger.getLogger(GreenIndexGraphStorageBuilder.class.getName());
private GreenIndexGraphStorage storage;
private final Map<Long, Double> greenIndices = new HashMap<>();
private static final int TOTAL_LEVEL = 64;
private static final int DEFAULT_LEVEL = TOTAL_LEVEL - 1;
private final Map<Byte, SlotRange> slots = new HashMap<>(TOTAL_LEVEL);
@Override
public GraphExtension init(GraphHopper graphhopper) throws Exception {
if (storage != null)
throw new Exception("GraphStorageBuilder has been already initialized.");
// TODO Refactoring Check if the _greenIndexFile exists
String csvFile = parameters.get("filepath");
readGreenIndicesFromCSV(csvFile);
prepareGreenIndexSlots();
storage = new GreenIndexGraphStorage();
return storage;
}
private void prepareGreenIndexSlots() {
double max = Collections.max(greenIndices.values());
double min = Collections.min(greenIndices.values());
double step = (max - min) / TOTAL_LEVEL;
// Divide the range of raw green index values into TOTAL_LEVEL,
// then map the raw value to [0..TOTAL_LEVEL - 1]
for (byte i = 0; i < TOTAL_LEVEL; i++) {
slots.put(i, new SlotRange(min + i * step, min + (i + 1) * step));
}
}
private void readGreenIndicesFromCSV(String csvFile) throws IOException {
try (BufferedReader csvBuffer = new BufferedReader(new FileReader(csvFile))) {
String row;
// Jump the header line
row = csvBuffer.readLine();
char separator = row.contains(";") ? ';' : ',';
String[] rowValues = new String[2];
while ((row = csvBuffer.readLine()) != null) {
if (!parseCSVrow(row, separator, rowValues))
continue;
greenIndices.put(Long.parseLong(rowValues[0]), Double.parseDouble(rowValues[1]));
}
} catch (IOException openFileEx) {
LOGGER.error(openFileEx.getStackTrace());
throw openFileEx;
}
}
private boolean parseCSVrow(String row, char separator, String[] rowValues) {
if (Helper.isEmpty(row))
return false;
int pos = row.indexOf(separator);
if (pos > 0) {
rowValues[0] = row.substring(0, pos).trim();
rowValues[1] = row.substring(pos + 1).trim();
// read, check and push "osm_id" and "ungreen_factor" values
return !Helper.isEmpty(rowValues[0]) && !Helper.isEmpty(rowValues[1]);
}
return false;
}
@Override
public void processWay(ReaderWay way) {
// do nothing
}
@Override
public void processEdge(ReaderWay way, EdgeIteratorState edge) {
storage.setEdgeValue(edge.getEdge(), calcGreenIndex(way.getId()));
}
private static class SlotRange {
double left = 0.0;
double right = 0.0;
SlotRange(double l, double r) {
this.left = l;
this.right = r;
}
boolean within(double val) {
// check if the @val falls in [left, right] range
return (val >= left) && (val <= right);
}
}
private byte calcGreenIndex(long id) {
Double gi = greenIndices.get(id);
// No such @id key in the _greenIndices, or the value of it is null
// We set its green level to TOTAL_LEVEL/2 indicating the middle value for such cases
// TODO Refactoring this DEFAULT_LEVEL should be put in the ors-config.json file and
// injected back in the code
if (gi == null)
return (byte) (DEFAULT_LEVEL);
for (Map.Entry<Byte, SlotRange> s : slots.entrySet()) {
if (s.getValue().within(gi))
return s.getKey();
}
return (byte) (DEFAULT_LEVEL);
}
@Override
public String getName() {
return "GreenIndex";
}
}