package de.fub.agg2graph.structs.frechet;
import de.fub.agg2graph.structs.frechet.FrechetDistance.Cell;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
/**
* This class is used to determined the monotone (and later conformal path) in
* the free space diagram. All possible path are computed with dynamic
* programming. From Algorithm 1 Alt'95
*
* @author Martinus
*
*/
public class CheckPath {
// 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 head;
List<Point> heads;
/**
* Constructor from the @FrechetDistance i = agg ; j = trace
*
* @param fd = used FrechetDistance
*/
public CheckPath(FrechetDistance fd) {
i = fd.getSizeP();
j = fd.getSizeQ();
cells = new Cell[i][j];
for (Cell c : fd.cells) {
cells[c.i][c.j] = c;
}
maxDistance = fd.getEpsilon();
start = new Point();
head = new Point();
heads = new ArrayList<Point>();
}
/**
* Algorithm 1 from Alt's paper
*/
public void algorithm1() {
// Start Point should be (0,0) else TODO
algorithm1(0, 0);
start.setLocation(0, 0);
System.out.println(head);
// 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());
}
}
}
/**
*
* @param i vertical
* @param j horizontal
*/
private void algorithm1(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()) {
updateHead(it, jt);
}
}
}
}
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()) {
// start = top.getBottomF().start;
// end = top.getBottomF().end;
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 head, if the point is further than head
*
* @param current
*/
private void updateHead(int i, int j) {
if ((i + j) > (head.x + head.y)) {
head.setLocation(i, j);
}
}
/**
* TODO: Check correctness Check connectivity from head to start
*/
public boolean checkConnectivity() {
Cell current = cells[head.x][head.y];
boolean startFound = false;
if (i == start.x
&& j == start.y
&& (!current.getBottomR().isEmpty() || !current.getLeftR()
.isEmpty())) {
startFound = true;
} else {
if (i > start.x && !current.getBottomR().isEmpty()) {
if (checkConnectivity(head.x - 1, head.y)) {
startFound = true;
}
}
if (j > start.y && !current.getLeftR().isEmpty()) {
if (checkConnectivity(head.x, head.y - 1)) {
startFound = true;
}
}
}
return startFound;
}
private boolean checkConnectivity(int i, int j) {
Cell current = cells[i][j];
boolean startFound = false;
if (i == start.x
&& j == start.y
&& (!current.getBottomR().isEmpty() || !current.getLeftR()
.isEmpty())) {
startFound = true;
} else {
if (i > start.x && !current.getBottomR().isEmpty()) {
if (checkConnectivity(i - 1, j)) {
startFound = true;
}
}
if (j > start.y && !current.getLeftR().isEmpty()) {
if (checkConnectivity(i, j - 1)) {
startFound = true;
}
}
}
return startFound;
}
}