package de.fub.agg2graph.agg.strategy;
import de.fub.agg2graph.agg.AggNode;
import de.fub.agg2graph.agg.IMergeHandler;
import de.fub.agg2graph.agg.ITraceDistance;
import de.fub.agg2graph.structs.ClassObjectEditor;
import de.fub.agg2graph.structs.GPSCalc;
import de.fub.agg2graph.structs.GPSPoint;
import de.fub.agg2graph.structs.ILocation;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
@SuppressWarnings("unused")
public class HausdorffTraceDistance implements ITraceDistance {
private static final Logger logger = Logger
.getLogger("agg2graph.agg.default.dist");
private double aggReflectionFactor = 4;
private int maxOutliners = 10;
private double maxDistance = 5;
private int maxLookahead = 4;
private double maxPathDifference = 10;
private int minLengthFirstSegment = 1;
/**
* Compute the difference of a path to the aggregation. This measure only
* guarantees relative correctness when questioned repeatedly for different
* paths. A difference of 0 indicates equality while larger values indicate
* increasingly different paths.
*
* @param aggPath
* @param tracePoints
* @param startIndex
* @param dmh
* @return Object[] { double bestValue, int bestValueLength }
*/
@Override
public Object[] getPathDifference(List<AggNode> aggPath,
List<GPSPoint> tracePoints, int startIndex, IMergeHandler dmh) {
double bestValue = Double.MIN_VALUE;
double bestValueLength = 0;
List<AggNode> aggResult = new ArrayList<AggNode>();
List<GPSPoint> traceResult = new ArrayList<GPSPoint>();
List<AggNode> aggLocations = aggPath;
List<GPSPoint> traceLocations = tracePoints;
// step 1a: get nearest distance in agg from trace
int j = startIndex;
int currentK;
int bestK;
double globalBestDistance = -1;
while (j < traceLocations.size()) {
double distance = 0;
double bestDistance = Double.MAX_VALUE;
ILocation currentNode = traceLocations.get(j);
// Get the nearest distance to an edge/a point and mark it.
for (int k = 0; k < aggLocations.size() - 1; k++) {
distance = GPSCalc.getDistancePointToEdgeMeter(currentNode,
aggLocations.get(k), aggLocations.get(k + 1));
if (bestDistance > distance && distance < getMaxDistance()) {
bestDistance = distance;
}
}
if (bestDistance > globalBestDistance
&& bestDistance < Double.MAX_VALUE) {
globalBestDistance = bestDistance;
} else if (bestDistance == Double.MAX_VALUE) {
break;
}
j++;
}
// There is absolut no match
if (globalBestDistance == -1) {
return null;
}
// step 1b: get nearest distance in trace from agg
int l = 0;
while (l < aggLocations.size()) {
AggNode current = aggLocations.get(l);
double bestDistFrom = Double.MAX_VALUE;
int bestKFrom = -1;
// Distance check & get the nearest points
for (int k = 0; k < Math.min(traceLocations.size() - 1, j); k++) {
double distFrom = GPSCalc.getDistancePointToEdgeMeter(current,
traceLocations.get(k), traceLocations.get(k + 1));
if (bestDistFrom > distFrom) {
bestDistFrom = distFrom;
bestKFrom = k;
}
}
// If best distance is higher than max distance
if (bestDistFrom > getMaxDistance()) {
break;
}
// Update global distance if necessary
if (bestDistFrom > globalBestDistance
&& bestDistFrom < Double.MAX_VALUE) {
globalBestDistance = bestDistFrom;
}
// Add the projection to result
aggResult.add(current);
if (!traceResult.contains(traceLocations.get(bestKFrom))) {
traceResult.add(traceLocations.get(bestKFrom));
}
if (!traceResult.contains(traceLocations.get(bestKFrom + 1))
&& GPSCalc.getDistanceTwoPointsMeter(current,
traceLocations.get(bestKFrom + 1)) <= getMaxDistance()) {
traceResult.add(traceLocations.get(bestKFrom + 1));
}
l++;
}
bestValue = globalBestDistance;
// bestValueLength = traceLocations.subList(startIndex, Math.min(traceLocations.size() - 1, j)).size();
bestValueLength = traceResult.size();
if (aggResult.size() <= 1) {
return null;
} else {
return new Object[]{bestValue, bestValueLength, aggResult,
traceResult};
}
}
@Override
public List<ClassObjectEditor> getSettings() {
List<ClassObjectEditor> result = new ArrayList<ClassObjectEditor>();
result.add(new ClassObjectEditor(this));
return result;
}
/**
* @return the aggReflectionFactor
*/
public double getAggReflectionFactor() {
return aggReflectionFactor;
}
/**
* @param aggReflectionFactor the aggReflectionFactor to set
*/
public void setAggReflectionFactor(double aggReflectionFactor) {
this.aggReflectionFactor = aggReflectionFactor;
}
/**
* @return the maxOutliners
*/
public int getMaxOutliners() {
return maxOutliners;
}
/**
* @param maxOutliners the maxOutliners to set
*/
public void setMaxOutliners(int maxOutliners) {
this.maxOutliners = maxOutliners;
}
/**
* @return the maxDistance
*/
public double getMaxDistance() {
return maxDistance;
}
/**
* @param maxDistance the maxDistance to set
*/
public void setMaxDistance(double maxDistance) {
this.maxDistance = maxDistance;
}
/**
* @return the maxLookahead
*/
public int getMaxLookahead() {
return maxLookahead;
}
/**
* @param maxLookahead the maxLookahead to set
*/
public void setMaxLookahead(int maxLookahead) {
this.maxLookahead = maxLookahead;
}
/**
* @return the maxPathDifference
*/
public double getMaxPathDifference() {
return maxPathDifference;
}
/**
* @param maxPathDifference the maxPathDifference to set
*/
public void setMaxPathDifference(double maxPathDifference) {
this.maxPathDifference = maxPathDifference;
}
/**
* @return the minLengthFirstSegment
*/
public int getMinLengthFirstSegment() {
return minLengthFirstSegment;
}
/**
* @param minLengthFirstSegment the minLengthFirstSegment to set
*/
public void setMinLengthFirstSegment(int minLengthFirstSegment) {
this.minLengthFirstSegment = minLengthFirstSegment;
}
}