Projector.java
package org.heigit.ors.fastisochrones.partitioning;
import com.carrotsearch.hppc.IntArrayList;
import com.carrotsearch.hppc.IntHashSet;
import com.graphhopper.storage.GraphHopperStorage;
import org.heigit.ors.fastisochrones.Contour;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;
import static org.heigit.ors.fastisochrones.partitioning.FastIsochroneParameters.getSplitValue;
import static org.heigit.ors.fastisochrones.partitioning.Projector.Projection.*;
public class Projector {
protected static Map<Projection, Projection> correspondingProjMap;
private GraphHopperStorage ghStorage;
private static final double TAN_67_5 = 2.414213;
private static final double TAN_45 = 1;
private static final double TAN_22_5 = 0.414213;
public Projector() {
prepareProjectionMaps();
}
private static void prepareProjectionMaps() {
correspondingProjMap = new EnumMap<>(Projection.class);
correspondingProjMap.put(LINE_P90, LINE_M00);
correspondingProjMap.put(LINE_P675, LINE_M225);
correspondingProjMap.put(LINE_P45, LINE_M45);
correspondingProjMap.put(LINE_P225, LINE_M675);
correspondingProjMap.put(LINE_M00, LINE_P90);
correspondingProjMap.put(LINE_M225, LINE_P675);
correspondingProjMap.put(LINE_M45, LINE_P45);
correspondingProjMap.put(LINE_M675, LINE_P225);
}
protected Map<Projection, IntArrayList> calculateProjections() {
//>> Loop through linear combinations and project each Node
EnumMap<Projection, IntArrayList> nodeListProjMap = new EnumMap<>(Projection.class);
Integer[] ids = IntStream.rangeClosed(0, ghStorage.getNodes() - 1).boxed().toArray(Integer[]::new);
Double[] values = new Double[ids.length];
Sort sort = new Sort();
for (Projection proj : Projection.values()) {
//>> sort projected Nodes
for (int i = 0; i < ids.length; i++) {
values[i] = proj.sortValue(ghStorage.getNodeAccess().getLat(ids[i]), ghStorage.getNodeAccess().getLon(ids[i]));
}
nodeListProjMap.put(proj, sort.sortByValueReturnList(ids, values));
}
//Check if there are at least two differing projections. If no lat lon data is set, all projections are the same.
boolean valid = false;
for (Projection proj : Projection.values()) {
if (!nodeListProjMap.get(proj).equals(nodeListProjMap.get(LINE_M00)))
valid = true;
}
if (!valid)
throw new IllegalStateException("All projections of the graph are the same. Maybe NodeAccess is faulty or not initialized?");
return nodeListProjMap;
}
protected BiPartitionProjection partitionProjections(Map<Projection, IntArrayList> originalProjections, BiPartition biPartition) {
IntHashSet part0 = biPartition.getPartition(0);
EnumMap<Projection, IntArrayList> projections0 = new EnumMap<>(Projection.class);
EnumMap<Projection, IntArrayList> projections1 = new EnumMap<>(Projection.class);
int origNodeCount = originalProjections.get(Projection.values()[0]).size();
//Add initial lists
for (Projection proj : Projection.values()) {
projections0.put(proj, new IntArrayList(origNodeCount / 3));
projections1.put(proj, new IntArrayList(origNodeCount / 3));
}
//Go through the original projections and separate each into two projections for the subsets, maintaining order
for (int i = 0; i < origNodeCount; i++) {
for (Map.Entry<Projection, IntArrayList> proj : originalProjections.entrySet()) {
int node = proj.getValue().get(i);
if (part0.contains(node))
projections0.get(proj.getKey()).add(node);
else
projections1.get(proj.getKey()).add(node);
}
}
return new BiPartitionProjection(projections0, projections1);
}
protected List<Projection> calculateProjectionOrder(Map<Projection, IntArrayList> projections) {
List<Projection> order;
EnumMap<Projection, Double> squareRangeProjMap = new EnumMap<>(Projection.class);
EnumMap<Projection, Double> orthogonalDiffProjMap = new EnumMap<>(Projection.class);
//>> calculate Projection-Distances
for (Map.Entry<Projection, IntArrayList> proj : projections.entrySet()) {
int idx = (int) (proj.getValue().size() * getSplitValue());
squareRangeProjMap.put(proj.getKey(), projIndividualValue(projections, proj.getKey(), idx));
}
//>> combine inverse Projection-Distances
for (Projection proj : projections.keySet()) {
orthogonalDiffProjMap.put(proj, projCombinedValue(squareRangeProjMap, proj));
}
//>> order Projections by Projection-Value
Sort sort = new Sort();
order = sort.sortByValueReturnList(orthogonalDiffProjMap, false);
return order;
}
private double projIndividualValue(Map<Projection, IntArrayList> projMap, Projection proj, int idx) {
IntArrayList tmpNodeList = projMap.get(proj);
double toLat = ghStorage.getNodeAccess().getLat(tmpNodeList.get(idx));
double toLon = ghStorage.getNodeAccess().getLon(tmpNodeList.get(idx));
double fromLat = ghStorage.getNodeAccess().getLat(tmpNodeList.get(tmpNodeList.size() - idx - 1));
double fromLon = ghStorage.getNodeAccess().getLon(tmpNodeList.get(tmpNodeList.size() - idx - 1));
return Contour.distance(fromLat, toLat, fromLon, toLon);
}
private double projCombinedValue(Map<Projection, Double> squareRangeProjMap, Projection proj) {
return squareRangeProjMap.get(proj) * squareRangeProjMap.get(proj) / squareRangeProjMap.get(correspondingProjMap.get(proj));
}
public void setGHStorage(GraphHopperStorage ghStorage) {
this.ghStorage = ghStorage;
}
public enum Projection {
LINE_P90 {
public double sortValue(double lat, double lon) {
return lat;
}
},
LINE_P675 {
public double sortValue(double lat, double lon) {
return lat + TAN_67_5 * lon;
}
},
LINE_P45 {
public double sortValue(double lat, double lon) {
return lat + TAN_45 * lon;
}
},
LINE_P225 {
public double sortValue(double lat, double lon) {
return lat + TAN_22_5 * lon;
}
},
LINE_M00 {
public double sortValue(double lat, double lon) {
return lon;
}
},
LINE_M225 {
public double sortValue(double lat, double lon) {
return lat - TAN_22_5 * lon;
}
},
LINE_M45 {
public double sortValue(double lat, double lon) {
return lat - TAN_45 * lon;
}
},
LINE_M675 {
public double sortValue(double lat, double lon) {
return lat - TAN_67_5 * lon;
}
};
abstract double sortValue(double lat, double lon);
}
}