/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2006-2016, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.coverage.processing;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.*;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.awt.image.WritableRaster;
import java.util.HashMap;
import java.util.Map;
import javax.media.jai.PlanarImage;
import javax.media.jai.ROI;
import javax.media.jai.RenderedOp;
import javax.media.jai.operator.ConstantDescriptor;
import org.geotools.coverage.CoverageFactoryFinder;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridCoverageFactory;
import org.geotools.coverage.grid.GridEnvelope2D;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.coverage.grid.Viewer;
import org.geotools.factory.GeoTools;
import org.geotools.geometry.DirectPosition2D;
import org.geotools.geometry.Envelope2D;
import org.geotools.geometry.GeneralEnvelope;
import org.geotools.geometry.jts.JTS;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.image.jai.Registry;
import org.geotools.referencing.crs.DefaultDerivedCRS;
import org.geotools.referencing.crs.DefaultGeocentricCRS;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.referencing.operation.transform.AffineTransform2D;
import org.geotools.referencing.operation.transform.ProjectiveTransform;
import org.geotools.resources.coverage.CoverageUtilities;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Test;
import org.opengis.geometry.Envelope;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import com.vividsolutions.jts.geom.CoordinateSequence;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.impl.CoordinateArraySequence;
import it.geosolutions.jaiext.range.NoDataContainer;
/**
* Tests the crop operation.
*
*
*
* @source $URL$
* @version $Id$
* @author Simone Giannecchini (GeoSolutions)
* @author Martin Desruisseaux (Geomatys)
* @author Emanuele Tajariol (GeoSolutions)
*
* @since 2.3
*/
public final class CropTest extends GridProcessingTestBase {
/**
* The grid coverage to test.
*/
private GridCoverage2D coverage;
/**
* Set up common objects used for all tests.
*/
@Before
public void setUp() {
coverage = EXAMPLES.get(0);
}
/**
* Tests the "Crop" operation.
*
* @throws TransformException if a transformation was required and failed.
*/
@Test
public void testCrop() throws TransformException {
final GridCoverage2D source = coverage;
testCrop(source);
}
private GridCoverage2D testCrop(final GridCoverage2D source) {
final CoverageProcessor processor = CoverageProcessor.getInstance();
/*
* Get the source coverage and build the cropped envelope.
*/
final Envelope oldEnvelope = source.getEnvelope();
final GeneralEnvelope cropEnvelope = new GeneralEnvelope(new double[] {
oldEnvelope.getMinimum(0) + oldEnvelope.getSpan(0) * 3 / 8,
oldEnvelope.getMinimum(1) + oldEnvelope.getSpan(1) * 3 / 8
}, new double[] {
oldEnvelope.getMinimum(0) + oldEnvelope.getSpan(0) * 5 / 8,
oldEnvelope.getMinimum(1) + oldEnvelope.getSpan(1) * 5 / 8
});
cropEnvelope.setCoordinateReferenceSystem(oldEnvelope.getCoordinateReferenceSystem());
/*
* Do the crop without conserving the envelope.
*/
ParameterValueGroup param = processor.getOperation("CoverageCrop").getParameters();
param.parameter("Source").setValue(source);
param.parameter("Envelope").setValue(cropEnvelope);
GridCoverage2D cropped = (GridCoverage2D) processor.doOperation(param);
if (SHOW) {
Viewer.show(coverage);
Viewer.show(cropped);
} else {
// Force computation
assertNotNull(PlanarImage.wrapRenderedImage(cropped.getRenderedImage()).getTiles());
}
RenderedImage raster = cropped.getRenderedImage();
assertEquals(168, raster.getMinX());
assertEquals(172, raster.getMinY());
assertEquals(114, raster.getWidth());
assertEquals(116, raster.getHeight());
assertEquals(source.getGridGeometry().getGridToCRS2D(),
cropped.getGridGeometry().getGridToCRS2D());
assertFalse(cropEnvelope.equals(cropped.getEnvelope()));
// check we did not use mosaic for this simple case
RenderedOp op = (RenderedOp) raster;
assertEquals("Crop", op.getOperationName());
// check there is no ROI set (none in input, none in output)
assertEquals(java.awt.Image.UndefinedProperty, raster.getProperty("ROI"));
return cropped;
}
@Test
public void testCropNoData() {
Map<String, Object> properties = new HashMap<>();
final Double theNoData = new Double(-123);
CoverageUtilities.setNoDataProperty(properties, theNoData);
GridCoverage2D source = new GridCoverageFactory().create(coverage.getName().toString(), coverage.getRenderedImage(), coverage.getEnvelope(), coverage.getSampleDimensions(), null, properties);
// check the grid coverage
GridCoverage2D cropped = testCrop(source);
NoDataContainer noData = CoverageUtilities.getNoDataProperty(cropped);
assertEquals(theNoData, noData.getAsSingleValue(), 0d);
// but also check the image
RenderedImage renderedImage = cropped.getRenderedImage();
Object property = renderedImage.getProperty(NoDataContainer.GC_NODATA);
assertNotEquals(property, Image.UndefinedProperty);
assertThat(property, instanceOf(NoDataContainer.class));
NoDataContainer nd = (NoDataContainer) property;
assertEquals(-123, nd.getAsSingleValue(), 0d);
}
/**
* Tests the "Crop" operation by providing different implementations of the
* opengis's Envelope interface instead of GeneralEnvelope in order to fix
* GEOT-3434.
*
* @throws TransformException if a transformation was required and failed.
*/
@Test
public void testCropEnvelopeSupport() throws TransformException {
final CoverageProcessor processor = CoverageProcessor.getInstance();
/*
* Get the source coverage and build the cropped envelope.
*/
final GridCoverage2D source = coverage;
final Envelope oldEnvelope = source.getEnvelope();
final GeneralEnvelope cropEnvelope = new GeneralEnvelope(new double[] {
oldEnvelope.getMinimum(0) + oldEnvelope.getSpan(0) * 3 / 8,
oldEnvelope.getMinimum(1) + oldEnvelope.getSpan(1) * 3 / 8
}, new double[] {
oldEnvelope.getMinimum(0) + oldEnvelope.getSpan(0) * 5 / 8,
oldEnvelope.getMinimum(1) + oldEnvelope.getSpan(1) * 5 / 8
});
cropEnvelope.setCoordinateReferenceSystem(oldEnvelope.getCoordinateReferenceSystem());
Envelope2D env2D = new Envelope2D(cropEnvelope);
/*
* Do the crop without conserving the envelope.
*/
ParameterValueGroup param = processor.getOperation("CoverageCrop").getParameters();
param.parameter("Source").setValue(source);
param.parameter("Envelope").setValue(env2D);
GridCoverage2D cropped = (GridCoverage2D) processor.doOperation(param);
if (SHOW) {
Viewer.show(coverage);
Viewer.show(cropped);
} else {
// Force computation
assertNotNull(PlanarImage.wrapRenderedImage(cropped.getRenderedImage()).getTiles());
}
RenderedImage raster = cropped.getRenderedImage();
assertEquals(168, raster.getMinX());
assertEquals(172, raster.getMinY());
assertEquals(114, raster.getWidth());
assertEquals(116, raster.getHeight());
assertEquals(source.getGridGeometry().getGridToCRS2D(),
cropped.getGridGeometry().getGridToCRS2D());
assertFalse(cropEnvelope.equals(cropped.getEnvelope()));
ReferencedEnvelope refEnv = new ReferencedEnvelope(cropEnvelope);
param.parameter("Envelope").setValue(refEnv);
cropped = (GridCoverage2D) processor.doOperation(param);
if (SHOW) {
Viewer.show(coverage);
Viewer.show(cropped);
} else {
// Force computation
assertNotNull(PlanarImage.wrapRenderedImage(cropped.getRenderedImage()).getTiles());
}
raster = cropped.getRenderedImage();
assertEquals(168, raster.getMinX());
assertEquals(172, raster.getMinY());
assertEquals(114, raster.getWidth());
assertEquals(116, raster.getHeight());
assertEquals(source.getGridGeometry().getGridToCRS2D(),
cropped.getGridGeometry().getGridToCRS2D());
assertFalse(cropEnvelope.equals(cropped.getEnvelope()));
}
/**
* Tests the specific catchable exception thrown when the area has no overlap
*/
@Test
public void testCropOutsideCoverageRealWorld() throws TransformException {
final CoverageProcessor processor = CoverageProcessor.getInstance();
ReferencedEnvelope re = ReferencedEnvelope.reference(coverage.getEnvelope2D());
// push it fully outside of the coverage area
re.translate(re.getWidth() + 10, 0);
/*
* Do the crop
*/
ParameterValueGroup param = processor.getOperation("CoverageCrop").getParameters();
param.parameter("Source").setValue(coverage);
param.parameter("Envelope").setValue(re);
try {
processor.doOperation(param);
fail("Should have thrown an exception here, there is no overlap");
} catch(EmptyIntersectionException e) {
assertEquals("Crop envelope does not intersect in model space", e.getMessage());
}
}
/**
* Tests the specific catchable exception thrown when the area has no overlap
*/
@Test
public void testCropOutsideCoverageRasterSpace() throws TransformException {
// Reproducing a real world setup that exhibits a numerical issue. Unsure if the
// same issue can be reproduced on all platforms, we might have to guard this one
// for OS/architecture
final int width = 450;
final int height = 225;
final BufferedImage image= new BufferedImage(width, height, BufferedImage.TYPE_USHORT_GRAY);
final WritableRaster raster =(WritableRaster) image.getData();
for (int y=0; y< height; y++) {
for (int x=0; x< width; x++) {
raster.setSample(x, y, 0,(int)( 1+(x+y)*65534.0/1000.0));
}
}
image.setData(raster);
final GridCoverageFactory factory = CoverageFactoryFinder.getGridCoverageFactory(null);
GridGeometry2D gg = new GridGeometry2D(new GridEnvelope2D(0, 0, 450, 225), new AffineTransform2D(0.8, 0, 0, -0.8, -179.6, 89.6), DefaultGeographicCRS.WGS84);
GridCoverage2D coverage = factory.create("UInt16 coverage", image, gg, null, null, null);
final CoverageProcessor processor = CoverageProcessor.getInstance();
ReferencedEnvelope re = new ReferencedEnvelope(-180, 0, -270, -90, DefaultGeographicCRS.WGS84);
/*
* Do the crop
*/
ParameterValueGroup param = processor.getOperation("CoverageCrop").getParameters();
param.parameter("Source").setValue(coverage);
param.parameter("Envelope").setValue(re);
try {
processor.doOperation(param);
fail("Should have thrown an exception here, there is no overlap");
} catch(EmptyIntersectionException e) {
assertEquals("Crop envelope intersects in model space, but not in raster space", e.getMessage());
}
}
/**
* Tests the "Crop" operation when there exists a rotation in the world to
* grid transformation
*
* @throws TransformException if a transformation was required and failed.
*/
@Test
public void testCropRotated() throws TransformException {
/*
* Get the test coverage.
*/
final GridCoverage2D source = coverage;
/*
* Get the grid-to-world and apply a transformation in order to get a
* rotated coverage in the end.
*/
final AffineTransform gridToCRS = AffineTransform.getRotateInstance(Math.PI / 4.0);
gridToCRS.concatenate(getAffineTransform(source));
final MathTransform tr = ProjectiveTransform.create(gridToCRS);
CoordinateReferenceSystem crs = source.getCoordinateReferenceSystem();
crs = new DefaultDerivedCRS("Rotated CRS", crs, tr, crs.getCoordinateSystem());
final GridCoverage2D rotated = project(source, crs, null, null);
/*
* Preparing the crop. We want to get a rectangle that is locate at the
* center of this coverage envelope that is large 1/4 f the original
* width and tall 1/4 of the original height.
*/
final CoverageProcessor processor = CoverageProcessor.getInstance();
final Envelope oldEnvelope = rotated.getEnvelope();
final GeneralEnvelope cropEnvelope = new GeneralEnvelope(new double[] {
oldEnvelope.getMinimum(0) + oldEnvelope.getSpan(0) * 3 / 8,
oldEnvelope.getMinimum(1) + oldEnvelope.getSpan(1) * 3 / 8
}, new double[] {
oldEnvelope.getMinimum(0) + oldEnvelope.getSpan(0) * 5 / 8,
oldEnvelope.getMinimum(1) + oldEnvelope.getSpan(1) * 5 / 8
});
cropEnvelope.setCoordinateReferenceSystem(oldEnvelope.getCoordinateReferenceSystem());
/*
* Do the crop without trying to conserve the envelope.
*/
ParameterValueGroup param = processor.getOperation("CoverageCrop").getParameters();
param.parameter("Source").setValue(rotated);
param.parameter("Envelope").setValue(cropEnvelope);
GridCoverage2D cropped = (GridCoverage2D) processor.doOperation(param);
if (SHOW) {
Viewer.show(coverage);
Viewer.show(cropped);
} else {
// Force computation
assertNotNull(PlanarImage.wrapRenderedImage(cropped.getRenderedImage()).getTiles());
assertNotNull(PlanarImage.wrapRenderedImage(coverage.getRenderedImage()).getTiles());
}
RenderedImage raster = cropped.getRenderedImage();
assertEquals(111, raster.getMinX());
assertEquals(116, raster.getMinY());
assertEquals(228, raster.getWidth());
assertEquals(228, raster.getHeight());
assertEquals(rotated.getGridGeometry().getGridToCRS2D(),
cropped.getGridGeometry().getGridToCRS2D());
/*
* Get the roi and test it against the crop area
*/
Object property = CoverageUtilities.getROIProperty(cropped);
assertNotNull(property);
assertTrue(property instanceof ROI);
ROI roi = (ROI) property;
assertEquals(new Rectangle(raster.getMinX(), raster.getMinY(),
raster.getWidth(), raster.getHeight()), roi.getBounds());
}
/**
* Tests the "Crop" operation with a ROI set.
*/
@Test
public void testCropWithROI() throws TransformException, InterruptedException, FactoryException {
final CoverageProcessor processor = CoverageProcessor.getInstance();
/*
* Get the source coverage and build the cropped envelope.
*/
final GridCoverage2D source = coverage;
final Envelope oldEnvelope = source.getEnvelope();
final GeneralEnvelope cropEnvelope = new GeneralEnvelope(new double[] {
oldEnvelope.getMinimum(0) /*+ oldEnvelope.getSpan(0) * 3 / 8*/,
oldEnvelope.getMinimum(1) /*+ oldEnvelope.getSpan(1) * 3 / 8*/
}, new double[] {
oldEnvelope.getMinimum(0) + oldEnvelope.getSpan(0) * 5 / 8,
oldEnvelope.getMinimum(1) + oldEnvelope.getSpan(1) * 5 / 8
});
cropEnvelope.setCoordinateReferenceSystem(oldEnvelope.getCoordinateReferenceSystem());
GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory( JTSFactoryFinder.EMPTY_HINTS );
double mid0 = oldEnvelope.getMinimum(0) + oldEnvelope.getSpan(0)/2;
double mid1 = oldEnvelope.getMinimum(1) + oldEnvelope.getSpan(1)* 4/10;
double qspan0 = oldEnvelope.getSpan(0) * 2/16;
double qspan1 = oldEnvelope.getSpan(1) * 2/16;
double half0 = oldEnvelope.getSpan(0) * 1/10;
double half1 = oldEnvelope.getSpan(1) * 1/10;
// overlapping square #1 - rotated by 45deg
CoordinateSequence cs1 = new CoordinateArraySequence(5);
cs1.setOrdinate(0, 0, mid0);
cs1.setOrdinate(0, 1, mid1 + qspan1);
cs1.setOrdinate(1, 0, mid0 + qspan0);
cs1.setOrdinate(1, 1, mid1);
cs1.setOrdinate(2, 0, mid0);
cs1.setOrdinate(2, 1, mid1 - qspan1);
cs1.setOrdinate(3, 0, mid0 - qspan0);
cs1.setOrdinate(3, 1, mid1);
cs1.setOrdinate(4, 0, mid0);
cs1.setOrdinate(4, 1, mid1 + qspan1);
LinearRing shape1 = geometryFactory.createLinearRing(cs1);
com.vividsolutions.jts.geom.Polygon poly1 = geometryFactory.createPolygon(shape1, null);
// overlapping square #2
CoordinateSequence cs2 = new CoordinateArraySequence(5);
cs2.setOrdinate(0, 0, mid0 + half0);
cs2.setOrdinate(0, 1, mid1 + half1);
cs2.setOrdinate(1, 0, mid0 + half0);
cs2.setOrdinate(1, 1, mid1 - half1);
cs2.setOrdinate(2, 0, mid0 - half0);
cs2.setOrdinate(2, 1, mid1 - half1);
cs2.setOrdinate(3, 0, mid0 - half0);
cs2.setOrdinate(3, 1, mid1 + half1);
cs2.setOrdinate(4, 0, mid0 + half0);
cs2.setOrdinate(4, 1, mid1 + half1);
LinearRing shape2 = geometryFactory.createLinearRing(cs2);
com.vividsolutions.jts.geom.Polygon poly2 = geometryFactory.createPolygon(shape2, null);
// Disjuncted square lower left -- will be included
CoordinateSequence cs3 = new CoordinateArraySequence(5);
cs3.setOrdinate(0, 0, oldEnvelope.getMinimum(0));
cs3.setOrdinate(0, 1, oldEnvelope.getMinimum(1));
cs3.setOrdinate(1, 0, oldEnvelope.getMinimum(0) + oldEnvelope.getSpan(0) / 8);
cs3.setOrdinate(1, 1, oldEnvelope.getMinimum(1));
cs3.setOrdinate(2, 0, oldEnvelope.getMinimum(0) + oldEnvelope.getSpan(0) / 8);
cs3.setOrdinate(2, 1, oldEnvelope.getMinimum(1) + oldEnvelope.getSpan(1) / 8);
cs3.setOrdinate(3, 0, oldEnvelope.getMinimum(0) );
cs3.setOrdinate(3, 1, oldEnvelope.getMinimum(1) + oldEnvelope.getSpan(1) / 8);
cs3.setOrdinate(4, 0, oldEnvelope.getMinimum(0));
cs3.setOrdinate(4, 1, oldEnvelope.getMinimum(1));
LinearRing shape3 = geometryFactory.createLinearRing(cs3);
com.vividsolutions.jts.geom.Polygon poly3 = geometryFactory.createPolygon(shape3, null);
// Disjuncted square lower right -- will be excluded by Envelope
CoordinateSequence cs4 = new CoordinateArraySequence(5);
cs4.setOrdinate(0, 0, oldEnvelope.getMaximum(0));
cs4.setOrdinate(0, 1, oldEnvelope.getMinimum(1));
cs4.setOrdinate(1, 0, oldEnvelope.getMaximum(0) - oldEnvelope.getSpan(0) / 8);
cs4.setOrdinate(1, 1, oldEnvelope.getMinimum(1));
cs4.setOrdinate(2, 0, oldEnvelope.getMaximum(0) - oldEnvelope.getSpan(0) / 8);
cs4.setOrdinate(2, 1, oldEnvelope.getMinimum(1) + oldEnvelope.getSpan(1) / 8);
cs4.setOrdinate(3, 0, oldEnvelope.getMaximum(0) );
cs4.setOrdinate(3, 1, oldEnvelope.getMinimum(1) + oldEnvelope.getSpan(1) / 8);
cs4.setOrdinate(4, 0, oldEnvelope.getMaximum(0));
cs4.setOrdinate(4, 1, oldEnvelope.getMinimum(1));
LinearRing shape4 = geometryFactory.createLinearRing(cs4);
com.vividsolutions.jts.geom.Polygon poly4 = geometryFactory.createPolygon(shape4, null);
Geometry mpoly = geometryFactory.createMultiPolygon(new com.vividsolutions.jts.geom.Polygon[]{poly1, poly2});
// Geometry union = geometryFactory.createGeometryCollection(new Geometry[]{
// poly1, poly2, poly3, poly4});
Geometry union = geometryFactory.createGeometryCollection(new Geometry[]{
mpoly, poly3, poly4});
ParameterValueGroup param = processor.getOperation("CoverageCrop").getParameters();
param.parameter("Source").setValue(source);
param.parameter("Envelope").setValue(cropEnvelope);
param.parameter("ROI").setValue(union);
GridCoverage2D cropped = (GridCoverage2D) processor.doOperation(param);
if (SHOW) {
Viewer.show(coverage, "Original");
Viewer.show(cropped, "Cropped");
Thread.sleep(10000);
} else {
// Force computation
assertNotNull(PlanarImage.wrapRenderedImage(cropped.getRenderedImage()).getTiles());
}
RenderedImage raster = cropped.getRenderedImage();
assertEquals(0, raster.getMinX());
assertEquals(219, raster.getMinY());
assertEquals(281, raster.getWidth());
assertEquals(241, raster.getHeight());
assertEquals(source.getGridGeometry().getGridToCRS2D(),
cropped.getGridGeometry().getGridToCRS2D());
assertFalse(cropEnvelope.equals(cropped.getEnvelope()));
}
/**
* Tests the "Crop" operation with a ROI set.
*/
@Test
public void testCropWithROIForceMosaic() throws TransformException, InterruptedException, FactoryException {
final CoverageProcessor processor = CoverageProcessor.getInstance();
/*
* Get the source coverage and build the cropped envelope.
*/
final GridCoverage2D source = coverage;
final Envelope oldEnvelope = source.getEnvelope();
final GeneralEnvelope cropEnvelope = new GeneralEnvelope(new double[] {
oldEnvelope.getMinimum(0) /*+ oldEnvelope.getSpan(0) * 3 / 8*/,
oldEnvelope.getMinimum(1) /*+ oldEnvelope.getSpan(1) * 3 / 8*/
}, new double[] {
oldEnvelope.getMinimum(0) + oldEnvelope.getSpan(0), //* 5 / 8,
oldEnvelope.getMinimum(1) + oldEnvelope.getSpan(1) //* 5 / 8
});
cropEnvelope.setCoordinateReferenceSystem(oldEnvelope.getCoordinateReferenceSystem());
GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory( JTSFactoryFinder.EMPTY_HINTS );
// Use this crop ROI
// (E) *---------* (A)
// / |
// (D) * |
// | |
// | |
// | |
// (C) *-----------* (B)
double min0 = cropEnvelope.getMinimum(0);
double min1 = cropEnvelope.getMinimum(1);
double max0 = cropEnvelope.getMaximum(0);
double max1 = cropEnvelope.getMaximum(1);
double mid0_E = min0 + cropEnvelope.getSpan(0)/16;
double mid1_D = max1 - cropEnvelope.getSpan(1)/16;
CoordinateSequence cs1 = new CoordinateArraySequence(6);
// A
cs1.setOrdinate(0, 0, max0);
cs1.setOrdinate(0, 1, max1);
// B
cs1.setOrdinate(1, 0, max0);
cs1.setOrdinate(1, 1, min1);
// C
cs1.setOrdinate(2, 0, min0);
cs1.setOrdinate(2, 1, min1);
// D
cs1.setOrdinate(3, 0, min0);
cs1.setOrdinate(3, 1, mid1_D);
// E
cs1.setOrdinate(4, 0, mid0_E);
cs1.setOrdinate(4, 1, max1);
// Close
cs1.setOrdinate(5, 0, max0);
cs1.setOrdinate(5, 1, max1);
LinearRing shape1 = geometryFactory.createLinearRing(cs1);
com.vividsolutions.jts.geom.Polygon mask = geometryFactory.createPolygon(shape1, null);
ParameterValueGroup param = processor.getOperation("CoverageCrop").getParameters();
param.parameter("Source").setValue(source);
param.parameter("Envelope").setValue(cropEnvelope);
param.parameter("ROI").setValue(mask);
GridCoverage2D cropped = (GridCoverage2D) processor.doOperation(param);
if (SHOW) {
Viewer.show(coverage, "Original");
Viewer.show(cropped, "Cropped");
Thread.sleep(10000);
} else {
// Force computation
assertNotNull(PlanarImage.wrapRenderedImage(cropped.getRenderedImage()).getTiles());
}
RenderedImage raster = cropped.getRenderedImage();
// Checking pixel values in the top left corner (0,0)
// It's not zero due to having used a crop instead of a mosaic
assertEquals(240, raster.getTile(0, 0).getSample(0, 0, 0));
assertTrue(cropEnvelope.equals(cropped.getEnvelope()));
// Forcing the mosaic operation and repeating the computation
param.parameter("ForceMosaic").setValue(true);
cropped = (GridCoverage2D) processor.doOperation(param);
raster = cropped.getRenderedImage();
// Now the value should be zero since we have cut away the corner
assertEquals(0, raster.getTile(0, 0).getSample(0, 0, 0));
assertTrue(cropEnvelope.equals(cropped.getEnvelope()));
}
/**
* Tests the intersection of the ROI and the cropEnvelope in the "Crop" operation.
*
*/
@Test
public void testCropWithROIIntersection() throws TransformException, InterruptedException, FactoryException {
final CoverageProcessor processor = CoverageProcessor.getInstance();
/*
* Get the source coverage and build the cropped envelope.
*/
final GridCoverage2D source = coverage;
final Envelope oldEnvelope = source.getEnvelope();
final GeneralEnvelope cropEnvelope = new GeneralEnvelope(new double[] {
oldEnvelope.getMinimum(0) /*+ oldEnvelope.getSpan(0) * 3 / 8*/,
oldEnvelope.getMinimum(1) /*+ oldEnvelope.getSpan(1) * 3 / 8*/
}, new double[] {
oldEnvelope.getMinimum(0) + oldEnvelope.getSpan(0) / 4,
oldEnvelope.getMinimum(1) + oldEnvelope.getSpan(1)
});
cropEnvelope.setCoordinateReferenceSystem(oldEnvelope.getCoordinateReferenceSystem());
GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory( JTSFactoryFinder.EMPTY_HINTS );
// overlapping square #1 - rotated by 45deg
CoordinateSequence cs1 = new CoordinateArraySequence(5);
cs1.setOrdinate(0, 0, oldEnvelope.getMedian(0));
cs1.setOrdinate(0, 1, oldEnvelope.getMaximum(1));
cs1.setOrdinate(1, 0, oldEnvelope.getMaximum(0));
cs1.setOrdinate(1, 1, oldEnvelope.getMedian(1));
cs1.setOrdinate(2, 0, oldEnvelope.getMedian(0));
cs1.setOrdinate(2, 1, oldEnvelope.getMinimum(1));
cs1.setOrdinate(3, 0, oldEnvelope.getMinimum(0));
cs1.setOrdinate(3, 1, oldEnvelope.getMedian(1));
cs1.setOrdinate(4, 0, oldEnvelope.getMedian(0));
cs1.setOrdinate(4, 1, oldEnvelope.getMaximum(1));
LinearRing shape1 = geometryFactory.createLinearRing(cs1);
com.vividsolutions.jts.geom.Polygon poly1 = geometryFactory.createPolygon(shape1, null);
ParameterValueGroup param = processor.getOperation("CoverageCrop").getParameters();
param.parameter("Source").setValue(source);
param.parameter("Envelope").setValue(cropEnvelope);
param.parameter("ROI").setValue(poly1);
GridCoverage2D cropped = (GridCoverage2D) processor.doOperation(param);
if (SHOW) {
Viewer.show(coverage, "Original");
Viewer.show(cropped, "Cropped");
Thread.sleep(10000);
} else {
// Force computation
assertNotNull(PlanarImage.wrapRenderedImage(cropped.getRenderedImage()).getTiles());
}
RenderedImage raster = cropped.getRenderedImage();
assertEquals(0, raster.getMinX());
assertEquals(115, raster.getMinY());
assertEquals(113, raster.getWidth());
assertEquals(230, raster.getHeight());
assertEquals(source.getGridGeometry().getGridToCRS2D(),
cropped.getGridGeometry().getGridToCRS2D());
assertFalse(cropEnvelope.equals(cropped.getEnvelope()));
}
/**
* Tests cropping to an external ROI.
*/
@Test
public void testCropWithExternalROI() throws TransformException, InterruptedException, FactoryException {
final CoverageProcessor processor = CoverageProcessor.getInstance();
/*
* Get the source coverage and build the cropped envelope.
*/
final GridCoverage2D source = coverage;
final Envelope oldEnvelope = source.getEnvelope();
final GeneralEnvelope cropEnvelope = new GeneralEnvelope(new double[] {
oldEnvelope.getMinimum(0),
oldEnvelope.getMinimum(1)
}, new double[] {
oldEnvelope.getMinimum(0) + oldEnvelope.getSpan(0) / 4,
oldEnvelope.getMinimum(1) + oldEnvelope.getSpan(1)
});
cropEnvelope.setCoordinateReferenceSystem(oldEnvelope.getCoordinateReferenceSystem());
GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory( JTSFactoryFinder.EMPTY_HINTS );
// external tri
CoordinateSequence cs1 = new CoordinateArraySequence(4);
cs1.setOrdinate(0, 0, oldEnvelope.getMaximum(0) + 1);
cs1.setOrdinate(0, 1, oldEnvelope.getMaximum(1));
cs1.setOrdinate(1, 0, oldEnvelope.getMaximum(0) + 2);
cs1.setOrdinate(1, 1, oldEnvelope.getMaximum(1));
cs1.setOrdinate(2, 0, oldEnvelope.getMaximum(0) + 2);
cs1.setOrdinate(2, 1, oldEnvelope.getMinimum(1));
cs1.setOrdinate(3, 0, oldEnvelope.getMaximum(0) + 1);
cs1.setOrdinate(3, 1, oldEnvelope.getMaximum(1));
LinearRing shape1 = geometryFactory.createLinearRing(cs1);
com.vividsolutions.jts.geom.Polygon poly1 = geometryFactory.createPolygon(shape1, null);
ParameterValueGroup param = processor.getOperation("CoverageCrop").getParameters();
param.parameter("Source").setValue(source);
param.parameter("Envelope").setValue(cropEnvelope);
param.parameter("ROI").setValue(poly1);
try {
processor.doOperation(param);
fail("Cropping outside bounds");
} catch (CannotCropException _) {
}
}
/**
* Test robustness checks
*/
@Test
public void testCropWithoutNeededParams() throws TransformException, InterruptedException, FactoryException {
final CoverageProcessor processor = CoverageProcessor.getInstance();
/*
* Get the source coverage and build the cropped envelope.
*/
final GridCoverage2D source = coverage;
ParameterValueGroup param = processor.getOperation("CoverageCrop").getParameters();
param.parameter("Source").setValue(source);
try {
processor.doOperation(param);
fail("Allowing missing parameters");
} catch (CannotCropException _) {
}
}
/**
* Tests the "Crop" operation with a ROI set, clipping at half pixel.
*/
@Test
public void testCropWithROIHalfPixel() throws TransformException, InterruptedException,
FactoryException {
// Disable MediaLib for this test
// Getting initial value
String disableMediaLibKey = "com.sun.media.jai.disableMediaLib";
String oldDisableMediaLib = System.getProperty(disableMediaLibKey, "false");
Registry.setNativeAccelerationAllowed("Mosaic", false);
// getting CoverageProcessor
final CoverageProcessor processor = CoverageProcessor.getInstance();
/*
* Create a simple Red image
*/
Byte[] red = new Byte[] { (byte) 255, 0, 0 };
RenderedOp image = ConstantDescriptor.create(Float.valueOf(40), Float.valueOf(37), red,
null);
final Envelope envelope = new ReferencedEnvelope(-1d, 1d, -1d, 1d,
DefaultGeographicCRS.WGS84);
/*
* Get the source coverage and build the cropped envelope.
*/
final GridCoverageFactory factory = new GridCoverageFactory(GeoTools.getDefaultHints());
final GridCoverage2D source = factory.create("test", image, envelope);
// Creating ROI for cropping
final ReferencedEnvelope cropBounds = new ReferencedEnvelope(0d, 1d, 0d, 1d,
DefaultGeographicCRS.WGS84);
com.vividsolutions.jts.geom.Polygon polygon = JTS.toGeometry(cropBounds);
Geometry roi = polygon.getFactory().createMultiPolygon(
new com.vividsolutions.jts.geom.Polygon[] { polygon });
ParameterValueGroup param = processor.getOperation("CoverageCrop").getParameters();
param.parameter("Source").setValue(source);
param.parameter("Envelope").setValue(cropBounds);
param.parameter("ROI").setValue(roi);
GridCoverage2D cropped = (GridCoverage2D) processor.doOperation(param);
if (SHOW) {
Viewer.show(source, "Original");
Viewer.show(cropped, "Cropped");
Thread.sleep(10000);
} else {
// Force computation
assertNotNull(PlanarImage.wrapRenderedImage(cropped.getRenderedImage()).getTiles());
}
RenderedImage raster = cropped.getRenderedImage();
assertEquals(20, raster.getMinX());
assertEquals(0, raster.getMinY());
assertEquals(20, raster.getWidth());
assertEquals(19, raster.getHeight());
assertEquals(source.getGridGeometry().getGridToCRS2D(), cropped.getGridGeometry()
.getGridToCRS2D());
// Ensure the pixels are RED
byte[] result = new byte[3];
// Upper Left
cropped.evaluate(new DirectPosition2D(0d, 0d), result);
assertEquals((byte) red[0], result[0]);
assertEquals((byte) red[1], result[1]);
assertEquals((byte) red[2], result[2]);
// Setting old acceleration value for Mosaic
Registry.setNativeAccelerationAllowed("Mosaic", Boolean.valueOf(oldDisableMediaLib));
}
}