/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2013 - 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.gce.imagemosaic; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.awt.Dimension; import java.awt.Rectangle; import java.awt.Transparency; import java.awt.geom.Point2D; import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.net.URL; import java.util.Properties; import javax.media.jai.PlanarImage; import javax.media.jai.ROI; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.geotools.coverage.grid.GridCoverage2D; import org.geotools.coverage.grid.GridEnvelope2D; import org.geotools.coverage.grid.GridGeometry2D; import org.geotools.coverage.grid.io.AbstractGridFormat; import org.geotools.coverage.grid.io.footprint.FootprintBehavior; import org.geotools.coverage.grid.io.footprint.FootprintInsetPolicy; import org.geotools.coverage.grid.io.footprint.MultiLevelROIProviderFactory; import org.geotools.data.DataUtilities; import org.geotools.data.shapefile.ShapefileDataStore; import org.geotools.data.simple.SimpleFeatureStore; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; import org.geotools.geometry.DirectPosition2D; import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.referencing.CRS; import org.geotools.referencing.crs.DefaultGeographicCRS; import org.geotools.resources.coverage.CoverageUtilities; import org.geotools.resources.image.ImageUtilities; import org.geotools.test.TestData; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.opengis.feature.Feature; import org.opengis.feature.FeatureVisitor; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.feature.type.GeometryDescriptor; import org.opengis.geometry.Envelope; import org.opengis.parameter.GeneralParameterValue; import org.opengis.parameter.ParameterValue; import org.opengis.referencing.FactoryException; import org.opengis.referencing.NoSuchAuthorityCodeException; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.datum.PixelInCell; import org.opengis.referencing.operation.MathTransform; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.io.WKBWriter; import com.vividsolutions.jts.io.WKTWriter; public class ImageMosaicFootprintsTest { private File testMosaic; private URL testMosaicUrl; private File footprintsSource; @Before public void cleanup() throws IOException { // clean up testMosaic = new File(TestData.file(this,"."),"footprintMosaic"); if (testMosaic.exists()) { FileUtils.deleteDirectory(testMosaic); } // create the base mosaic we are going to use File mosaicSource = TestData.file(this,"rgb"); FileUtils.copyDirectory(mosaicSource, testMosaic); testMosaicUrl = DataUtilities.fileToURL(testMosaic); // footprint source footprintsSource = TestData.file(this,"rgb-footprints"); } @Test public void testSingleShapefileDefaults() throws Exception { // copy the footprints mosaic over FileUtils.copyDirectory(footprintsSource, testMosaic); assertItalyFootprints(); } @Test public void testWkbSidecars() throws Exception { // create wkb sidecar files ShapefileDataStore ds = new ShapefileDataStore(DataUtilities.fileToURL(new File( footprintsSource, "footprints.shp"))); ds.getFeatureSource().getFeatures().accepts(new FeatureVisitor() { @Override public void visit(Feature feature) { try { SimpleFeature sf = (SimpleFeature) feature; String fileName = (String) sf.getAttribute("location"); int idx = fileName.lastIndexOf("."); Geometry g = (Geometry) sf.getDefaultGeometry(); File wkbFile = new File(testMosaic, fileName.substring(0, idx) + ".wkb"); byte[] bytes = new WKBWriter().write(g); FileUtils.writeByteArrayToFile(wkbFile, bytes); } catch (IOException e) { throw new RuntimeException(e); } } }, null); ds.dispose(); assertItalyFootprints(); } @Test public void testWktSidecars() throws Exception { // create wkb sidecar files ShapefileDataStore ds = new ShapefileDataStore(DataUtilities.fileToURL(new File( footprintsSource, "footprints.shp"))); ds.getFeatureSource().getFeatures().accepts(new FeatureVisitor() { @Override public void visit(Feature feature) { try { SimpleFeature sf = (SimpleFeature) feature; String fileName = (String) sf.getAttribute("location"); int idx = fileName.lastIndexOf("."); Geometry g = (Geometry) sf.getDefaultGeometry(); File wkbFile = new File(testMosaic, fileName.substring(0, idx) + ".wkt"); String wkt = new WKTWriter().write(g); FileUtils.writeStringToFile(wkbFile, wkt); } catch (IOException e) { throw new RuntimeException(e); } } }, null); ds.dispose(); assertItalyFootprints(); } @Test public void testShapefileSidecars() throws Exception { // create wkb sidecar files ShapefileDataStore ds = new ShapefileDataStore(DataUtilities.fileToURL(new File( footprintsSource, "footprints.shp"))); ds.getFeatureSource().getFeatures().accepts(new FeatureVisitor() { @Override public void visit(Feature feature) { try { SimpleFeature sf = (SimpleFeature) feature; String fileName = (String) sf.getAttribute("location"); int idx = fileName.lastIndexOf("."); Geometry g = (Geometry) sf.getDefaultGeometry(); String filename = fileName.substring(0, idx); File shpFile = new File(testMosaic, filename + ".shp"); ShapefileDataStore sds = new ShapefileDataStore( DataUtilities.fileToURL(shpFile)); SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder(); tb.setName(filename); GeometryDescriptor gd = sf.getFeatureType().getGeometryDescriptor(); tb.add("the_geom", gd.getType().getBinding(), gd.getCoordinateReferenceSystem()); SimpleFeatureType sft = tb.buildFeatureType(); sds.createSchema(sft); SimpleFeatureBuilder fb = new SimpleFeatureBuilder(sft); fb.add(g); SimpleFeature footprintFeature = fb.buildFeature(null); SimpleFeatureStore fs = (SimpleFeatureStore) sds.getFeatureSource(); fs.addFeatures(DataUtilities.collection(footprintFeature)); sds.dispose(); } catch (IOException e) { throw new RuntimeException(e); } } }, null); assertItalyFootprints(); } private void assertItalyFootprints() throws NoSuchAuthorityCodeException, FactoryException, IOException { GridCoverage2D coverage = readCoverage(); // RenderedImageBrowser.showChain(coverage.getRenderedImage()); // System.in.read(); // check the footprints have been applied by pocking the output image byte[] pixel = new byte[3]; // Mar Ionio, should be black coverage.evaluate(new DirectPosition2D(16.87, 40.19), pixel); assertEquals(0, pixel[0]); assertEquals(0, pixel[1]); assertEquals(0, pixel[2]); // Golfo di La Spezia, should be black coverage.evaluate(new DirectPosition2D(9.12, 44.25), pixel); assertEquals(0, pixel[0]); assertEquals(0, pixel[1]); assertEquals(0, pixel[2]); // Sardinia, not black coverage.evaluate(new DirectPosition2D(9, 40), pixel); assertTrue(pixel[0] + pixel[1] + pixel[2] > 0); // Piedmont, not black coverage.evaluate(new DirectPosition2D(8, 45), pixel); assertTrue(pixel[0] + pixel[1] + pixel[2] > 0); } private GridCoverage2D readCoverage() throws NoSuchAuthorityCodeException, FactoryException, IOException { final AbstractGridFormat format = TestUtils.getFormat(testMosaicUrl); final ImageMosaicReader reader = TestUtils.getReader(testMosaicUrl, format); // activate footprint management GeneralParameterValue[] params = new GeneralParameterValue[2]; ParameterValue<String> footprintManagement = AbstractGridFormat.FOOTPRINT_BEHAVIOR.createValue(); footprintManagement.setValue(FootprintBehavior.Cut.name()); params[0] = footprintManagement; // this prevents us from having problems with link to files still open. ParameterValue<Boolean> jaiImageRead = ImageMosaicFormat.USE_JAI_IMAGEREAD.createValue(); jaiImageRead.setValue(false); params[1] = jaiImageRead; GridCoverage2D coverage = reader.read(params); reader.dispose(); assertNotNull(coverage); return coverage; } @Test public void testAreaOutside() throws Exception { // copy the footprints mosaic over FileUtils.copyDirectory(footprintsSource, testMosaic); Properties p = new Properties(); p.put(FootprintInsetPolicy.INSET_PROPERTY, "0.1"); saveFootprintProperties(p); final AbstractGridFormat format = TestUtils.getFormat(testMosaicUrl); final ImageMosaicReader reader = TestUtils.getReader(testMosaicUrl, format); // activate footprint management GeneralParameterValue[] params = new GeneralParameterValue[3]; ParameterValue<String> footprintManagement = AbstractGridFormat.FOOTPRINT_BEHAVIOR.createValue(); footprintManagement.setValue(FootprintBehavior.None.name()); params[0] = footprintManagement; // this prevents us from having problems with link to files still open. ParameterValue<Boolean> jaiImageRead = ImageMosaicFormat.USE_JAI_IMAGEREAD.createValue(); jaiImageRead.setValue(false); params[1] = jaiImageRead; // limit yourself to reading just a bit of it final ParameterValue<GridGeometry2D> gg = AbstractGridFormat.READ_GRIDGEOMETRY2D .createValue(); final Dimension dim = new Dimension(); dim.setSize(4, 4); final Rectangle rasterArea = ((GridEnvelope2D) reader.getOriginalGridRange()); rasterArea.setSize(dim); final GridEnvelope2D range = new GridEnvelope2D(rasterArea); gg.setValue(new GridGeometry2D(range, PixelInCell.CELL_CENTER,reader.getOriginalGridToWorld(PixelInCell.CELL_CENTER),reader.getCoordinateReferenceSystem(),null)); params[2]=gg; GridCoverage2D coverage = reader.read(params); reader.dispose(); assertNotNull(coverage); } @Test public void testRequestHole() throws Exception { // copy the footprints mosaic over FileUtils.copyDirectory(footprintsSource, testMosaic); Properties p = new Properties(); p.put(FootprintInsetPolicy.INSET_PROPERTY, "0.1"); saveFootprintProperties(p); final AbstractGridFormat format = TestUtils.getFormat(testMosaicUrl); ImageMosaicReader reader = TestUtils.getReader(testMosaicUrl, format); reader.dispose(); // get rid of the sample image File sampleImage = new File(testMosaic, Utils.SAMPLE_IMAGE_NAME); sampleImage.delete(); // a new reader without the sample image, in normal conditions it can actually produce // output reader = TestUtils.getReader(testMosaicUrl, format); // activate footprint management GeneralParameterValue[] params = new GeneralParameterValue[3]; ParameterValue<String> footprintManagement = AbstractGridFormat.FOOTPRINT_BEHAVIOR .createValue(); footprintManagement.setValue(FootprintBehavior.Transparent.name()); params[0] = footprintManagement; // this prevents us from having problems with link to files still open. ParameterValue<Boolean> jaiImageRead = ImageMosaicFormat.USE_JAI_IMAGEREAD.createValue(); jaiImageRead.setValue(false); params[1] = jaiImageRead; // limit yourself to reading just a bit of it MathTransform mt = reader.getOriginalGridToWorld(PixelInCell.CELL_CENTER); GridEnvelope2D ge = new GridEnvelope2D(6, 44, 1, 1); final ParameterValue<GridGeometry2D> gg = AbstractGridFormat.READ_GRIDGEOMETRY2D .createValue(); gg.setValue(new GridGeometry2D(ge, mt, DefaultGeographicCRS.WGS84)); params[2] = gg; // read the first time, no sample_image yet present GridCoverage2D coverage = reader.read(params); reader.dispose(); assertNotNull(coverage); RenderedImage ri = coverage.getRenderedImage(); assertNotEquals(Transparency.OPAQUE, ri.getColorModel().getTransparency()); reader.dispose(); // read a second time reader = TestUtils.getReader(testMosaicUrl, format); coverage = reader.read(params); reader.dispose(); assertNotNull(coverage); ri = coverage.getRenderedImage(); assertNotEquals(Transparency.OPAQUE, ri.getColorModel().getTransparency()); reader.dispose(); } @Test public void testInsetsFull() throws Exception { // copy the footprints mosaic over FileUtils.copyDirectory(footprintsSource, testMosaic); Properties p = new Properties(); p.put(FootprintInsetPolicy.INSET_PROPERTY, "0.1"); p.put(FootprintInsetPolicy.INSET_TYPE_PROPERTY, "full"); saveFootprintProperties(p); GridCoverage2D coverage = readCoverage(); // check the footprints have been applied by pocking the output image byte[] pixel = new byte[3]; // Close to San Marino, black if we have the insets coverage.evaluate(new DirectPosition2D(12.54, 44.03), pixel); assertEquals(0, pixel[0]); assertEquals(0, pixel[1]); assertEquals(0, pixel[2]); // Inner BORDER gets black with FULL insets coverage.evaluate(new DirectPosition2D(11.52, 44.57), pixel); assertEquals(0, pixel[0]); assertEquals(0, pixel[1]); assertEquals(0, pixel[2]); // Golfo di La Spezia, should be black coverage.evaluate(new DirectPosition2D(9.12, 44.25), pixel); assertEquals(0, pixel[0]); assertEquals(0, pixel[1]); assertEquals(0, pixel[2]); // Sardinia, not black coverage.evaluate(new DirectPosition2D(9, 40), pixel); assertTrue(pixel[0] + pixel[1] + pixel[2] > 0); // Piedmont, not black coverage.evaluate(new DirectPosition2D(8, 45), pixel); assertTrue(pixel[0] + pixel[1] + pixel[2] > 0); disposeCoverage(coverage); final ImageMosaicReader reader = TestUtils.getReader(testMosaicUrl, new ImageMosaicFormat()); // activate footprint management GeneralParameterValue[] params = new GeneralParameterValue[3]; ParameterValue<String> footprintManagement = AbstractGridFormat.FOOTPRINT_BEHAVIOR.createValue(); footprintManagement.setValue(FootprintBehavior.Transparent.name()); params[0] = footprintManagement; // this prevents us from having problems with link to files still open. ParameterValue<Boolean> jaiImageRead = ImageMosaicFormat.USE_JAI_IMAGEREAD.createValue(); jaiImageRead.setValue(false); params[1] = jaiImageRead; // GridGeometry, small aread at the upper right corner final GridEnvelope2D ge2D= new GridEnvelope2D( reader.getOriginalGridRange().getHigh(0)-3, reader.getOriginalGridRange().getLow(1), 3, 3); final GridGeometry2D gg2D= new GridGeometry2D(ge2D, reader.getOriginalGridToWorld(PixelInCell.CELL_CENTER), reader.getCoordinateReferenceSystem()); ParameterValue<GridGeometry2D> gg2DParam = ImageMosaicFormat.READ_GRIDGEOMETRY2D.createValue(); gg2DParam.setValue(gg2D); params[2] = gg2DParam; coverage = reader.read(params); MathTransform tr = reader.getOriginalGridToWorld(PixelInCell.CELL_CORNER); reader.dispose(); assertNotNull(coverage); // check the footprints have been applied by pocking the output image pixel = new byte[4]; // Close to San Marino, black if we have the insets coverage.evaluate(new DirectPosition2D(coverage.getEnvelope().getMinimum(0) + 1e-3, coverage.getEnvelope().getMinimum(1) + 1e-3), pixel); assertEquals(0, pixel[0]); assertEquals(0, pixel[1]); assertEquals(0, pixel[2]); assertEquals(0, pixel[3]); disposeCoverage(coverage); } @Test public void testInsetsMargin() throws Exception { // copy the footprints mosaic over FileUtils.copyDirectory(footprintsSource, testMosaic); Properties p = new Properties(); p.put(FootprintInsetPolicy.INSET_PROPERTY, "0.1"); p.put(FootprintInsetPolicy.INSET_TYPE_PROPERTY, "border"); saveFootprintProperties(p); GridCoverage2D coverage = readCoverage(); // // check the footprints have been applied by pocking the output image byte[] pixel = new byte[3]; // Close to San Marino, black if we have the insets coverage.evaluate(new DirectPosition2D(12.54, 44.03), pixel); assertEquals(0, pixel[0]); assertEquals(0, pixel[1]); assertEquals(0, pixel[2]); // Inner BORDER should not get black with border insets coverage.evaluate(new DirectPosition2D(11.52, 44.57), pixel); assertTrue(pixel[0] + pixel[1] + pixel[2] > 0); // Golfo di La Spezia, should be black coverage.evaluate(new DirectPosition2D(9.12, 44.25), pixel); assertEquals(0, pixel[0]); assertEquals(0, pixel[1]); assertEquals(0, pixel[2]); // Sardinia, not black coverage.evaluate(new DirectPosition2D(9, 40), pixel); assertTrue(pixel[0] + pixel[1] + pixel[2] > 0); // Piedmont, not black coverage.evaluate(new DirectPosition2D(8, 45), pixel); assertTrue(pixel[0] + pixel[1] + pixel[2] > 0); disposeCoverage(coverage); final ImageMosaicReader reader = TestUtils.getReader(testMosaicUrl, new ImageMosaicFormat()); // activate footprint management GeneralParameterValue[] params = new GeneralParameterValue[3]; ParameterValue<String> footprintManagement = AbstractGridFormat.FOOTPRINT_BEHAVIOR.createValue(); footprintManagement.setValue(FootprintBehavior.Transparent.name()); params[0] = footprintManagement; // this prevents us from having problems with link to files still open. ParameterValue<Boolean> jaiImageRead = ImageMosaicFormat.USE_JAI_IMAGEREAD.createValue(); jaiImageRead.setValue(false); params[1] = jaiImageRead; // GridGeometry, small read at the upper right corner final GridEnvelope2D ge2D= new GridEnvelope2D( reader.getOriginalGridRange().getHigh(0)-3, reader.getOriginalGridRange().getLow(1), 3, 3); final GridGeometry2D gg2D= new GridGeometry2D(ge2D, reader.getOriginalGridToWorld(PixelInCell.CELL_CENTER), reader.getCoordinateReferenceSystem()); ParameterValue<GridGeometry2D> gg2DParam = ImageMosaicFormat.READ_GRIDGEOMETRY2D.createValue(); gg2DParam.setValue(gg2D); params[2] = gg2DParam; coverage = reader.read(params); MathTransform tr = reader.getOriginalGridToWorld(PixelInCell.CELL_CORNER); reader.dispose(); assertNotNull(coverage); // check the footprints have been applied by pocking the output image pixel = new byte[4]; // Close to San Marino, black if we have the insets coverage.evaluate(new DirectPosition2D(coverage.getEnvelope().getMinimum(0) + 1e-3 ,coverage.getEnvelope().getMinimum(1) + 1e-3), pixel); assertEquals(0, pixel[0]); assertEquals(0, pixel[1]); assertEquals(0, pixel[2]); assertEquals(0, pixel[3]); disposeCoverage(coverage); } /** * Dispose the provided coverage for good. * @param coverage */ private void disposeCoverage(GridCoverage2D coverage) { if(coverage==null){ return; } final RenderedImage im= coverage.getRenderedImage(); ImageUtilities.disposePlanarImageChain(PlanarImage.wrapRenderedImage(im)); coverage.dispose(true); } private void saveFootprintProperties(Properties p) throws FileNotFoundException, IOException { FileOutputStream fos = null; try { fos = new FileOutputStream(new File(testMosaic, "footprints.properties")); p.store(fos, null); } finally { IOUtils.closeQuietly(fos); } } @AfterClass public static void close(){ System.clearProperty("org.geotools.referencing.forceXY"); CRS.reset("all"); } @BeforeClass public static void init(){ //make sure CRS ordering is correct CRS.reset("all"); System.setProperty("org.geotools.referencing.forceXY", "true"); } @Test public void testInsetsBorder() throws Exception { // copy the footprints mosaic over FileUtils.copyDirectory(footprintsSource, testMosaic); Properties p = new Properties(); p.put(FootprintInsetPolicy.INSET_PROPERTY, "0.1"); saveFootprintProperties(p); GridCoverage2D coverage = readCoverage(); // check the footprints have been applied by pocking the output image byte[] pixel = new byte[3]; // Close to San Marino, black if we have the insets coverage.evaluate(new DirectPosition2D(12.54, 44.03), pixel); assertEquals(0, pixel[0]); assertEquals(0, pixel[1]); assertEquals(0, pixel[2]); // Golfo di La Spezia, should be black coverage.evaluate(new DirectPosition2D(9.12, 44.25), pixel); assertEquals(0, pixel[0]); assertEquals(0, pixel[1]); assertEquals(0, pixel[2]); // Sardinia, not black coverage.evaluate(new DirectPosition2D(9, 40), pixel); assertTrue(pixel[0] + pixel[1] + pixel[2] > 0); // Piedmont, not black coverage.evaluate(new DirectPosition2D(8, 45), pixel); assertTrue(pixel[0] + pixel[1] + pixel[2] > 0); disposeCoverage(coverage); } @Test public void testFootprintA() throws IOException { ImageMosaicReader reader = (ImageMosaicReader) new ImageMosaicFormatFactory().createFormat() .getReader(TestData.file(this,"footprint_a")); GeneralParameterValue[] params = new GeneralParameterValue[1]; ParameterValue<String> footprintManagement = AbstractGridFormat.FOOTPRINT_BEHAVIOR .createValue(); footprintManagement.setValue(FootprintBehavior.Transparent.name()); params[0] = footprintManagement; GridCoverage2D coverage = reader.read(params); byte[] result = new byte[4]; DirectPosition2D position = new DirectPosition2D(); position.setLocation(1, 1); coverage.evaluate(position, result); //RGBA assertEquals(4, coverage.getSampleDimensions().length); //Transparent assertEquals(0, result[3]); position = new DirectPosition2D(); position.setLocation(-1, -1); coverage.evaluate(position, result); //Blue assertEquals(0, result[0]); assertEquals(0, result[1]); assertTrue(0 != result[2]); assertTrue(0 != result[3]); } @Test public void testFootprintRGB() throws FileNotFoundException, IOException { testFootprint(TestData.file(this,"footprint_rgb")); } @Test public void testFootprintRGBA() throws FileNotFoundException, IOException { testFootprint(TestData.file(this,"footprint_rgba")); } public void testFootprint(File mosaic) throws IOException { ImageMosaicReader reader = (ImageMosaicReader) new ImageMosaicFormatFactory().createFormat() .getReader(mosaic); GeneralParameterValue[] params = new GeneralParameterValue[1]; ParameterValue<String> footprintManagement = AbstractGridFormat.FOOTPRINT_BEHAVIOR .createValue(); footprintManagement.setValue(FootprintBehavior.Transparent.name()); params[0] = footprintManagement; GridCoverage2D coverage = reader.read(params); byte[] result = new byte[4]; DirectPosition2D position = new DirectPosition2D(); position.setLocation(1, 1); coverage.evaluate(position, result); //Red assertTrue(0 != result[0]); assertEquals(0, result[1]); assertEquals(0, result[2]); assertTrue(0 != result[3]); position = new DirectPosition2D(); position.setLocation(-1, -1); coverage.evaluate(position, result); //Blue assertEquals(0, result[0]); assertEquals(0, result[1]); assertTrue(0 != result[2]); assertTrue(0 != result[3]); } @Test public void testRasterFootprintExternal() throws Exception { // Raster File testMosaicRaster = new File(TestData.file(this, "."), "footprintRaster"); if (testMosaicRaster.exists()) { FileUtils.deleteDirectory(testMosaicRaster); } // Reading Coverage with Raster footprint GridCoverage2D coverage = readRasterFootprint("rastermask", testMosaicRaster, false); // Evaluate results byte[] results = new byte[4]; DirectPosition2D position = new DirectPosition2D(); // Should be 0 position.setLocation(-86.724, 25.085); results = coverage.evaluate(position, results); assertEquals(results[0], 0); assertEquals(results[1], 0); assertEquals(results[2], 0); assertEquals(results[3], 0); // Should be > 0 position.setLocation(-86.252, 27.7984); results = coverage.evaluate(position, results); assertTrue(results[0] != 0); assertTrue(results[1] != 0); assertTrue(results[2] != 0); assertTrue(results[3] != 0); // Should be 0 position.setLocation(-87.937, 26.144); results = coverage.evaluate(position, results); assertEquals(results[0], 0); assertEquals(results[1], 0); assertEquals(results[2], 0); assertEquals(results[3], 0); // Should be > 0 position.setLocation(-89.084, 27.133); results = coverage.evaluate(position, results); assertTrue(results[0] != 0); assertTrue(results[1] != 0); assertTrue(results[2] != 0); assertTrue(results[3] != 0); // Should be 0 position.setLocation(-89.763, 25.167); results = coverage.evaluate(position, results); assertEquals(results[0], 0); assertEquals(results[1], 0); assertEquals(results[2], 0); assertEquals(results[3], 0); } @Test public void testRasterFootprintSubmsampling() throws Exception { // Raster File testMosaicRaster = new File(TestData.file(this, "."), "footprintRasterSubsampling"); if (testMosaicRaster.exists()) { FileUtils.deleteDirectory(testMosaicRaster); } // Reading Coverage with Raster footprint GridCoverage2D coverage = readRasterFootprint("masked2", testMosaicRaster, true); // check the ROI and the image are black in the same pixels ROI roi = CoverageUtilities.getROIProperty(coverage); Raster roiImage = roi.getAsImage().getData(); Raster image = coverage.getRenderedImage().getData(); int[] px = new int[4]; int[] rpx = new int[1]; for (int i = 0; i < image.getHeight(); i++) { for (int j = 0; j < image.getWidth(); j++) { image.getPixel(j, i, px); roiImage.getPixel(j, i, rpx); if (px[0] == 0 && px[1] == 0 && px[2] == 0) { assertEquals("Difference at " + i + "," + j, 0, rpx[0]); } else { assertEquals("Difference at " + i + "," + j, 1, rpx[0]); } } } } @Test public void testRasterFootprintInternal() throws Exception { // Raster File testMosaicRaster = new File(TestData.file(this, "."), "footprintRaster"); if (testMosaicRaster.exists()) { FileUtils.deleteDirectory(testMosaicRaster); } // Reading Coverage with Raster footprint GridCoverage2D coverage = readRasterFootprint("rastermask2", testMosaicRaster, false); // Evaluate results byte[] results = new byte[4]; DirectPosition2D position = new DirectPosition2D(); // Should be 0 position.setLocation(-86.724, 25.085); results = coverage.evaluate(position, results); assertEquals(results[0], 0); assertEquals(results[1], 0); assertEquals(results[2], 0); assertEquals(results[3], 0); // Should be > 0 position.setLocation(-86.252, 27.7984); results = coverage.evaluate(position, results); assertTrue(results[0] != 0); assertTrue(results[1] != 0); assertTrue(results[2] != 0); assertTrue(results[3] != 0); // Should be 0 position.setLocation(-87.937, 26.144); results = coverage.evaluate(position, results); assertEquals(results[0], 0); assertEquals(results[1], 0); assertEquals(results[2], 0); assertEquals(results[3], 0); // Should be > 0 position.setLocation(-89.084, 27.133); results = coverage.evaluate(position, results); assertTrue(results[0] != 0); assertTrue(results[1] != 0); assertTrue(results[2] != 0); assertTrue(results[3] != 0); // Should be 0 position.setLocation(-89.763, 25.167); results = coverage.evaluate(position, results); assertEquals(results[0], 0); assertEquals(results[1], 0); assertEquals(results[2], 0); assertEquals(results[3], 0); } @Test public void testRasterFootprintExternalMask() throws Exception { // Raster File testMosaicRaster = new File(TestData.file(this, "."), "footprintRaster"); if (testMosaicRaster.exists()) { FileUtils.deleteDirectory(testMosaicRaster); } // Reading Coverage with Raster footprint GridCoverage2D coverage = readRasterFootprint("rastermask", testMosaicRaster, true); // Evaluate results byte[] results = new byte[4]; DirectPosition2D position = new DirectPosition2D(); // Should be 0 but since the mask is subsampled, it may happen that the // final pixel is not masked position.setLocation(-86.724, 25.085); results = coverage.evaluate(position, results); assertTrue(results[0] != 0); assertTrue(results[1] != 0); assertTrue(results[2] != 0); assertTrue(results[3] != 0); // Should be > 0 position.setLocation(-86.252, 27.7984); results = coverage.evaluate(position, results); assertTrue(results[0] != 0); assertTrue(results[1] != 0); assertTrue(results[2] != 0); assertTrue(results[3] != 0); // Should be 0 but since the mask is subsampled, it may happen that the // final pixel is not masked position.setLocation(-87.937, 26.144); results = coverage.evaluate(position, results); assertTrue(results[0] != 0); assertTrue(results[1] != 0); assertTrue(results[2] != 0); assertTrue(results[3] != 0); // Should be > 0 position.setLocation(-89.084, 27.133); results = coverage.evaluate(position, results); assertTrue(results[0] != 0); assertTrue(results[1] != 0); assertTrue(results[2] != 0); assertTrue(results[3] != 0); // Should be 0 position.setLocation(-89.763, 25.167); results = coverage.evaluate(position, results); assertEquals(results[0], 0); assertEquals(results[1], 0); assertEquals(results[2], 0); assertEquals(results[3], 0); } @Test public void testRasterFootprintInternalMaskAndOverviews() throws Exception { // Raster File testMosaicRaster = new File(TestData.file(this, "."), "footprintRaster"); if (testMosaicRaster.exists()) { FileUtils.deleteDirectory(testMosaicRaster); } // Reading Coverage with Raster footprint GridCoverage2D coverage = readRasterFootprint("rastermask2", testMosaicRaster, true); // Evaluate results byte[] results = new byte[4]; DirectPosition2D position = new DirectPosition2D(); // Should be 0 position.setLocation(-86.724, 25.085); results = coverage.evaluate(position, results); assertEquals(results[0], 0); assertEquals(results[1], 0); assertEquals(results[2], 0); assertEquals(results[3], 0); // Should be > 0 position.setLocation(-86.252, 27.7984); results = coverage.evaluate(position, results); assertTrue(results[0] != 0); assertTrue(results[1] != 0); assertTrue(results[2] != 0); assertTrue(results[3] != 0); // Should be 0 position.setLocation(-87.937, 26.144); results = coverage.evaluate(position, results); assertEquals(results[0], 0); assertEquals(results[1], 0); assertEquals(results[2], 0); assertEquals(results[3], 0); // Should be > 0 position.setLocation(-89.084, 27.133); results = coverage.evaluate(position, results); assertTrue(results[0] != 0); assertTrue(results[1] != 0); assertTrue(results[2] != 0); assertTrue(results[3] != 0); // Should be 0 position.setLocation(-89.763, 25.167); results = coverage.evaluate(position, results); assertEquals(results[0], 0); assertEquals(results[1], 0); assertEquals(results[2], 0); assertEquals(results[3], 0); } private GridCoverage2D readRasterFootprint(String path, File testMosaicRaster, boolean testOverviews) throws Exception { // create the base mosaic we are going to use File mosaicSourceRaster = TestData.file(this, path); FileUtils.copyDirectory(mosaicSourceRaster, testMosaicRaster); URL testMosaicRasterUrl = DataUtilities.fileToURL(testMosaicRaster); // copy the footprints mosaic properties Properties p = new Properties(); // Setting Raster property p.put(MultiLevelROIProviderFactory.SOURCE_PROPERTY, "raster"); FileOutputStream fos = null; try { fos = new FileOutputStream(new File(testMosaicRaster, "footprints.properties")); p.store(fos, null); } finally { IOUtils.closeQuietly(fos); } final AbstractGridFormat format = TestUtils.getFormat(testMosaicRasterUrl); final ImageMosaicReader reader = TestUtils.getReader(testMosaicRasterUrl, format); // activate footprint management GeneralParameterValue[] params = new GeneralParameterValue[3]; ParameterValue<String> footprintManagement = AbstractGridFormat.FOOTPRINT_BEHAVIOR .createValue(); footprintManagement.setValue(FootprintBehavior.Transparent.name()); params[0] = footprintManagement; // this prevents us from having problems with link to files still open. ParameterValue<Boolean> jaiImageRead = ImageMosaicFormat.USE_JAI_IMAGEREAD.createValue(); jaiImageRead.setValue(false); params[1] = jaiImageRead; // setup how much we are going to read final ParameterValue<GridGeometry2D> gg = AbstractGridFormat.READ_GRIDGEOMETRY2D .createValue(); final Rectangle rasterArea = ((GridEnvelope2D) reader.getOriginalGridRange()); if (testOverviews) { Dimension dim = new Dimension(); dim.setSize(8, 8); rasterArea.setSize(dim); final GridEnvelope2D range = new GridEnvelope2D(rasterArea); gg.setValue(new GridGeometry2D(range, reader.getOriginalEnvelope())); params[2] = gg; } else { final GridEnvelope2D range = new GridEnvelope2D(rasterArea); gg.setValue(new GridGeometry2D(range, PixelInCell.CELL_CENTER, reader .getOriginalGridToWorld(PixelInCell.CELL_CENTER), reader .getCoordinateReferenceSystem(), null)); params[2] = gg; } // Read the coverage GridCoverage2D coverage = reader.read(params); reader.dispose(); assertNotNull(coverage); // Check if ROI is present ROI roi = CoverageUtilities.getROIProperty(coverage); assertNotNull(roi); // Checking ROI Bounds // Ensure has the same size of the input image Rectangle roiBounds = roi.getBounds(); Rectangle imgBounds = coverage.getGridGeometry().getGridRange2D(); assertEquals(imgBounds.x, roiBounds.x); assertEquals(imgBounds.y, roiBounds.y); assertEquals(imgBounds.width, roiBounds.width); assertEquals(imgBounds.height, roiBounds.height); return coverage; } @Rule public TemporaryFolder redFootprintFolder = new TemporaryFolder(); /** * When the mosaic bounds don't match the requested image bounds, there's only one granule in the requested bounds * and FootprintBehavior is transparent a border is added to the image. This actually only happens in * very specific circumstances, like in the test data which is an L shaped. In this case the * footprint behavior was not being respected, resulting in a background color even though the * background should be transparent. * */ @Test public void testFootprintWithBorderNeeded() throws IOException { File testFolder = redFootprintFolder.newFolder(); File mosaic = TestData.file(this, "red_footprint_test"); FileUtils.copyDirectory(mosaic, testFolder); ImageMosaicReader reader = (ImageMosaicReader) new ImageMosaicFormatFactory().createFormat() .getReader(testFolder); ParameterValue<String> footprintBehaviorParam = AbstractGridFormat.FOOTPRINT_BEHAVIOR.createValue(); footprintBehaviorParam.setValue(FootprintBehavior.Transparent.name()); ParameterValue<GridGeometry2D> readGeom = AbstractGridFormat.READ_GRIDGEOMETRY2D.createValue(); CoordinateReferenceSystem coordinateReferenceSystem = reader.getOriginalEnvelope() .getCoordinateReferenceSystem(); GridEnvelope2D gridRange = new GridEnvelope2D(0,0,100,100); Envelope requestEnvelope = new ReferencedEnvelope(989964.5828856088, 990881.0173239836, 218260.08651691137, 219176.52095528613, coordinateReferenceSystem); GridGeometry2D readGeometry = new GridGeometry2D(gridRange, requestEnvelope); readGeom.setValue(readGeometry); GeneralParameterValue[] readParams = new GeneralParameterValue[]{footprintBehaviorParam, readGeom}; GridCoverage2D coverage = reader.read(readParams); int numComponents = coverage.getRenderedImage().getColorModel().getNumComponents(); assertEquals(numComponents, 4); } }