package ika.geo.grid; import ika.geo.GeoGrid; /** * * @author Bernhard Jenny, Institute of Cartography, ETH Zurich. */ public class GridPercentileOperator implements GridOperator { private int filterSize; public GridPercentileOperator() { } public GridPercentileOperator(int filterSize) { this.filterSize = filterSize; } public String getName() { return "Percentile"; } public GeoGrid operate(GeoGrid geoGrid) { if (geoGrid == null) { throw new IllegalArgumentException(); } // make sure filterSize is odd number if (filterSize % 2 != 1) { return null; } final int halfFilterSize = this.filterSize / 2; final float scale = 1f / (this.filterSize * this.filterSize - 1); // create the new grid final int nrows = geoGrid.getRows(); final int ncols = geoGrid.getCols(); final double meshSize = geoGrid.getCellSize(); GeoGrid newGrid = new GeoGrid(ncols, nrows, meshSize); newGrid.setWest(geoGrid.getWest()); newGrid.setNorth(geoGrid.getNorth()); float[][] srcGrid = geoGrid.getGrid(); float[][] dstGrid = newGrid.getGrid(); // filter interior of grid for (int row = halfFilterSize; row < nrows - halfFilterSize; row++) { final float[] dstRow = dstGrid[row]; for (int col = halfFilterSize; col < ncols - halfFilterSize; col++) { int nbrSmaller = 0; final float centralCell = srcGrid[row][col]; for (int r = -halfFilterSize; r <= halfFilterSize; r++) { for (int c = -halfFilterSize; c <= halfFilterSize; c++) { final float v = srcGrid[row + r][col + c]; if (v < centralCell) { ++nbrSmaller; } } } dstRow[col] = nbrSmaller * scale; } } // filter border of grid this.operateBorder(geoGrid, newGrid); return newGrid; } private void operateBorder(GeoGrid src, GeoGrid dst) { final int halfFilterSize = this.filterSize / 2; final int cols = src.getCols(); final int rows = src.getRows(); // top rows for (int r = 0; r < halfFilterSize; r++) { for (int c = 0; c < cols; c++) { this.operateBorder(src, dst, c, r); } } // bottom rows for (int r = rows - halfFilterSize; r < rows; r++) { for (int c = 0; c < cols; c++) { this.operateBorder(src, dst, c, r); } } // left columns for (int r = 0; r < rows; r++) { for (int c = 0; c < halfFilterSize; c++) { this.operateBorder(src, dst, c, r); } } // right columns for (int r = 0; r < rows; r++) { for (int c = cols - halfFilterSize; c < cols; c++) { this.operateBorder(src, dst, c, r); } } } private void operateBorder(GeoGrid src, GeoGrid dst, int col, int row) { final int halfFilterSize = this.filterSize / 2; final float scale = 1f / (this.filterSize * this.filterSize - 1); final int cols = src.getCols(); final int rows = src.getRows(); float[][] srcGrid = src.getGrid(); int nbrSmaller = 0; final float centralCell = srcGrid[row][col]; for (int r = -halfFilterSize + row; r <= halfFilterSize + row; r++) { final int gridRow = r < 0 ? -r : (r >= rows ? 2 * rows - 2 - r : r); for (int c = -halfFilterSize + col; c <= halfFilterSize + col; c++) { final int gridCol = c < 0 ? -c : (c >= cols ? 2 * cols - 2 - c : c); final float v = srcGrid[gridRow][gridCol]; if (v < centralCell) { ++nbrSmaller; } } } dst.setValue(nbrSmaller * scale, col, row); } public int getFilterSize() { return filterSize; } public void setFilterSize(int filterSize) { this.filterSize = filterSize; } }