package ika.geo.grid;
import ika.geo.GeoGrid;
/**
* Minimum curvature, only the absolute values of the negative values.
* http://www.soi.city.ac.uk/~jwo/phd/04param.php
* @author jenny
*/
public class NegativeMinimumCurvatureOperator extends ThreadedGridOperator {
@Override
public String getName() {
return "Negative Minimum Curvature";
}
@Override
public boolean isOverwrittingSupported() {
return false;
}
private void operateBorder(GeoGrid src, GeoGrid dst, int col, int row, double cellSize) {
float[][] srcGrid = src.getGrid();
float[][] dstGrid = dst.getGrid();
final int cols = src.getCols();
final int rows = src.getRows();
final int rm = row - 1 < 0 ? 0 : row - 1;
final int rp = row + 1 >= rows ? rows - 1 : row + 1;
final int cm = col - 1 < 0 ? 0 : col - 1;
final int cp = col + 1 >= cols ? cols - 1 : col + 1;
final float z1 = srcGrid[rm][cm]; // top left
final float z2 = srcGrid[rm][col]; // top
final float z3 = srcGrid[rm][cp]; // top right
final float z4 = srcGrid[row][cm]; // left
final float z5 = srcGrid[row][col]; // center
final float z6 = srcGrid[row][cp]; // right
final float z7 = srcGrid[rp][cm]; // bottom left
final float z8 = srcGrid[rp][col]; // bottom
final float z9 = srcGrid[rp][cp]; // bottom right
final double gg = cellSize * cellSize;
final double a = gg * ((z1 + z3 + z4 + z6 + z7 + z9) / 6 - (z2 + z5 + z8) / 3);
final double b = gg * ((z1 + z2 + z3 + z7 + z8 + z9) / 6 - (z4 + z5 + z6) / 3);
final double a_b = a - b;
final double c = (z3 + z7 - z1 - z9) / 4 * gg;
double v = -a - b - Math.sqrt(a_b * a_b + c * c);
dstGrid[row][col] = v < 0 ? (float) -v : 0;
}
@Override
public void operate(GeoGrid src, GeoGrid dst, int startRow, int endRow) {
final int cols = src.getCols();
final int rows = src.getRows();
final double cellSize = src.getCellSize();
final double gg = cellSize * cellSize;
final int firstInteriorRow = Math.max(1, startRow);
final int lastInteriorRow = Math.min(rows - 1, endRow);
// top row
if (startRow == 0) {
for (int col = 0; col < cols; col++) {
operateBorder(src, dst, col, 0, cellSize);
}
}
// bottom row
if (endRow == rows - 1) { // FIXME -1 correct?
for (int col = 0; col < cols; col++) {
operateBorder(src, dst, col, rows - 1, cellSize);
}
}
// left column
for (int row = firstInteriorRow; row < lastInteriorRow; row++) {
operateBorder(src, dst, 0, row, cellSize);
}
// right column
for (int row = firstInteriorRow; row < lastInteriorRow; row++) {
operateBorder(src, dst, cols - 1, row, cellSize);
}
// interior of grid
float[][] srcGrid = src.getGrid();
float[][] dstGrid = dst.getGrid();
for (int row = firstInteriorRow; row < lastInteriorRow; row++) {
for (int col = 1; col < cols - 1; col++) {
final float z1 = srcGrid[row - 1][col - 1]; // top left
final float z2 = srcGrid[row - 1][col]; // top
final float z3 = srcGrid[row - 1][col + 1]; // top right
final float z4 = srcGrid[row][col - 1]; // left
final float z5 = srcGrid[row][col]; // center
final float z6 = srcGrid[row][col + 1]; // right
final float z7 = srcGrid[row + 1][col - 1]; // bottom left
final float z8 = srcGrid[row + 1][col]; // bottom
final float z9 = srcGrid[row + 1][col + 1]; // bottom right
final double a = gg * ((z1 + z3 + z4 + z6 + z7 + z9) / 6 - (z2 + z5 + z8) / 3);
final double b = gg * ((z1 + z2 + z3 + z7 + z8 + z9) / 6 - (z4 + z5 + z6) / 3);
final double a_b = a - b;
final double c = (z3 + z7 - z1 - z9) / 4 * gg;
final double v = -a - b - Math.sqrt(a_b * a_b + c * c);
dstGrid[row][col] = v < 0 ? (float) -v : 0f;
}
}
}
}