package ika.geo.grid;
import ika.geo.GeoGrid;
import ika.geo.GeoObject;
import java.awt.geom.Rectangle2D;
/**
* Combines two grid. An optional grid with weights for linear weighting per
* cell can be used. An optional mask with NaN values can be used..
* @author jenny
*/
public class GridCombineOperator extends ThreadedGridOperator {
private GeoGrid src2;
private GeoGrid weightGrid;
private GeoGrid mask;
public String getName() {
return "Combination";
}
public void operate(GeoGrid src, GeoGrid dst, int startRow, int endRow) {
if (weightGrid == null) {
if (mask == null) {
combine(startRow, endRow, src, dst);
} else {
combineMasked(startRow, endRow, src, dst);
}
} else {
if (mask == null) {
combineWeighted(startRow, endRow, src, dst);
} else {
combineWeightedMasked(startRow, endRow, src, dst);
}
}
}
private void combineWeightedMasked(int startRow, int endRow, GeoGrid src, GeoGrid dst) {
final int nCols = src.getCols();
float[][] wGrid = weightGrid.getGrid();
for (int row = startRow; row < endRow; ++row) {
float[] srcRow1 = src.getGrid()[row];
float[] srcRow2 = src2.getGrid()[row];
float[] wRow = wGrid[row];
float[] dstRow = dst.getGrid()[row];
float[] maskRow = mask.getGrid()[row];
for (int col = 0; col < nCols; ++col) {
if (Float.isNaN(maskRow[col])) {
dstRow[col] = Float.NaN;
} else {
final float w = wRow[col];
dstRow[col] = srcRow1[col] * w + srcRow2[col] * (1f - w);
}
}
}
}
private void combineWeighted(int startRow, int endRow, GeoGrid src, GeoGrid dst) {
final int nCols = src.getCols();
float[][] wGrid = weightGrid.getGrid();
for (int row = startRow; row < endRow; ++row) {
float[] srcRow1 = src.getGrid()[row];
float[] srcRow2 = src2.getGrid()[row];
float[] wRow = wGrid[row];
float[] dstRow = dst.getGrid()[row];
for (int col = 0; col < nCols; ++col) {
final float w = wRow[col];
dstRow[col] = srcRow1[col] * w + srcRow2[col] * (1f - w);
}
}
}
private void combineMasked(int startRow, int endRow, GeoGrid src, GeoGrid dst) {
final int nCols = src.getCols();
for (int row = startRow; row < endRow; ++row) {
float[] srcRow1 = src.getGrid()[row];
float[] srcRow2 = src2.getGrid()[row];
float[] dstRow = dst.getGrid()[row];
float[] maskRow = mask.getGrid()[row];
for (int col = 0; col < nCols; ++col) {
if (Float.isNaN(maskRow[col])) {
dstRow[col] = Float.NaN;
} else {
dstRow[col] = srcRow1[col] + srcRow2[col];
}
}
}
}
private void combine(int startRow, int endRow, GeoGrid src, GeoGrid dst) {
final int nCols = src.getCols();
for (int row = startRow; row < endRow; ++row) {
float[] srcRow1 = src.getGrid()[row];
float[] srcRow2 = src2.getGrid()[row];
float[] dstRow = dst.getGrid()[row];
for (int col = 0; col < nCols; ++col) {
dstRow[col] = srcRow1[col] + srcRow2[col];
}
}
}
/**
* Sums the values of two grids. The new grid has the size of grid1, grid2
* is resampled using bicubic interpolation.
* @param grid1
* @param grid2
* @return
*/
public GeoGrid operateWithResampling(GeoGrid grid1, GeoGrid grid2) {
if (grid1 == null || grid2 == null) {
throw new IllegalArgumentException();
}
final int nrows = grid1.getRows();
final int ncols = grid1.getCols();
GeoGrid newGrid = new GeoGrid(ncols, nrows, grid1.getCellSize());
newGrid.setWest(grid1.getWest());
newGrid.setNorth(grid1.getNorth());
float[][] src1Grid = grid1.getGrid();
float[][] dst = newGrid.getGrid();
Rectangle2D boundsGrid2 = grid2.getBounds2D(GeoObject.UNDEFINED_SCALE);
for (int row = 0; row < nrows; ++row) {
for (int col = 0; col < ncols; ++col) {
double x = grid1.getWest() + col * grid1.getCellSize();
double y = grid1.getNorth() - row * grid1.getCellSize();
float v1 = src1Grid[row][col];
float v2 = 0;
try {
v2 = boundsGrid2.contains(x, y) ? grid2.getBilinearInterpol(x, y) : 0;
} catch (Throwable e) {
}
dst[row][col] = v1 < 0 ? 0 : v1 + v2;
}
}
return newGrid;
}
/**
* @param grid2 the grid2 to set
*/
public void setSrc2(GeoGrid src2) {
this.src2 = src2;
}
/**
* @param weightGrid the weightGrid to set
*/
public void setWeightGrid(GeoGrid weightGrid) {
this.weightGrid = weightGrid;
}
/**
* @param mask the mask to set
*/
public void setMask(GeoGrid mask) {
this.mask = mask;
}
}