/* 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.algebra; import static org.junit.Assert.assertEquals; import java.awt.Rectangle; import java.awt.image.DataBuffer; import java.awt.image.Raster; import java.awt.image.RenderedImage; import javax.media.jai.ROI; import javax.media.jai.ROIShape; import javax.media.jai.RenderedOp; import org.junit.BeforeClass; import org.junit.Test; import com.sun.media.jai.util.ImageUtil; import it.geosolutions.jaiext.algebra.AlgebraDescriptor.Operator; import it.geosolutions.jaiext.range.Range; import it.geosolutions.jaiext.range.RangeFactory; import it.geosolutions.jaiext.testclasses.TestBase; public class AlgebraTest extends TestBase { private static final int NUM_IMAGES = 3; private static final int NUM_TYPES = 6; private static final int DEFAULT_WIDTH_REDUCED = DEFAULT_WIDTH / 2; private static final int DEFAULT_HEIGHT_REDUCED = DEFAULT_HEIGHT / 2; private static final double TOLERANCE = 0.1d; private static RenderedImage[][] testImages; private static Range noDataByte; private static Range noDataUShort; private static Range noDataShort; private static Range noDataInt; private static Range noDataFloat; private static Range noDataDouble; private static int destNoData; private static ROI roiObject; @BeforeClass public static void initialSetup() { byte noDataB = 50; short noDataS = 50; int noDataI = 50; float noDataF = 50; double noDataD = 50; testImages = new RenderedImage[NUM_TYPES][NUM_IMAGES]; IMAGE_FILLER = true; for (int j = 0; j < NUM_IMAGES; j++) { testImages[DataBuffer.TYPE_BYTE][j] = createTestImage(DataBuffer.TYPE_BYTE, DEFAULT_WIDTH_REDUCED, DEFAULT_HEIGHT_REDUCED, noDataB, false, j == 0 ? 1 : 3, 64 + j); testImages[DataBuffer.TYPE_USHORT][j] = createTestImage(DataBuffer.TYPE_USHORT, DEFAULT_WIDTH_REDUCED, DEFAULT_HEIGHT_REDUCED, noDataS, false, j == 0 ? 1 : 3, Short.MAX_VALUE / 4 + j); testImages[DataBuffer.TYPE_SHORT][j] = createTestImage(DataBuffer.TYPE_SHORT, DEFAULT_WIDTH_REDUCED, DEFAULT_HEIGHT_REDUCED, noDataS, false, j == 0 ? 1 : 3, -50 + j); testImages[DataBuffer.TYPE_INT][j] = createTestImage(DataBuffer.TYPE_INT, DEFAULT_WIDTH_REDUCED, DEFAULT_HEIGHT_REDUCED, noDataI, false, j == 0 ? 1 : 3, 100 + j ); testImages[DataBuffer.TYPE_FLOAT][j] = createTestImage(DataBuffer.TYPE_FLOAT, DEFAULT_WIDTH_REDUCED, DEFAULT_HEIGHT_REDUCED, noDataF, false, j == 0 ? 1 : 3, (255 / 2) * 5 + j); testImages[DataBuffer.TYPE_DOUBLE][j] = createTestImage(DataBuffer.TYPE_DOUBLE, DEFAULT_WIDTH_REDUCED, DEFAULT_HEIGHT_REDUCED, noDataD, false, j == 0 ? 1 : 3, (255 / 1) * 4 + j); } IMAGE_FILLER = false; // No Data Ranges boolean minIncluded = true; boolean maxIncluded = true; noDataByte = RangeFactory.create(noDataB, minIncluded, noDataB, maxIncluded); noDataUShort = RangeFactory.createU(noDataS, minIncluded, noDataS, maxIncluded); noDataShort = RangeFactory.create(noDataS, minIncluded, noDataS, maxIncluded); noDataInt = RangeFactory.create(noDataI, minIncluded, noDataI, maxIncluded); noDataFloat = RangeFactory.create(noDataF, minIncluded, noDataF, maxIncluded, true); noDataDouble = RangeFactory.create(noDataD, minIncluded, noDataD, maxIncluded, true); // Destination No Data destNoData = 100; // ROI creation Rectangle roiBounds = new Rectangle(5, 5, DEFAULT_WIDTH_REDUCED / 4, DEFAULT_HEIGHT_REDUCED / 4); roiObject = new ROIShape(roiBounds); } @Test public void testNoROINoNoData() { boolean roiUsed = false; boolean noDataUsed = false; for(int i = 0; i < 6; i++){ runTests(i, noDataUsed, roiUsed); } } @Test public void testOnlyNoData() { boolean roiUsed = false; boolean noDataUsed = true; for(int i = 0; i < 6; i++){ runTests(i, noDataUsed, roiUsed); } } @Test public void testOnlyROI() { boolean roiUsed = true; boolean noDataUsed = false; for(int i = 0; i < 6; i++){ runTests(i, noDataUsed, roiUsed); } } @Test public void testROIAndNoData() { boolean roiUsed = true; boolean noDataUsed = true; for(int i = 0; i < 6; i++){ runTests(i, noDataUsed, roiUsed); } } private void runTests(int dataType, boolean noDataUsed, boolean roiUsed) { testOperation(testImages[dataType], Operator.SUM, noDataUsed, roiUsed); testOperation(testImages[dataType], Operator.SUBTRACT, noDataUsed, roiUsed); testOperation(testImages[dataType], Operator.MULTIPLY, noDataUsed, roiUsed); testOperation(testImages[dataType], Operator.DIVIDE, noDataUsed, roiUsed); testOperation(testImages[dataType], Operator.LOG, noDataUsed, roiUsed); testOperation(testImages[dataType], Operator.EXP, noDataUsed, roiUsed); if(dataType != DataBuffer.TYPE_FLOAT && dataType != DataBuffer.TYPE_DOUBLE){ testOperation(testImages[dataType], Operator.ABSOLUTE, noDataUsed, roiUsed); testOperation(testImages[dataType], Operator.AND, noDataUsed, roiUsed); testOperation(testImages[dataType], Operator.OR, noDataUsed, roiUsed); testOperation(testImages[dataType], Operator.XOR, noDataUsed, roiUsed); testOperation(testImages[dataType], Operator.INVERT, noDataUsed, roiUsed); testOperation(testImages[dataType], Operator.NOT, noDataUsed, roiUsed); } } private void testOperation(RenderedImage[] sources, Operator op, boolean noDataUsed, boolean roiUsed) { // Optional No Data Range used Range noData; // Source image data type int dataType = sources[0].getSampleModel().getDataType(); // If no Data are present, the No Data Range associated is used if (noDataUsed) { switch (dataType) { case DataBuffer.TYPE_BYTE: noData = noDataByte; break; case DataBuffer.TYPE_USHORT: noData = noDataUShort; break; case DataBuffer.TYPE_SHORT: noData = noDataShort; break; case DataBuffer.TYPE_INT: noData = noDataInt; break; case DataBuffer.TYPE_FLOAT: noData = noDataFloat; break; case DataBuffer.TYPE_DOUBLE: noData = noDataDouble; break; default: throw new IllegalArgumentException("Wrong data type"); } } else { noData = null; } ROI roi; if (roiUsed) { roi = roiObject; } else { roi = null; } int minBandNumber = Integer.MAX_VALUE; for (int i = 0; i < NUM_IMAGES; i++) { int numBandImage = sources[i].getSampleModel().getNumBands(); if (numBandImage < minBandNumber) { minBandNumber = numBandImage; } } // operation RenderedOp calculated = AlgebraDescriptor .create(op, roi, noData, destNoData, null, sources); // Check if the bands number is the same assertEquals(minBandNumber, calculated.getNumBands()); switch (op) { case SUM: testSum(calculated, sources, roi, noData, minBandNumber); break; case SUBTRACT: testSubtract(calculated, sources, roi, noData, minBandNumber); break; case MULTIPLY: testMultiply(calculated, sources, roi, noData, minBandNumber); break; case DIVIDE: testDivide(calculated, sources, roi, noData, minBandNumber); break; case AND: case OR: case XOR: testLogicalOp(calculated, sources, roi, noData, minBandNumber, op); break; case EXP: case NOT: case INVERT: case ABSOLUTE: case LOG: testSingleImageOp(calculated, sources, roi, noData, minBandNumber, op); break; } // Disposal of the output image calculated.dispose(); } private void testLogicalOp(RenderedOp calculated, RenderedImage[] sources, ROI roi, Range noData, int minBandNumber, Operator op) { boolean roiUsed = roi != null; boolean noDataUsed = noData != null; // Upper-Left tile indexes int minTileX = calculated.getMinTileX(); int minTileY = calculated.getMinTileY(); // Raster object Raster upperLeftTile = calculated.getTile(minTileX, minTileY); // Tile bounds int minX = upperLeftTile.getMinX(); int minY = upperLeftTile.getMinY(); int maxX = upperLeftTile.getWidth() + minX; int maxY = upperLeftTile.getHeight() + minY; int numSrc = sources.length; // Source Raster Array Raster[] sourceRasters = new Raster[numSrc]; for (int i = 0; i < numSrc; i++) { sourceRasters[i] = sources[i].getTile(minTileX, minTileY); } // Old band value double valueOld = 0; double value = 0; double sample = 0; boolean isValidData = false; int dataType = calculated.getSampleModel().getDataType(); // Cycle on all the tile Bands for (int b = 0; b < minBandNumber; b++) { // Cycle on the y-axis for (int x = minX; x < maxX; x++) { // Cycle on the x-axis for (int y = minY; y < maxY; y++) { // Calculated value value = upperLeftTile.getSampleDouble(x, y, b); valueOld = 0; isValidData = false; boolean isValidROI = !roiUsed || roiUsed && roi.contains(x, y); if(isValidROI){ switch (dataType) { case DataBuffer.TYPE_BYTE: byte valueB = 0; for(int i = 0; i < numSrc; i++){ sample = sourceRasters[i].getSampleDouble(x, y, b); if(!noDataUsed || noDataUsed && !noDataDouble.contains(sample)){ isValidData = true; if(i == 0){ valueB = (byte) sample; } else { valueB = op.calculate(valueB, (byte) sample); } } } valueOld = valueB; //valueOld = (byte) (((((int) valueOld << 23) >> 31) | (int) valueOld) & 0xFF); value = (byte) (((((int) value << 23) >> 31) | (int) value) & 0xFF); break; case DataBuffer.TYPE_USHORT: short valueU = 0; for(int i = 0; i < numSrc; i++){ sample = sourceRasters[i].getSampleDouble(x, y, b); if(!noDataUsed || noDataUsed && !noDataDouble.contains(sample)){ isValidData = true; if(i == 0){ valueU = (short) sample; } else { valueU = op.calculate(true, valueU, (short) sample); } } } valueOld = valueU; //valueOld = ImageUtil.clampRoundUShort(valueOld)&0xFFFF; break; case DataBuffer.TYPE_SHORT: short valueS = 0; for(int i = 0; i < numSrc; i++){ sample = sourceRasters[i].getSampleDouble(x, y, b); if(!noDataUsed || noDataUsed && !noDataDouble.contains(sample)){ isValidData = true; if(i == 0){ valueS = (short) sample; } else { valueS = op.calculate(false, valueS, (short) sample); } } } valueOld = valueS; //valueOld = ImageUtil.clampRoundShort(valueOld); break; case DataBuffer.TYPE_INT: int valueI = 0; for(int i = 0; i < numSrc; i++){ sample = sourceRasters[i].getSampleDouble(x, y, b); if(!noDataUsed || noDataUsed && !noDataDouble.contains(sample)){ isValidData = true; if(i == 0){ valueI = (int) sample; } else { valueI = op.calculate(valueI, (int) sample); } } } valueOld = valueI; //valueOld = ImageUtil.clampRoundInt(valueOld); break; default: break; } if(!isValidData){ assertEquals(value, destNoData, TOLERANCE); }else { assertEquals(value, valueOld, TOLERANCE); } }else{ assertEquals(value, destNoData, TOLERANCE); } } } } } private void testSingleImageOp(RenderedOp calculated, RenderedImage[] sources, ROI roi, Range noData, int minBandNumber, Operator op) { boolean roiUsed = roi != null; boolean noDataUsed = noData != null; // Upper-Left tile indexes int minTileX = calculated.getMinTileX(); int minTileY = calculated.getMinTileY(); // Raster object Raster upperLeftTile = calculated.getTile(minTileX, minTileY); // Tile bounds int minX = upperLeftTile.getMinX(); int minY = upperLeftTile.getMinY(); int maxX = upperLeftTile.getWidth() + minX; int maxY = upperLeftTile.getHeight() + minY; // Source Raster Array Raster sourceRasters = sources[0].getTile(minTileX, minTileY); // Old band value double valueOld = 0; double value = 0; double sample = 0; boolean isValidData = false; int dataType = calculated.getSampleModel().getDataType(); // Cycle on all the tile Bands for (int b = 0; b < minBandNumber; b++) { // Cycle on the y-axis for (int x = minX; x < maxX; x++) { // Cycle on the x-axis for (int y = minY; y < maxY; y++) { // Calculated value value = upperLeftTile.getSampleDouble(x, y, b); valueOld = 0; sample = sourceRasters.getSampleDouble(x, y, b); isValidData = (!roiUsed || roiUsed && roi.contains(x, y)) && (!noDataUsed || noDataUsed && !noDataDouble.contains(sample)); if(isValidData){ switch (dataType) { case DataBuffer.TYPE_BYTE: valueOld = op.calculate((byte)sample); //valueOld = (byte) (((((int) valueOld << 23) >> 31) | (int) valueOld) & 0xFF); value = (byte) (((((int) value << 23) >> 31) | (int) value) & 0xFF); break; case DataBuffer.TYPE_USHORT: valueOld = op.calculate(true, (short)sample)&0xFFFF; //valueOld = ImageUtil.clampRoundUShort(valueOld)&0xFFFF; break; case DataBuffer.TYPE_SHORT: valueOld = op.calculate(false, (short)sample); valueOld = ImageUtil.clampRoundShort(valueOld); break; case DataBuffer.TYPE_INT: valueOld = op.calculate((int)sample); valueOld = ImageUtil.clampRoundInt(valueOld); break; case DataBuffer.TYPE_FLOAT: valueOld = op.calculate((float)sample); //valueOld = (float) sample; break; case DataBuffer.TYPE_DOUBLE: valueOld = op.calculate(sample); break; default: break; } assertEquals(value, valueOld, TOLERANCE); } else { assertEquals(value, destNoData, TOLERANCE); } } } } } private void testSum(RenderedOp calculated, RenderedImage[] sources, ROI roi, Range noData, int minBandNumber) { boolean roiUsed = roi != null; boolean noDataUsed = noData != null; // Upper-Left tile indexes int minTileX = calculated.getMinTileX(); int minTileY = calculated.getMinTileY(); // Raster object Raster upperLeftTile = calculated.getTile(minTileX, minTileY); // Tile bounds int minX = upperLeftTile.getMinX(); int minY = upperLeftTile.getMinY(); int maxX = upperLeftTile.getWidth() + minX; int maxY = upperLeftTile.getHeight() + minY; int numSrc = sources.length; // Source Raster Array Raster[] sourceRasters = new Raster[numSrc]; for (int i = 0; i < numSrc; i++) { sourceRasters[i] = sources[i].getTile(minTileX, minTileY); } // Old band value double valueOld = 0; double value = 0; double sample = 0; boolean isValidData = false; int dataType = calculated.getSampleModel().getDataType(); // Cycle on all the tile Bands for (int b = 0; b < minBandNumber; b++) { // Cycle on the y-axis for (int x = minX; x < maxX; x++) { // Cycle on the x-axis for (int y = minY; y < maxY; y++) { // Calculated value value = upperLeftTile.getSampleDouble(x, y, b); valueOld = 0; isValidData = false; // If no Data are present, no data check is performed if (noDataUsed && roiUsed) { if (roi.contains(x, y)) { for (int i = 0; i < numSrc; i++) { sample = sourceRasters[i].getSampleDouble(x, y, b); if (!noDataDouble.contains(sample)) { valueOld += sample; isValidData = true; } } if (isValidData) { switch (dataType) { case DataBuffer.TYPE_BYTE: valueOld = (byte) (((((int) valueOld << 23) >> 31) | (int) valueOld) & 0xFF); value = (byte) (((((int) value << 23) >> 31) | (int) value) & 0xFF); break; case DataBuffer.TYPE_USHORT: valueOld = ImageUtil.clampRoundUShort(valueOld)&0xFFFF; break; case DataBuffer.TYPE_SHORT: valueOld = ImageUtil.clampRoundShort(valueOld); break; case DataBuffer.TYPE_INT: valueOld = ImageUtil.clampRoundInt(valueOld); break; case DataBuffer.TYPE_FLOAT: valueOld = (float) valueOld; break; default: break; } assertEquals(value, valueOld, TOLERANCE); } else { assertEquals(value, destNoData, TOLERANCE); } } else { assertEquals(value, destNoData, TOLERANCE); } } else if (noDataUsed) { for (int i = 0; i < numSrc; i++) { sample = sourceRasters[i].getSampleDouble(x, y, b); if (!noDataDouble.contains(sample)) { valueOld += sample; isValidData = true; } } if (isValidData) { switch (dataType) { case DataBuffer.TYPE_BYTE: valueOld = (byte) (((((int) valueOld << 23) >> 31) | (int) valueOld) & 0xFF); value = (byte) (((((int) value << 23) >> 31) | (int) value) & 0xFF); break; case DataBuffer.TYPE_USHORT: valueOld = ImageUtil.clampRoundUShort(valueOld)&0xFFFF; break; case DataBuffer.TYPE_SHORT: valueOld = ImageUtil.clampRoundShort(valueOld); break; case DataBuffer.TYPE_INT: valueOld = ImageUtil.clampRoundInt(valueOld); break; case DataBuffer.TYPE_FLOAT: valueOld = (float) valueOld; break; default: break; } assertEquals(value, valueOld, TOLERANCE); } else { assertEquals(value, destNoData, TOLERANCE); } } else if (roiUsed) { if (roi.contains(x, y)) { for (int i = 0; i < numSrc; i++) { valueOld += sourceRasters[i].getSampleDouble(x, y, b); } switch (dataType) { case DataBuffer.TYPE_BYTE: valueOld = (byte) (((((int) valueOld << 23) >> 31) | (int) valueOld) & 0xFF); value = (byte) (((((int) value << 23) >> 31) | (int) value) & 0xFF); break; case DataBuffer.TYPE_USHORT: valueOld = ImageUtil.clampRoundUShort(valueOld)&0xFFFF; break; case DataBuffer.TYPE_SHORT: valueOld = ImageUtil.clampRoundShort(valueOld); break; case DataBuffer.TYPE_INT: valueOld = ImageUtil.clampRoundInt(valueOld); break; case DataBuffer.TYPE_FLOAT: valueOld = (float) valueOld; break; default: break; } assertEquals(value, valueOld, TOLERANCE); } else { assertEquals(value, destNoData, TOLERANCE); } } else { for (int i = 0; i < numSrc; i++) { valueOld += sourceRasters[i].getSampleDouble(x, y, b); } switch (dataType) { case DataBuffer.TYPE_BYTE: valueOld = (byte) (((((int) valueOld << 23) >> 31) | (int) valueOld) & 0xFF); value = (byte) (((((int) value << 23) >> 31) | (int) value) & 0xFF); break; case DataBuffer.TYPE_USHORT: valueOld = ImageUtil.clampRoundUShort(valueOld)&0xFFFF; break; case DataBuffer.TYPE_SHORT: valueOld = ImageUtil.clampRoundShort(valueOld); break; case DataBuffer.TYPE_INT: valueOld = ImageUtil.clampRoundInt(valueOld); break; case DataBuffer.TYPE_FLOAT: valueOld = (float) valueOld; break; default: break; } // Else a simple value comparison is done assertEquals(value, valueOld, TOLERANCE); } } } } } private void testSubtract(RenderedOp calculated, RenderedImage[] sources, ROI roi, Range noData, int minBandNumber) { boolean roiUsed = roi != null; boolean noDataUsed = noData != null; // Upper-Left tile indexes int minTileX = calculated.getMinTileX(); int minTileY = calculated.getMinTileY(); // Raster object Raster upperLeftTile = calculated.getTile(minTileX, minTileY); // Tile bounds int minX = upperLeftTile.getMinX(); int minY = upperLeftTile.getMinY(); int maxX = upperLeftTile.getWidth() + minX; int maxY = upperLeftTile.getHeight() + minY; int numSrc = sources.length; // Source Raster Array Raster[] sourceRasters = new Raster[numSrc]; for (int i = 0; i < numSrc; i++) { sourceRasters[i] = sources[i].getTile(minTileX, minTileY); } // Old band value double valueOld = 0; double value = 0; double sample = 0; boolean isValidData = false; int dataType = calculated.getSampleModel().getDataType(); // Cycle on all the tile Bands for (int b = 0; b < minBandNumber; b++) { // Cycle on the y-axis for (int x = minX; x < maxX; x++) { // Cycle on the x-axis for (int y = minY; y < maxY; y++) { // Calculated value value = upperLeftTile.getSampleDouble(x, y, b); valueOld = 0; isValidData = false; // If no Data are present, no data check is performed if (noDataUsed && roiUsed) { if (roi.contains(x, y)) { sample = sourceRasters[0].getSampleDouble(x, y, b); if (!noDataDouble.contains(sample)) { valueOld = sample; isValidData = true; } for (int i = 1; i < numSrc; i++) { sample = sourceRasters[i].getSampleDouble(x, y, b); if (!noDataDouble.contains(sample)) { valueOld -= sample; isValidData = true; } } if (isValidData) { switch (dataType) { case DataBuffer.TYPE_BYTE: valueOld = (byte) (((((int) valueOld << 23) >> 31) | (int) valueOld) & 0xFF); value = (byte) (((((int) value << 23) >> 31) | (int) value) & 0xFF); break; case DataBuffer.TYPE_USHORT: valueOld = ImageUtil.clampRoundUShort(valueOld)&0xFFFF; break; case DataBuffer.TYPE_SHORT: valueOld = ImageUtil.clampRoundShort(valueOld); break; case DataBuffer.TYPE_INT: valueOld = ImageUtil.clampRoundInt(valueOld); break; case DataBuffer.TYPE_FLOAT: valueOld = (float) valueOld; break; default: break; } assertEquals(value, valueOld, TOLERANCE); } else { assertEquals(value, destNoData, TOLERANCE); } } else { assertEquals(value, destNoData, TOLERANCE); } } else if (noDataUsed) { sample = sourceRasters[0].getSampleDouble(x, y, b); if (!noDataDouble.contains(sample)) { valueOld = sample; isValidData = true; } for (int i = 1; i < numSrc; i++) { sample = sourceRasters[i].getSampleDouble(x, y, b); if (!noDataDouble.contains(sample)) { valueOld -= sample; isValidData = true; } } if (isValidData) { switch (dataType) { case DataBuffer.TYPE_BYTE: valueOld = (byte) (((((int) valueOld << 23) >> 31) | (int) valueOld) & 0xFF); value = (byte) (((((int) value << 23) >> 31) | (int) value) & 0xFF); break; case DataBuffer.TYPE_USHORT: valueOld = ImageUtil.clampRoundUShort(valueOld)&0xFFFF; break; case DataBuffer.TYPE_SHORT: valueOld = ImageUtil.clampRoundShort(valueOld); break; case DataBuffer.TYPE_INT: valueOld = ImageUtil.clampRoundInt(valueOld); break; case DataBuffer.TYPE_FLOAT: valueOld = (float) valueOld; break; default: break; } assertEquals(value, valueOld, TOLERANCE); } else { assertEquals(value, destNoData, TOLERANCE); } } else if (roiUsed) { if (roi.contains(x, y)) { valueOld = sourceRasters[0].getSampleDouble(x, y, b); for (int i = 1; i < numSrc; i++) { valueOld -= sourceRasters[i].getSampleDouble(x, y, b); } switch (dataType) { case DataBuffer.TYPE_BYTE: valueOld = (byte) (((((int) valueOld << 23) >> 31) | (int) valueOld) & 0xFF); value = (byte) (((((int) value << 23) >> 31) | (int) value) & 0xFF); break; case DataBuffer.TYPE_USHORT: valueOld = ImageUtil.clampRoundUShort(valueOld)&0xFFFF; break; case DataBuffer.TYPE_SHORT: valueOld = ImageUtil.clampRoundShort(valueOld); break; case DataBuffer.TYPE_INT: valueOld = ImageUtil.clampRoundInt(valueOld); break; case DataBuffer.TYPE_FLOAT: valueOld = (float) valueOld; break; default: break; } assertEquals(value, valueOld, TOLERANCE); } else { assertEquals(value, destNoData, TOLERANCE); } } else { valueOld = sourceRasters[0].getSampleDouble(x, y, b); for (int i = 1; i < numSrc; i++) { valueOld -= sourceRasters[i].getSampleDouble(x, y, b); } switch (dataType) { case DataBuffer.TYPE_BYTE: valueOld = (byte) (((((int) valueOld << 23) >> 31) | (int) valueOld) & 0xFF); value = (byte) (((((int) value << 23) >> 31) | (int) value) & 0xFF); break; case DataBuffer.TYPE_USHORT: valueOld = ImageUtil.clampRoundUShort(valueOld)&0xFFFF; break; case DataBuffer.TYPE_SHORT: valueOld = ImageUtil.clampRoundShort(valueOld); break; case DataBuffer.TYPE_INT: valueOld = ImageUtil.clampRoundInt(valueOld); break; case DataBuffer.TYPE_FLOAT: valueOld = (float) valueOld; break; default: break; } // Else a simple value comparison is done assertEquals(value, valueOld, TOLERANCE); } } } } } private void testMultiply(RenderedOp calculated, RenderedImage[] sources, ROI roi, Range noData, int minBandNumber) { boolean roiUsed = roi != null; boolean noDataUsed = noData != null; // Upper-Left tile indexes int minTileX = calculated.getMinTileX(); int minTileY = calculated.getMinTileY(); // Raster object Raster upperLeftTile = calculated.getTile(minTileX, minTileY); // Tile bounds int minX = upperLeftTile.getMinX(); int minY = upperLeftTile.getMinY(); int maxX = upperLeftTile.getWidth() + minX; int maxY = upperLeftTile.getHeight() + minY; int numSrc = sources.length; // Source Raster Array Raster[] sourceRasters = new Raster[numSrc]; for (int i = 0; i < numSrc; i++) { sourceRasters[i] = sources[i].getTile(minTileX, minTileY); } // Old band value double valueOld = 0; double value = 0; double sample = 0; boolean isValidData = false; int dataType = calculated.getSampleModel().getDataType(); // Cycle on all the tile Bands for (int b = 0; b < minBandNumber; b++) { // Cycle on the y-axis for (int x = minX; x < maxX; x++) { // Cycle on the x-axis for (int y = minY; y < maxY; y++) { // Calculated value value = upperLeftTile.getSampleDouble(x, y, b); valueOld = 0; isValidData = false; // If no Data are present, no data check is performed if (noDataUsed && roiUsed) { if (roi.contains(x, y)) { sample = sourceRasters[0].getSampleDouble(x, y, b); if (!noDataDouble.contains(sample)) { valueOld = sample; isValidData = true; } else { valueOld = 1; } for (int i = 1; i < numSrc; i++) { sample = sourceRasters[i].getSampleDouble(x, y, b); if (!noDataDouble.contains(sample)) { valueOld *= sample; isValidData = true; } } if (isValidData) { switch (dataType) { case DataBuffer.TYPE_BYTE: valueOld = (byte) (((((int) valueOld << 23) >> 31) | (int) valueOld) & 0xFF); value = (byte) (((((int) value << 23) >> 31) | (int) value) & 0xFF); break; case DataBuffer.TYPE_USHORT: valueOld = ImageUtil.clampRoundUShort(valueOld)&0xFFFF; break; case DataBuffer.TYPE_SHORT: valueOld = ImageUtil.clampRoundShort(valueOld); break; case DataBuffer.TYPE_INT: valueOld = ImageUtil.clampRoundInt(valueOld); break; case DataBuffer.TYPE_FLOAT: valueOld = (float) valueOld; break; default: break; } assertEquals(value, valueOld, TOLERANCE); } else { assertEquals(value, destNoData, TOLERANCE); } } else { assertEquals(value, destNoData, TOLERANCE); } } else if (noDataUsed) { sample = sourceRasters[0].getSampleDouble(x, y, b); if (!noDataDouble.contains(sample)) { valueOld = sample; isValidData = true; } else { valueOld = 1; } for (int i = 1; i < numSrc; i++) { sample = sourceRasters[i].getSampleDouble(x, y, b); if (!noDataDouble.contains(sample)) { valueOld *= sample; isValidData = true; } } if (isValidData) { switch (dataType) { case DataBuffer.TYPE_BYTE: valueOld = (byte) (((((int) valueOld << 23) >> 31) | (int) valueOld) & 0xFF); value = (byte) (((((int) value << 23) >> 31) | (int) value) & 0xFF); break; case DataBuffer.TYPE_USHORT: valueOld = ImageUtil.clampRoundUShort(valueOld)&0xFFFF; break; case DataBuffer.TYPE_SHORT: valueOld = ImageUtil.clampRoundShort(valueOld); break; case DataBuffer.TYPE_INT: valueOld = ImageUtil.clampRoundInt(valueOld); break; case DataBuffer.TYPE_FLOAT: valueOld = (float) valueOld; break; default: break; } assertEquals(value, valueOld, TOLERANCE); } else { assertEquals(value, destNoData, TOLERANCE); } } else if (roiUsed) { if (roi.contains(x, y)) { valueOld = sourceRasters[0].getSampleDouble(x, y, b); for (int i = 1; i < numSrc; i++) { valueOld *= sourceRasters[i].getSampleDouble(x, y, b); } switch (dataType) { case DataBuffer.TYPE_BYTE: valueOld = (byte) (((((int) valueOld << 23) >> 31) | (int) valueOld) & 0xFF); value = (byte) (((((int) value << 23) >> 31) | (int) value) & 0xFF); break; case DataBuffer.TYPE_USHORT: valueOld = ImageUtil.clampRoundUShort(valueOld)&0xFFFF; break; case DataBuffer.TYPE_SHORT: valueOld = ImageUtil.clampRoundShort(valueOld); break; case DataBuffer.TYPE_INT: valueOld = ImageUtil.clampRoundInt(valueOld); break; case DataBuffer.TYPE_FLOAT: valueOld = (float) valueOld; break; default: break; } assertEquals(value, valueOld, TOLERANCE); } else { assertEquals(value, destNoData, TOLERANCE); } } else { valueOld = sourceRasters[0].getSampleDouble(x, y, b); for (int i = 1; i < numSrc; i++) { valueOld *= sourceRasters[i].getSampleDouble(x, y, b); } switch (dataType) { case DataBuffer.TYPE_BYTE: valueOld = (byte) (((((int) valueOld << 23) >> 31) | (int) valueOld) & 0xFF); value = (byte) (((((int) value << 23) >> 31) | (int) value) & 0xFF); break; case DataBuffer.TYPE_USHORT: valueOld = ImageUtil.clampRoundUShort(valueOld)&0xFFFF; break; case DataBuffer.TYPE_SHORT: valueOld = ImageUtil.clampRoundShort(valueOld); break; case DataBuffer.TYPE_INT: valueOld = ImageUtil.clampRoundInt(valueOld); break; case DataBuffer.TYPE_FLOAT: valueOld = (float) valueOld; break; default: break; } // Else a simple value comparison is done assertEquals(value, valueOld, TOLERANCE); } } } } } private void testDivide(RenderedOp calculated, RenderedImage[] sources, ROI roi, Range noData, int minBandNumber) { boolean roiUsed = roi != null; boolean noDataUsed = noData != null; // Upper-Left tile indexes int minTileX = calculated.getMinTileX(); int minTileY = calculated.getMinTileY(); // Raster object Raster upperLeftTile = calculated.getTile(minTileX, minTileY); // Tile bounds int minX = upperLeftTile.getMinX(); int minY = upperLeftTile.getMinY(); int maxX = upperLeftTile.getWidth() + minX; int maxY = upperLeftTile.getHeight() + minY; int numSrc = sources.length; // Source Raster Array Raster[] sourceRasters = new Raster[numSrc]; for (int i = 0; i < numSrc; i++) { sourceRasters[i] = sources[i].getTile(minTileX, minTileY); } // Old band value double valueOld = 0; double value = 0; double sample = 0; boolean isValidData = false; int dataType = calculated.getSampleModel().getDataType(); // Cycle on all the tile Bands for (int b = 0; b < minBandNumber; b++) { // Cycle on the y-axis for (int x = minX; x < maxX; x++) { // Cycle on the x-axis for (int y = minY; y < maxY; y++) { // Calculated value value = upperLeftTile.getSampleDouble(x, y, b); valueOld = 0; isValidData = false; // If no Data are present, no data check is performed if (noDataUsed && roiUsed) { if (roi.contains(x, y)) { sample = sourceRasters[0].getSampleDouble(x, y, b); if (!noDataDouble.contains(sample)) { valueOld = sample; isValidData = true; } else { valueOld = 1; } for (int i = 1; i < numSrc; i++) { sample = sourceRasters[i].getSampleDouble(x, y, b); if (!noDataDouble.contains(sample)) { valueOld /= sample == 0 ? 1 : sample; isValidData = true; } } if (isValidData) { switch (dataType) { case DataBuffer.TYPE_BYTE: valueOld = (byte) (((((int) valueOld << 23) >> 31) | (int) valueOld) & 0xFF); value = (byte) (((((int) value << 23) >> 31) | (int) value) & 0xFF); break; case DataBuffer.TYPE_USHORT: valueOld = ImageUtil.clampRoundUShort(valueOld)&0xFFFF; break; case DataBuffer.TYPE_SHORT: valueOld = ImageUtil.clampRoundShort(valueOld); break; case DataBuffer.TYPE_INT: valueOld = ImageUtil.clampRoundInt(valueOld); break; case DataBuffer.TYPE_FLOAT: valueOld = (float) valueOld; break; default: break; } assertEquals(value, valueOld, TOLERANCE); } else { assertEquals(value, destNoData, TOLERANCE); } } else { assertEquals(value, destNoData, TOLERANCE); } } else if (noDataUsed) { sample = sourceRasters[0].getSampleDouble(x, y, b); if (!noDataDouble.contains(sample)) { valueOld = sample; isValidData = true; } else { valueOld = 1; } for (int i = 1; i < numSrc; i++) { sample = sourceRasters[i].getSampleDouble(x, y, b); if (!noDataDouble.contains(sample)) { valueOld /= sample == 0 ? 1 : sample; isValidData = true; } } if (isValidData) { switch (dataType) { case DataBuffer.TYPE_BYTE: valueOld = (byte) (((((int) valueOld << 23) >> 31) | (int) valueOld) & 0xFF); value = (byte) (((((int) value << 23) >> 31) | (int) value) & 0xFF); break; case DataBuffer.TYPE_USHORT: valueOld = ImageUtil.clampRoundUShort(valueOld)&0xFFFF; break; case DataBuffer.TYPE_SHORT: valueOld = ImageUtil.clampRoundShort(valueOld); break; case DataBuffer.TYPE_INT: valueOld = ImageUtil.clampRoundInt(valueOld); break; case DataBuffer.TYPE_FLOAT: valueOld = (float) valueOld; break; default: break; } assertEquals(value, valueOld, TOLERANCE); } else { assertEquals(value, destNoData, TOLERANCE); } } else if (roiUsed) { if (roi.contains(x, y)) { valueOld = sourceRasters[0].getSampleDouble(x, y, b); for (int i = 1; i < numSrc; i++) { sample = sourceRasters[i].getSampleDouble(x, y, b); valueOld /= sample == 0 ? 1 : sample; } switch (dataType) { case DataBuffer.TYPE_BYTE: valueOld = (byte) (((((int) valueOld << 23) >> 31) | (int) valueOld) & 0xFF); value = (byte) (((((int) value << 23) >> 31) | (int) value) & 0xFF); break; case DataBuffer.TYPE_USHORT: valueOld = ImageUtil.clampRoundUShort(valueOld)&0xFFFF; break; case DataBuffer.TYPE_SHORT: valueOld = ImageUtil.clampRoundShort(valueOld); break; case DataBuffer.TYPE_INT: valueOld = ImageUtil.clampRoundInt(valueOld); break; case DataBuffer.TYPE_FLOAT: valueOld = (float) valueOld; break; default: break; } assertEquals(value, valueOld, TOLERANCE); } else { assertEquals(value, destNoData, TOLERANCE); } } else { valueOld = sourceRasters[0].getSampleDouble(x, y, b); for (int i = 1; i < numSrc; i++) { sample = sourceRasters[i].getSampleDouble(x, y, b); valueOld /= sample == 0 ? 1 : sample; } switch (dataType) { case DataBuffer.TYPE_BYTE: valueOld = (byte) (((((int) valueOld << 23) >> 31) | (int) valueOld) & 0xFF); value = (byte) (((((int) value << 23) >> 31) | (int) value) & 0xFF); break; case DataBuffer.TYPE_USHORT: valueOld = ImageUtil.clampRoundUShort(valueOld)&0xFFFF; break; case DataBuffer.TYPE_SHORT: valueOld = ImageUtil.clampRoundShort(valueOld); break; case DataBuffer.TYPE_INT: valueOld = ImageUtil.clampRoundInt(valueOld); break; case DataBuffer.TYPE_FLOAT: valueOld = (float) valueOld; break; default: break; } // Else a simple value comparison is done assertEquals(value, valueOld, TOLERANCE); } } } } } }