package de.fub.agg2graph.structs.frechet;
import de.fub.agg2graph.structs.GPSEdge;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
/**
* TODO: More Continuity
*
* @author Martinus
*
*/
public class PartialFrechetDistance extends FrechetDistance {
// Free space cells
public Cell[][] cells;
// Parameter that secure the monotone requirements
int i; // The highest i
int j; // The highest j
double maxDistance;
// Head
Point start;
Point end;
List<Pair<Point, Point>> pathList;
public PartialFrechetDistance(double maxDistance) {
super(maxDistance);
init();
}
public PartialFrechetDistance(List<GPSEdge> a, List<GPSEdge> t,
double epsilon) {
super(a, t, epsilon);
init();
}
@Override
public void updateFreeSpace() {
for (int i = 0; i < P.size(); ++i) {
for (int j = 0; j < Q.size(); ++j) {
if (getCell(i, j).isRelevant) {
getCell(i, j).updateCell();
}
}
}
}
private void init() {
i = super.getSizeP();
j = super.getSizeQ();
cells = new Cell[i][j];
for (Cell c : super.cells) {
cells[c.i][c.j] = c;
}
updateFreeSpace();
maxDistance = super.getEpsilon();
start = new Point();
end = new Point();
pathList = new ArrayList<Pair<Point, Point>>();
}
@Override
public void calculateReachableSpace() {
int i = 0;
int j = 0;
boolean moreWhiteSpace = true;
Point nextStart = null;
start.setLocation(i, j);
while (moreWhiteSpace) {
calculateReachableSpace(start.x, start.y);
Pair<Point, Point> newPath = new Pair<Point, Point>(start, end);
pathList.add(newPath);
nextStart = checkAnotherWhiteSpaces(end.x, end.y);
if (nextStart != null) {
start = new Point(nextStart);
end = new Point();
} else {
moreWhiteSpace = false;
}
}
// TODO: for debug-test only
// for (int i = 0; i < this.i; i++) {
// for (int j = 0; j < this.j; j++) {
// System.out.println("i = " + i + " : j = " + j);
// System.out.println("leftR = "
// + !cells[i][j].getLeftR().isEmpty());
// System.out.println("bottomR = "
// + !cells[i][j].getBottomR().isEmpty());
// }
// }
}
/**
* This function does almost similar to the @calculateReachableSpace from
* the super class.
*
* @param i vertical
* @param j horizontal
*/
private void calculateReachableSpace(int i, int j) {
for (int it = i; it < this.i; it++) {
// Calculate LR_i,1
Cell current = cells[it][j];
current.setLeftR(current.getLeftF());
}
for (int jt = j; jt < this.j; jt++) {
// Calculate BR_1,j
Cell current = cells[i][jt];
current.setBottomR(current.getBottomF());
}
for (int it = i; it < this.i; it++) {
for (int jt = j; jt < this.j; jt++) {
// Construct the rest
construct(it, jt);
Cell current = cells[it][jt];
if (!current.getBottomR().isEmpty()
|| !current.getLeftR().isEmpty()) {
updateEnd(it, jt);
}
}
}
}
/**
* This function is used to search another monotone path. It determines the
* next start.
*
* @param x
* @param y
* @return
*/
private Point checkAnotherWhiteSpaces(int x, int y) {
List<Point> candidates = new ArrayList<Point>();
for (int it = x; it < this.i; it++) {
for (int jt = y; jt < this.j; jt++) {
Cell current = cells[it][jt];
if (!current.getBottomF().isEmpty()
|| !current.getLeftF().isEmpty()) {
if (it > x || jt > y) {
candidates.add(new Point(it, jt));
}
}
}
}
Point best = new Point(-1, -1);
for (Point candidate : candidates) {
if (best.x + best.y > candidate.x + candidate.y || best.x == -1
|| best.y == -1) {
best = candidate;
}
}
return ((best.x == -1 || best.y == -1) ? null : best);
}
/**
* Help function of Algorithm 1 alt'95
*
* @param i
* @param j
*/
private void construct(int i, int j) {
if (i < (this.i - 1)) {
calculateBottom(i, j);
}
if (j < (this.j - 1)) {
calculateLeft(i, j);
}
// only for check
// if (i == (this.i - 1) && j == (this.j - 1)) {
// Cell current = cells[i][j];
// if (!current.getBottomR().isEmpty()
// && !current.getLeftR().isEmpty()) {
// System.out.println("MATCHED");
// }
// }
}
/**
* Calculate BR
*
* @param i
* @param j
*/
private void calculateBottom(int i, int j) {
Cell current = cells[i][j];
Cell top = cells[i + 1][j];
// if current bottom is empty, then bottomR = bottomF
if (current.getBottomR().isEmpty() && !current.getLeftR().isEmpty()) {
Interval bottom = new Interval(top.getBottomF().start,
top.getBottomF().end);
top.setBottomR(bottom);
return;
} // if bottom is not empty, then calculate it!
else if (!current.getBottomR().isEmpty()) {
Interval bottom = calculate(current.getBottomR(), top.getBottomF());
top.setBottomR(bottom);
return;
}
// Set BR_i,j+1
top.setBottomR(new Interval(Double.MAX_VALUE, Double.MIN_VALUE));
}
/**
* Calculate LR
*
* @param i
* @param j
*/
private void calculateLeft(int i, int j) {
Cell current = cells[i][j];
Cell right = cells[i][j + 1];
// if current left is empty, then leftR = leftF
if (current.getLeftR().isEmpty() && !current.getBottomR().isEmpty()) {
// start = right.getLeftF().start;
// end = right.getLeftF().end;
Interval left = new Interval(right.getLeftF().start,
right.getLeftF().end);
right.setLeftR(left);
return;
} // if left is not empty, then calculate it!
else if (!current.getLeftR().isEmpty()) {
Interval left = calculate(current.getLeftR(), right.getLeftF());
right.setLeftR(left);
return;
}
// Set LR_i+1,j
right.setLeftR(new Interval(Double.MAX_VALUE, Double.MIN_VALUE));
}
/**
* R-Interval calculation
*
* @param before
* @param after
* @return
*/
private Interval calculate(Interval before, Interval after) {
double start = Double.MAX_VALUE;
double end = Double.MIN_VALUE;
// No available F
if (after.isEmpty()) {
return new Interval(start, end);
}
// Determine Start
if (before.start <= after.start) {
start = after.start;
} else if (before.start > after.start && before.start <= after.end) {
start = before.start;
} else {
return new Interval(start, end);
}
// Determine End
end = after.end;
return new Interval(start, end);
}
/**
* Update end, if the point is further than head
*
* @param current
*/
private void updateEnd(int i, int j) {
if ((i + j) > (end.x + end.y)) {
end.setLocation(i, j);
}
}
public List<Pair<Point, Point>> getPathList() {
calculateReachableSpace();
return pathList;
}
}