/* JAI-Ext - OpenSource Java Advanced Image Extensions Library
* http://www.geo-solutions.it/
* Copyright 2014 GeoSolutions
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package it.geosolutions.jaiext.buffer;
import it.geosolutions.jaiext.iterators.RandomIterFactory;
import it.geosolutions.jaiext.range.Range;
import java.awt.Rectangle;
import java.awt.image.DataBuffer;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.media.jai.AreaOpImage;
import javax.media.jai.BorderExtender;
import javax.media.jai.ImageLayout;
import javax.media.jai.ROI;
import javax.media.jai.ROIShape;
import javax.media.jai.RasterAccessor;
import javax.media.jai.RasterFormatTag;
import javax.media.jai.iterator.RandomIter;
import com.sun.media.jai.util.ImageUtil;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.index.strtree.STRtree;
public class BufferOpImage extends AreaOpImage {
public static final int TILE_EXTENDER = 1;
public static final int USHORT_MAX_VALUE = Short.MAX_VALUE - Short.MIN_VALUE;
public static final boolean TILE_CACHED = true;
public static final boolean ARRAY_CALC = true;
/**
* Spatial index for fast accessing the geometries that contain the selected pixel
*/
private final STRtree spatialIndex = new STRtree();
private boolean hasROI;
private List<ROI> rois;
private Range noData;
private final boolean hasNoData;
private boolean setBackground;
private boolean[] booleanLookupTable;
private byte destinationNoDataByte;
private short destinationNoDataShort;
private int destinationNoDataInt;
private float destinationNoDataFloat;
private double destinationNoDataDouble;
private byte valueToCountB;
private short valueToCountS;
private int valueToCountI;
private float valueToCountF;
private double valueToCountD;
private boolean counter;
private Rectangle union;
private int kWidth;
private int kHeight;
private boolean skipCalculations;
private final double pixelArea;
public BufferOpImage(RenderedImage source, ImageLayout layout, Map configuration,
BorderExtender extender, int leftPadding, int rightPadding, int topPadding,
int bottomPadding, List<ROI> rois, Range noData, double destinationNoDataDouble,
Double valueToCount, double pixelArea) {
super(source, layout, configuration, true, extender, leftPadding, rightPadding, topPadding,
bottomPadding);
// Padding Values
kWidth = leftPadding + rightPadding + 1;
kHeight = topPadding + bottomPadding + 1;
// Get the ROI
this.rois = rois;
// Get NoData
this.noData = noData;
hasROI = rois != null && !rois.isEmpty();
hasNoData = noData != null;
// Get PixelArea
this.pixelArea = pixelArea;
counter = valueToCount != null;
this.valueToCountD = counter ? valueToCount : 0;
SampleModel sm = getSampleModel();
// Source image data Type
int dstDataType = sm.getDataType();
// Check if the input NoData Range is equal to that of the final image data type except for Double and Float Images
if (hasNoData) {
int rangeType = noData.getDataType().getDataType();
if (dstDataType != rangeType
&& !(rangeType == DataBuffer.TYPE_FLOAT || rangeType == DataBuffer.TYPE_DOUBLE)) {
throw new IllegalArgumentException(
"Input Range must have the same data type of the final image");
}
}
// Boolean indicating that no calcolations must be done if the value to
// count is equal to nodata
skipCalculations = false;
switch (dstDataType) {
case DataBuffer.TYPE_BYTE:
destinationNoDataByte = (byte) (((byte) destinationNoDataDouble) & 0xff);
// Creation of a lookuptable containing the values to use for no
// data
if (hasNoData) {
booleanLookupTable = new boolean[256];
for (int i = 0; i < booleanLookupTable.length; i++) {
byte value = (byte) i;
booleanLookupTable[i] = !!noData.contains(value);
}
}
if (counter) {
valueToCountB = valueToCount.byteValue();
if (!noData.contains(valueToCountB)) {
skipCalculations = true;
}
}
break;
case DataBuffer.TYPE_USHORT:
destinationNoDataShort = (short) (((short) destinationNoDataDouble) & 0xffff);
if (counter) {
valueToCountS = valueToCount.shortValue();
if (!noData.contains(valueToCountS)) {
skipCalculations = true;
}
}
break;
case DataBuffer.TYPE_SHORT:
destinationNoDataShort = (short) destinationNoDataDouble;
if (counter) {
valueToCountS = valueToCount.shortValue();
if (!noData.contains(valueToCountS)) {
skipCalculations = true;
}
}
break;
case DataBuffer.TYPE_INT:
destinationNoDataInt = (int) destinationNoDataDouble;
if (counter) {
valueToCountI = valueToCount.intValue();
if (!noData.contains(valueToCountI)) {
skipCalculations = true;
}
}
break;
case DataBuffer.TYPE_FLOAT:
destinationNoDataFloat = (float) destinationNoDataDouble;
if (counter) {
valueToCountF = valueToCount.floatValue();
if (!noData.contains(valueToCountF)) {
skipCalculations = true;
}
}
break;
case DataBuffer.TYPE_DOUBLE:
this.destinationNoDataDouble = destinationNoDataDouble;
if (counter) {
if (!noData.contains(valueToCountD)) {
skipCalculations = true;
}
}
break;
default:
throw new IllegalArgumentException("Wrong data Type");
}
// Check if the rois are present. Otherwise the entire image buffer
// is calculated
if (rois == null || rois.isEmpty()) {
this.rois = new ArrayList<ROI>();
ROI roi = new ROIShape(getBounds());
this.rois.add(roi);
// Bounds Union
union = new Rectangle(getBounds());
double minX = union.getMinX();
double maxX = union.getMaxX();
double minY = union.getMinY();
double maxY = union.getMaxY();
Envelope env = new Envelope(minX, maxX, minY, maxY);
// Addition to the geometries list
spatialIndex.insert(env, roi);
} else {
// Bounds Union
union = new Rectangle(rois.get(0).getBounds());
// Insertion of the zones to the spatial index and union of the
// bounds for every ROI/Zone object
for (ROI roi : rois) {
// Spatial index creation
Rectangle rect = roi.getBounds();
double minX = rect.getMinX();
double maxX = rect.getMaxX();
double minY = rect.getMinY();
double maxY = rect.getMaxY();
Envelope env = new Envelope(minX, maxX, minY, maxY);
// Union
union = union.union(rect);
// Addition to the geometries list
spatialIndex.insert(env, roi);
}
// Sets of the roi list
this.rois = rois;
}
// Building of the spatial index
// Coordinate object creation for the spatial indexing
Coordinate p1 = new Coordinate(0, 0);
// Envelope associated to the coordinate object
Envelope searchEnv = new Envelope(p1);
// Query on the geometry list
spatialIndex.query(searchEnv);
}
/**
* Calculates the buffer on the defined raster
*
* @param sources an array of source Rasters, guaranteed to provide all necessary source data for computing the output.
* @param dest a WritableRaster tile containing the area to be computed.
* @param destRect the rectangle within dest to be processed.
*/
protected void computeRect(Raster[] sources, WritableRaster dest, Rectangle destRect) {
// Retrieve format tags.
RasterFormatTag[] formatTags = getFormatTags();
Raster source = sources[0];
Rectangle srcRect = mapDestRect(destRect, 0);
RasterAccessor srcAccessor = new RasterAccessor(source, srcRect, formatTags[0],
getSourceImage(0).getColorModel());
RasterAccessor dstAccessor = new RasterAccessor(dest, destRect, formatTags[1],
getColorModel());
// Check if the tile is inside the geometry bound-union
if (!hasROI || union.intersects(destRect) && !skipCalculations) {
switch (dstAccessor.getDataType()) {
case DataBuffer.TYPE_BYTE:
byteLoop(source, srcRect, srcAccessor, dstAccessor);
break;
case DataBuffer.TYPE_INT:
intLoop(source, srcRect, srcAccessor, dstAccessor);
break;
case DataBuffer.TYPE_SHORT:
shortLoop(source, srcRect, srcAccessor, dstAccessor);
break;
case DataBuffer.TYPE_USHORT:
ushortLoop(source, srcRect, srcAccessor, dstAccessor);
break;
case DataBuffer.TYPE_FLOAT:
floatLoop(source, srcRect, srcAccessor, dstAccessor);
break;
case DataBuffer.TYPE_DOUBLE:
doubleLoop(source, srcRect, srcAccessor, dstAccessor);
break;
default:
throw new IllegalArgumentException("Wrong data type");
}
// If the RasterAccessor object set up a temporary buffer for the
// op to write to, tell the RasterAccessor to write that data
// to the raster no that we're done with it.
if (dstAccessor.isDataCopy()) {
dstAccessor.clampDataArrays();
dstAccessor.copyDataToRaster();
}
} else {
// If the tile is outside the ROI, then the destination Raster is
// set to backgroundValues
if (setBackground) {
int numBands = getNumBands();
double[] background = new double[numBands];
for (int i = 0; i < numBands; i++) {
background[i] = destinationNoDataDouble;
}
ImageUtil.fillBackground(dest, destRect, background);
}
}
}
private void byteLoop(Raster ras, Rectangle srcRect, RasterAccessor src, RasterAccessor dst) {
RandomIter iter = RandomIterFactory.create(ras, srcRect, TILE_CACHED, ARRAY_CALC);
int dwidth = dst.getWidth();
int dheight = dst.getHeight();
int dnumBands = dst.getNumBands();
int dstX = dst.getX();
int dstY = dst.getY();
byte dstDataArrays[][] = dst.getByteDataArrays();
int dstBandOffsets[] = dst.getBandOffsets();
int dstPixelStride = dst.getPixelStride();
int dstScanlineStride = dst.getScanlineStride();
int dstScanlineOffset = 0;
// Both ROI and NoData
if (hasNoData) {
for (int j = 0; j < dheight; j++) {
int dstPixelOffset = dstScanlineOffset;
int y0 = dstY + j;
for (int i = 0; i < dwidth; i++) {
int x0 = dstX + i;
// check on containment
if (hasROI && !union.contains(x0, y0)) {
for (int k = 0; k < dnumBands; k++) {
byte dstData[] = dstDataArrays[k];
dstData[dstPixelOffset + dstBandOffsets[k]] = destinationNoDataByte;
}
dstPixelOffset += dstPixelStride;
continue;
}
// if every geometry really contains the selected point
boolean contains = true;
if (hasROI) {
contains = checkInROI(y0, x0);
}
if (!contains) {
for (int k = 0; k < dnumBands; k++) {
byte dstData[] = dstDataArrays[k];
dstData[dstPixelOffset + dstBandOffsets[k]] = destinationNoDataByte;
}
dstPixelOffset += dstPixelStride;
continue;
}
for (int k = 0; k < dnumBands; k++) {
byte dstData[] = dstDataArrays[k];
int value = 0;
boolean isValidData = false;
int xStart = x0 - leftPadding;
int yStart = y0 - topPadding;
if (counter) {
for (int u = 0; u < kHeight; u++) {
for (int v = 0; v < kWidth; v++) {
int data = iter.getSample(xStart + v, yStart + u, k) & 0xFF;
byte dataB = (byte) data;
if (booleanLookupTable[data]) {
if (dataB == valueToCountB) {
value++;
isValidData = booleanLookupTable[data];
}
}
}
}
} else {
for (int u = 0; u < kHeight; u++) {
for (int v = 0; v < kWidth; v++) {
int data = iter.getSample(xStart + v, yStart + u, k) & 0xFF;
if (booleanLookupTable[data]) {
value += data;
isValidData = booleanLookupTable[data];
}
}
}
}
value *= pixelArea;
if (value < 0) {
value = 0;
} else if (value > 255) {
value = 255;
} else if (!isValidData) {
value = destinationNoDataByte;
}
dstData[dstPixelOffset + dstBandOffsets[k]] = (byte) value;
}
dstPixelOffset += dstPixelStride;
}
dstScanlineOffset += dstScanlineStride;
}
// No NODATA
} else {
for (int j = 0; j < dheight; j++) {
int dstPixelOffset = dstScanlineOffset;
int y0 = dstY + j;
for (int i = 0; i < dwidth; i++) {
int x0 = dstX + i;
// check on containment
if (hasROI && !union.contains(x0, y0)) {
for (int k = 0; k < dnumBands; k++) {
byte dstData[] = dstDataArrays[k];
dstData[dstPixelOffset + dstBandOffsets[k]] = destinationNoDataByte;
}
dstPixelOffset += dstPixelStride;
continue;
}
// if every geometry really contains the selected point
boolean contains = true;
if (hasROI) {
contains = checkInROI(y0, x0);
}
if (!contains) {
for (int k = 0; k < dnumBands; k++) {
byte dstData[] = dstDataArrays[k];
dstData[dstPixelOffset + dstBandOffsets[k]] = destinationNoDataByte;
}
dstPixelOffset += dstPixelStride;
continue;
}
for (int k = 0; k < dnumBands; k++) {
byte dstData[] = dstDataArrays[k];
int value = 0;
int xStart = x0 - leftPadding;
int yStart = y0 - topPadding;
if (counter) {
for (int u = 0; u < kHeight; u++) {
for (int v = 0; v < kWidth; v++) {
byte data = (byte) (iter.getSample(xStart + v, yStart + u, k) & 0xFF);
if (data == valueToCountB) {
value++;
}
}
}
} else {
for (int u = 0; u < kHeight; u++) {
for (int v = 0; v < kWidth; v++) {
int data = iter.getSample(xStart + v, yStart + u, k) & 0xFF;
value += data;
}
}
}
value *= pixelArea;
if (value < 0) {
value = 0;
} else if (value > 255) {
value = 255;
}
dstData[dstPixelOffset + dstBandOffsets[k]] = (byte) value;
}
dstPixelOffset += dstPixelStride;
}
dstScanlineOffset += dstScanlineStride;
}
}
}
private void ushortLoop(Raster ras, Rectangle srcRect, RasterAccessor src, RasterAccessor dst) {
RandomIter iter = RandomIterFactory.create(ras, srcRect, TILE_CACHED, ARRAY_CALC);
int dwidth = dst.getWidth();
int dheight = dst.getHeight();
int dnumBands = dst.getNumBands();
int dstX = dst.getX();
int dstY = dst.getY();
short dstDataArrays[][] = dst.getShortDataArrays();
int dstBandOffsets[] = dst.getBandOffsets();
int dstPixelStride = dst.getPixelStride();
int dstScanlineStride = dst.getScanlineStride();
int dstScanlineOffset = 0;
// Both ROI and NoData
if (hasNoData) {
for (int j = 0; j < dheight; j++) {
int dstPixelOffset = dstScanlineOffset;
int y0 = dstY + j;
for (int i = 0; i < dwidth; i++) {
int x0 = dstX + i;
// check on containment
if (hasROI && !union.contains(x0, y0)) {
for (int k = 0; k < dnumBands; k++) {
short dstData[] = dstDataArrays[k];
dstData[dstPixelOffset + dstBandOffsets[k]] = destinationNoDataShort;
}
dstPixelOffset += dstPixelStride;
continue;
}
// if every geometry really contains the selected point
boolean contains = true;
if (hasROI) {
contains = checkInROI(y0, x0);
}
if (!contains) {
for (int k = 0; k < dnumBands; k++) {
short dstData[] = dstDataArrays[k];
dstData[dstPixelOffset + dstBandOffsets[k]] = destinationNoDataShort;
}
dstPixelOffset += dstPixelStride;
continue;
}
for (int k = 0; k < dnumBands; k++) {
short dstData[] = dstDataArrays[k];
int value = 0;
boolean isValidData = false;
int xStart = x0 - leftPadding;
int yStart = y0 - topPadding;
if (counter) {
for (int u = 0; u < kHeight; u++) {
for (int v = 0; v < kWidth; v++) {
int data = iter.getSample(xStart + v, yStart + u, k) & 0xFFFF;
short dataS = (short) data;
boolean valid = !noData.contains(dataS);
if (valid) {
if (dataS == valueToCountS) {
value++;
isValidData = valid;
}
}
}
}
} else {
for (int u = 0; u < kHeight; u++) {
for (int v = 0; v < kWidth; v++) {
int data = iter.getSample(xStart + v, yStart + u, k) & 0xFFFF;
short dataS = (short) data;
boolean valid = !noData.contains(dataS);
if (valid) {
value += data;
isValidData = valid;
}
}
}
}
value *= pixelArea;
if (value < 0) {
value = 0;
} else if (value > USHORT_MAX_VALUE) {
value = USHORT_MAX_VALUE;
} else if (!isValidData) {
value = destinationNoDataShort;
}
dstData[dstPixelOffset + dstBandOffsets[k]] = (short) value;
}
dstPixelOffset += dstPixelStride;
}
dstScanlineOffset += dstScanlineStride;
}
// No NODATA
} else {
for (int j = 0; j < dheight; j++) {
int dstPixelOffset = dstScanlineOffset;
int y0 = dstY + j;
for (int i = 0; i < dwidth; i++) {
int x0 = dstX + i;
// check on containment
if (hasROI && !union.contains(x0, y0)) {
for (int k = 0; k < dnumBands; k++) {
short dstData[] = dstDataArrays[k];
dstData[dstPixelOffset + dstBandOffsets[k]] = destinationNoDataShort;
}
dstPixelOffset += dstPixelStride;
continue;
}
// if every geometry really contains the selected point
boolean contains = true;
if (hasROI) {
contains = checkInROI(y0, x0);
}
if (!contains) {
for (int k = 0; k < dnumBands; k++) {
short dstData[] = dstDataArrays[k];
dstData[dstPixelOffset + dstBandOffsets[k]] = destinationNoDataShort;
}
dstPixelOffset += dstPixelStride;
continue;
}
for (int k = 0; k < dnumBands; k++) {
short dstData[] = dstDataArrays[k];
int value = 0;
int xStart = x0 - leftPadding;
int yStart = y0 - topPadding;
if (counter) {
for (int u = 0; u < kHeight; u++) {
for (int v = 0; v < kWidth; v++) {
short data = (short) (iter.getSample(xStart + v, yStart + u, k) & 0xFFFF);
if (data == valueToCountS) {
value++;
}
}
}
} else {
for (int u = 0; u < kHeight; u++) {
for (int v = 0; v < kWidth; v++) {
int data = iter.getSample(xStart + v, yStart + u, k) & 0xFFFF;
value += data;
}
}
}
value *= pixelArea;
if (value < 0) {
value = 0;
} else if (value > USHORT_MAX_VALUE) {
value = USHORT_MAX_VALUE;
}
dstData[dstPixelOffset + dstBandOffsets[k]] = (short) value;
}
dstPixelOffset += dstPixelStride;
}
dstScanlineOffset += dstScanlineStride;
}
}
}
private void shortLoop(Raster ras, Rectangle srcRect, RasterAccessor src, RasterAccessor dst) {
RandomIter iter = RandomIterFactory.create(ras, srcRect, TILE_CACHED, ARRAY_CALC);
int dwidth = dst.getWidth();
int dheight = dst.getHeight();
int dnumBands = dst.getNumBands();
int dstX = dst.getX();
int dstY = dst.getY();
short dstDataArrays[][] = dst.getShortDataArrays();
int dstBandOffsets[] = dst.getBandOffsets();
int dstPixelStride = dst.getPixelStride();
int dstScanlineStride = dst.getScanlineStride();
int dstScanlineOffset = 0;
// Both ROI and NoData
if (hasNoData) {
for (int j = 0; j < dheight; j++) {
int dstPixelOffset = dstScanlineOffset;
int y0 = dstY + j;
for (int i = 0; i < dwidth; i++) {
int x0 = dstX + i;
// check on containment
if (hasROI && !union.contains(x0, y0)) {
for (int k = 0; k < dnumBands; k++) {
short dstData[] = dstDataArrays[k];
dstData[dstPixelOffset + dstBandOffsets[k]] = destinationNoDataShort;
}
dstPixelOffset += dstPixelStride;
continue;
}
// if every geometry really contains the selected point
boolean contains = true;
if (hasROI) {
contains = checkInROI(y0, x0);
}
if (!contains) {
for (int k = 0; k < dnumBands; k++) {
short dstData[] = dstDataArrays[k];
dstData[dstPixelOffset + dstBandOffsets[k]] = destinationNoDataShort;
}
dstPixelOffset += dstPixelStride;
continue;
}
for (int k = 0; k < dnumBands; k++) {
short dstData[] = dstDataArrays[k];
int value = 0;
boolean isValidData = false;
int xStart = x0 - leftPadding;
int yStart = y0 - topPadding;
if (counter) {
for (int u = 0; u < kHeight; u++) {
for (int v = 0; v < kWidth; v++) {
short data = (short) iter.getSample(xStart + v, yStart + u, k);
boolean valid = !noData.contains(data);
if (valid) {
if (data == valueToCountS) {
value++;
isValidData = valid;
}
}
}
}
} else {
for (int u = 0; u < kHeight; u++) {
for (int v = 0; v < kWidth; v++) {
short data = (short) iter.getSample(xStart + v, yStart + u, k);
boolean valid = !noData.contains(data);
if (valid) {
value += data;
isValidData = valid;
}
}
}
}
value *= pixelArea;
if (value < Short.MIN_VALUE) {
value = Short.MIN_VALUE;
} else if (value > Short.MAX_VALUE) {
value = Short.MAX_VALUE;
} else if (!isValidData) {
value = destinationNoDataShort;
}
dstData[dstPixelOffset + dstBandOffsets[k]] = (short) value;
}
dstPixelOffset += dstPixelStride;
}
dstScanlineOffset += dstScanlineStride;
}
// No NODATA
} else {
for (int j = 0; j < dheight; j++) {
int dstPixelOffset = dstScanlineOffset;
int y0 = dstY + j;
for (int i = 0; i < dwidth; i++) {
int x0 = dstX + i;
// check on containment
if (hasROI && !union.contains(x0, y0)) {
for (int k = 0; k < dnumBands; k++) {
short dstData[] = dstDataArrays[k];
dstData[dstPixelOffset + dstBandOffsets[k]] = destinationNoDataShort;
}
dstPixelOffset += dstPixelStride;
continue;
}
// if every geometry really contains the selected point
boolean contains = true;
if (hasROI) {
contains = checkInROI(y0, x0);
}
if (!contains) {
for (int k = 0; k < dnumBands; k++) {
short dstData[] = dstDataArrays[k];
dstData[dstPixelOffset + dstBandOffsets[k]] = destinationNoDataShort;
}
dstPixelOffset += dstPixelStride;
continue;
}
for (int k = 0; k < dnumBands; k++) {
short dstData[] = dstDataArrays[k];
int value = 0;
int xStart = x0 - leftPadding;
int yStart = y0 - topPadding;
if (counter) {
for (int u = 0; u < kHeight; u++) {
for (int v = 0; v < kWidth; v++) {
short data = (short) (iter.getSample(xStart + v, yStart + u, k));
if (data == valueToCountS) {
value++;
}
}
}
} else {
for (int u = 0; u < kHeight; u++) {
for (int v = 0; v < kWidth; v++) {
int data = iter.getSample(xStart + v, yStart + u, k);
value += data;
}
}
}
value *= pixelArea;
if (value < Short.MIN_VALUE) {
value = Short.MIN_VALUE;
} else if (value > Short.MAX_VALUE) {
value = Short.MAX_VALUE;
}
dstData[dstPixelOffset + dstBandOffsets[k]] = (short) value;
}
dstPixelOffset += dstPixelStride;
}
dstScanlineOffset += dstScanlineStride;
}
}
}
private void intLoop(Raster ras, Rectangle srcRect, RasterAccessor src, RasterAccessor dst) {
RandomIter iter = RandomIterFactory.create(ras, srcRect, TILE_CACHED, ARRAY_CALC);
int dwidth = dst.getWidth();
int dheight = dst.getHeight();
int dnumBands = dst.getNumBands();
int dstX = dst.getX();
int dstY = dst.getY();
int dstDataArrays[][] = dst.getIntDataArrays();
int dstBandOffsets[] = dst.getBandOffsets();
int dstPixelStride = dst.getPixelStride();
int dstScanlineStride = dst.getScanlineStride();
int dstScanlineOffset = 0;
// Both ROI and NoData
if (hasNoData) {
for (int j = 0; j < dheight; j++) {
int dstPixelOffset = dstScanlineOffset;
int y0 = dstY + j;
for (int i = 0; i < dwidth; i++) {
int x0 = dstX + i;
// check on containment
if (hasROI && !union.contains(x0, y0)) {
for (int k = 0; k < dnumBands; k++) {
int dstData[] = dstDataArrays[k];
dstData[dstPixelOffset + dstBandOffsets[k]] = destinationNoDataInt;
}
dstPixelOffset += dstPixelStride;
continue;
}
// if every geometry really contains the selected point
boolean contains = true;
if (hasROI) {
contains = checkInROI(y0, x0);
}
if (!contains) {
for (int k = 0; k < dnumBands; k++) {
int dstData[] = dstDataArrays[k];
dstData[dstPixelOffset + dstBandOffsets[k]] = destinationNoDataInt;
}
dstPixelOffset += dstPixelStride;
continue;
}
for (int k = 0; k < dnumBands; k++) {
int dstData[] = dstDataArrays[k];
long value = 0;
boolean isValidData = false;
int xStart = x0 - leftPadding;
int yStart = y0 - topPadding;
if (counter) {
for (int u = 0; u < kHeight; u++) {
for (int v = 0; v < kWidth; v++) {
int data = iter.getSample(xStart + v, yStart + u, k);
boolean valid = !noData.contains(data);
if (valid) {
if (data == valueToCountI) {
value++;
isValidData = valid;
}
}
}
}
} else {
for (int u = 0; u < kHeight; u++) {
for (int v = 0; v < kWidth; v++) {
int data = iter.getSample(xStart + v, yStart + u, k);
boolean valid = !noData.contains(data);
if (valid) {
value += data;
isValidData = valid;
}
}
}
}
value *= pixelArea;
if (value < Integer.MIN_VALUE) {
value = Integer.MIN_VALUE;
} else if (value > Integer.MAX_VALUE) {
value = Integer.MAX_VALUE;
} else if (!isValidData) {
value = destinationNoDataInt;
}
dstData[dstPixelOffset + dstBandOffsets[k]] = (int) value;
}
dstPixelOffset += dstPixelStride;
}
dstScanlineOffset += dstScanlineStride;
}
// No NODATA
} else {
for (int j = 0; j < dheight; j++) {
int dstPixelOffset = dstScanlineOffset;
int y0 = dstY + j;
for (int i = 0; i < dwidth; i++) {
int x0 = dstX + i;
// check on containment
if (hasROI && !union.contains(x0, y0)) {
for (int k = 0; k < dnumBands; k++) {
int dstData[] = dstDataArrays[k];
dstData[dstPixelOffset + dstBandOffsets[k]] = destinationNoDataInt;
}
dstPixelOffset += dstPixelStride;
continue;
}
// if every geometry really contains the selected point
boolean contains = true;
if (hasROI) {
contains = checkInROI(y0, x0);
}
if (!contains) {
for (int k = 0; k < dnumBands; k++) {
int dstData[] = dstDataArrays[k];
dstData[dstPixelOffset + dstBandOffsets[k]] = destinationNoDataInt;
}
dstPixelOffset += dstPixelStride;
continue;
}
for (int k = 0; k < dnumBands; k++) {
int dstData[] = dstDataArrays[k];
long value = 0;
int xStart = x0 - leftPadding;
int yStart = y0 - topPadding;
if (counter) {
for (int u = 0; u < kHeight; u++) {
for (int v = 0; v < kWidth; v++) {
int data = iter.getSample(xStart + v, yStart + u, k);
if (data == valueToCountI) {
value++;
}
}
}
} else {
for (int u = 0; u < kHeight; u++) {
for (int v = 0; v < kWidth; v++) {
int data = iter.getSample(xStart + v, yStart + u, k);
value += data;
}
}
}
value *= pixelArea;
if (value < Integer.MIN_VALUE) {
value = Integer.MIN_VALUE;
} else if (value > Integer.MAX_VALUE) {
value = Integer.MAX_VALUE;
}
dstData[dstPixelOffset + dstBandOffsets[k]] = (int) value;
}
dstPixelOffset += dstPixelStride;
}
dstScanlineOffset += dstScanlineStride;
}
}
}
private void floatLoop(Raster ras, Rectangle srcRect, RasterAccessor src, RasterAccessor dst) {
RandomIter iter = RandomIterFactory.create(ras, srcRect, TILE_CACHED, ARRAY_CALC);
int dwidth = dst.getWidth();
int dheight = dst.getHeight();
int dnumBands = dst.getNumBands();
int dstX = dst.getX();
int dstY = dst.getY();
float dstDataArrays[][] = dst.getFloatDataArrays();
int dstBandOffsets[] = dst.getBandOffsets();
int dstPixelStride = dst.getPixelStride();
int dstScanlineStride = dst.getScanlineStride();
int dstScanlineOffset = 0;
// Both ROI and NoData
if (hasNoData) {
for (int j = 0; j < dheight; j++) {
int dstPixelOffset = dstScanlineOffset;
int y0 = dstY + j;
for (int i = 0; i < dwidth; i++) {
int x0 = dstX + i;
// check on containment
if (hasROI && !union.contains(x0, y0)) {
for (int k = 0; k < dnumBands; k++) {
float dstData[] = dstDataArrays[k];
dstData[dstPixelOffset + dstBandOffsets[k]] = destinationNoDataFloat;
}
dstPixelOffset += dstPixelStride;
continue;
}
// if every geometry really contains the selected point
boolean contains = true;
if (hasROI) {
contains = checkInROI(y0, x0);
}
if (!contains) {
for (int k = 0; k < dnumBands; k++) {
float dstData[] = dstDataArrays[k];
dstData[dstPixelOffset + dstBandOffsets[k]] = destinationNoDataFloat;
}
dstPixelOffset += dstPixelStride;
continue;
}
for (int k = 0; k < dnumBands; k++) {
float dstData[] = dstDataArrays[k];
double value = 0;
boolean isValidData = false;
int xStart = x0 - leftPadding;
int yStart = y0 - topPadding;
if (counter) {
for (int u = 0; u < kHeight; u++) {
for (int v = 0; v < kWidth; v++) {
float data = iter.getSampleFloat(xStart + v, yStart + u, k);
boolean valid = !noData.contains(data);
if (valid) {
if (data == valueToCountF) {
value++;
isValidData = valid;
}
}
}
}
} else {
for (int u = 0; u < kHeight; u++) {
for (int v = 0; v < kWidth; v++) {
float data = iter.getSampleFloat(xStart + v, yStart + u, k);
boolean valid = !noData.contains(data);
if (valid) {
value += data;
isValidData = valid;
}
}
}
}
value *= pixelArea;
if (value < -Float.MAX_VALUE) {
value = -Float.MAX_VALUE;
} else if (value > Float.MAX_VALUE) {
value = Float.MAX_VALUE;
} else if (!isValidData) {
value = destinationNoDataFloat;
}
dstData[dstPixelOffset + dstBandOffsets[k]] = (float) value;
}
dstPixelOffset += dstPixelStride;
}
dstScanlineOffset += dstScanlineStride;
}
// No NODATA
} else {
for (int j = 0; j < dheight; j++) {
int dstPixelOffset = dstScanlineOffset;
int y0 = dstY + j;
for (int i = 0; i < dwidth; i++) {
int x0 = dstX + i;
// check on containment
if (hasROI && !union.contains(x0, y0)) {
for (int k = 0; k < dnumBands; k++) {
float dstData[] = dstDataArrays[k];
dstData[dstPixelOffset + dstBandOffsets[k]] = destinationNoDataFloat;
}
dstPixelOffset += dstPixelStride;
continue;
}
// if every geometry really contains the selected point
boolean contains = true;
if (hasROI) {
contains = checkInROI(y0, x0);
}
if (!contains) {
for (int k = 0; k < dnumBands; k++) {
float dstData[] = dstDataArrays[k];
dstData[dstPixelOffset + dstBandOffsets[k]] = destinationNoDataFloat;
}
dstPixelOffset += dstPixelStride;
continue;
}
for (int k = 0; k < dnumBands; k++) {
float dstData[] = dstDataArrays[k];
double value = 0;
int xStart = x0 - leftPadding;
int yStart = y0 - topPadding;
if (counter) {
for (int u = 0; u < kHeight; u++) {
for (int v = 0; v < kWidth; v++) {
float data = iter.getSampleFloat(xStart + v, yStart + u, k);
if (data == valueToCountF) {
value++;
}
}
}
} else {
for (int u = 0; u < kHeight; u++) {
for (int v = 0; v < kWidth; v++) {
float data = iter.getSampleFloat(xStart + v, yStart + u, k);
value += data;
}
}
}
value *= pixelArea;
if (value < -Float.MAX_VALUE) {
value = -Float.MAX_VALUE;
} else if (value > Float.MAX_VALUE) {
value = Float.MAX_VALUE;
}
dstData[dstPixelOffset + dstBandOffsets[k]] = (float) value;
}
dstPixelOffset += dstPixelStride;
}
dstScanlineOffset += dstScanlineStride;
}
}
}
private void doubleLoop(Raster ras, Rectangle srcRect, RasterAccessor src, RasterAccessor dst) {
RandomIter iter = RandomIterFactory.create(ras, srcRect, TILE_CACHED, ARRAY_CALC);
int dwidth = dst.getWidth();
int dheight = dst.getHeight();
int dnumBands = dst.getNumBands();
int dstX = dst.getX();
int dstY = dst.getY();
double dstDataArrays[][] = dst.getDoubleDataArrays();
int dstBandOffsets[] = dst.getBandOffsets();
int dstPixelStride = dst.getPixelStride();
int dstScanlineStride = dst.getScanlineStride();
int dstScanlineOffset = 0;
// Both ROI and NoData
if (hasNoData) {
for (int j = 0; j < dheight; j++) {
int dstPixelOffset = dstScanlineOffset;
int y0 = dstY + j;
for (int i = 0; i < dwidth; i++) {
int x0 = dstX + i;
// check on containment
if (hasROI && !union.contains(x0, y0)) {
for (int k = 0; k < dnumBands; k++) {
double dstData[] = dstDataArrays[k];
dstData[dstPixelOffset + dstBandOffsets[k]] = destinationNoDataDouble;
}
dstPixelOffset += dstPixelStride;
continue;
}
// if every geometry really contains the selected point
boolean contains = true;
if (hasROI) {
contains = checkInROI(y0, x0);
}
if (!contains) {
for (int k = 0; k < dnumBands; k++) {
double dstData[] = dstDataArrays[k];
dstData[dstPixelOffset + dstBandOffsets[k]] = destinationNoDataDouble;
}
dstPixelOffset += dstPixelStride;
continue;
}
for (int k = 0; k < dnumBands; k++) {
double dstData[] = dstDataArrays[k];
double value = 0;
boolean isValidData = false;
int xStart = x0 - leftPadding;
int yStart = y0 - topPadding;
if (counter) {
for (int u = 0; u < kHeight; u++) {
for (int v = 0; v < kWidth; v++) {
double data = iter.getSampleDouble(xStart + v, yStart + u, k);
boolean valid = !noData.contains(data);
if (valid) {
if (data == valueToCountD) {
value++;
isValidData = valid;
}
}
}
}
} else {
for (int u = 0; u < kHeight; u++) {
for (int v = 0; v < kWidth; v++) {
double data = iter.getSampleDouble(xStart + v, yStart + u, k);
boolean valid = !noData.contains(data);
if (valid) {
value += data;
isValidData = valid;
}
}
}
}
value *= pixelArea;
if (!isValidData) {
value = destinationNoDataDouble;
}
dstData[dstPixelOffset + dstBandOffsets[k]] = value;
}
dstPixelOffset += dstPixelStride;
}
dstScanlineOffset += dstScanlineStride;
}
// No NODATA
} else {
for (int j = 0; j < dheight; j++) {
int dstPixelOffset = dstScanlineOffset;
int y0 = dstY + j;
for (int i = 0; i < dwidth; i++) {
int x0 = dstX + i;
// check on containment
if (hasROI && !union.contains(x0, y0)) {
for (int k = 0; k < dnumBands; k++) {
double dstData[] = dstDataArrays[k];
dstData[dstPixelOffset + dstBandOffsets[k]] = destinationNoDataDouble;
}
dstPixelOffset += dstPixelStride;
continue;
}
// if every geometry really contains the selected point
boolean contains = true;
if (hasROI) {
contains = checkInROI(y0, x0);
}
if (!contains) {
for (int k = 0; k < dnumBands; k++) {
double dstData[] = dstDataArrays[k];
dstData[dstPixelOffset + dstBandOffsets[k]] = destinationNoDataDouble;
}
dstPixelOffset += dstPixelStride;
continue;
}
for (int k = 0; k < dnumBands; k++) {
double dstData[] = dstDataArrays[k];
double value = 0;
int xStart = x0 - leftPadding;
int yStart = y0 - topPadding;
if (counter) {
for (int u = 0; u < kHeight; u++) {
for (int v = 0; v < kWidth; v++) {
double data = iter.getSampleDouble(xStart + v, yStart + u, k);
if (data == valueToCountD) {
value++;
}
}
}
} else {
for (int u = 0; u < kHeight; u++) {
for (int v = 0; v < kWidth; v++) {
double data = iter.getSampleDouble(xStart + v, yStart + u, k);
value += data;
}
}
}
value *= pixelArea;
dstData[dstPixelOffset + dstBandOffsets[k]] = value;
}
dstPixelOffset += dstPixelStride;
}
dstScanlineOffset += dstScanlineStride;
}
}
}
private boolean checkInROI(int y0, int x0) {
boolean contains;
// Coordinate object creation for the spatial indexing
Coordinate p1 = new Coordinate(x0, y0);
// Envelope associated to the coordinate object
Envelope searchEnv = new Envelope(p1);
// Query on the geometry list
List<ROI> roiList = spatialIndex.query(searchEnv);
contains = false;
// Cycle on all the geometries found
for (ROI roi : roiList) {
synchronized (this) { // HACK
contains = roi.contains(x0, y0);
}
if (contains) {
break;
}
}
return contains;
}
}