/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 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.io.netcdf; import org.apache.commons.io.FileUtils; import org.geotools.coverage.grid.GridCoverage2D; import org.geotools.coverage.grid.io.AbstractGridFormat; import org.geotools.factory.Hints; import org.geotools.gce.imagemosaic.ImageMosaicFormat; import org.geotools.gce.imagemosaic.ImageMosaicReader; import org.geotools.gce.imagemosaic.Utils; import org.geotools.referencing.CRS; import org.geotools.test.TestData; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.opengis.parameter.GeneralParameterValue; import org.opengis.parameter.ParameterValue; import javax.media.jai.PlanarImage; import java.awt.image.DataBuffer; import java.awt.image.Raster; import java.io.File; import java.util.Arrays; import java.util.List; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; /** * Tests that a data set that contains a dimension with multiple bands is correctly handled. * Is very important to use a clean test directory for each run, this guarantees that * generated files (like the binary index for example) are not reused. The stations data * set is very small (perfect for testing proposes) please use netcdf dump if you need to * check is content. */ public final class NetCDFStationsTest extends Assert { @Before public void init() { // make sure CRS ordering is correct System.setProperty("org.geotools.referencing.forceXY", "true"); CRS.reset("all"); } @Test public void readMultipleBandsDimension() throws Exception { // we should have three bands and all the values should be present checkRasterData(new GeneralParameterValue[]{}, new int[]{5, 6, 7, 8, 9, 0, 1, 2, 3, 4}, new int[]{105, 106, 107, 108, 109, 100, 101, 102, 103, 104}, new int[]{1005, 1006, 1007, 1008, 1009, 1000, 1001, 1002, 1003, 1004}); } @Test public void readMultipleBandsDimensionSelectingOnlyOneBand() throws Exception { // we should have only band a single band ParameterValue<int[]> selectedBands = AbstractGridFormat.BANDS.createValue(); selectedBands.setValue(new int[]{1}); checkRasterData(new GeneralParameterValue[]{selectedBands}, new int[]{105, 106, 107, 108, 109, 100, 101, 102, 103, 104}); } @Test public void readMultipleBandsDimensionWithDifferentOrderBandsSelection() throws Exception { // we should have three bands with values indexes ordered as 2, 0, 1 ParameterValue<int[]> selectedBands = AbstractGridFormat.BANDS.createValue(); selectedBands.setValue(new int[]{2, 0, 1}); checkRasterData(new GeneralParameterValue[]{selectedBands}, new int[]{1005, 1006, 1007, 1008, 1009, 1000, 1001, 1002, 1003, 1004}, new int[]{5, 6, 7, 8, 9, 0, 1, 2, 3, 4}, new int[]{105, 106, 107, 108, 109, 100, 101, 102, 103, 104}); } @Test public void readMultipleBandsDimensionWithDifferentOrderAndRepeatedBandsSelection() throws Exception { // we should have six bands with values indexes ordered as 2, 0, 1, 1, 2, 0 ParameterValue<int[]> selectedBands = AbstractGridFormat.BANDS.createValue(); selectedBands.setValue(new int[]{2, 0, 1, 1, 2, 0}); checkRasterData(new GeneralParameterValue[]{selectedBands}, new int[]{1005, 1006, 1007, 1008, 1009, 1000, 1001, 1002, 1003, 1004}, new int[]{5, 6, 7, 8, 9, 0, 1, 2, 3, 4}, new int[]{105, 106, 107, 108, 109, 100, 101, 102, 103, 104}, new int[]{105, 106, 107, 108, 109, 100, 101, 102, 103, 104}, new int[]{1005, 1006, 1007, 1008, 1009, 1000, 1001, 1002, 1003, 1004}, new int[]{5, 6, 7, 8, 9, 0, 1, 2, 3, 4}); } /** * Helper method that simply checks that the raster contains the expected data. The number of bands * should match the number of expected banks in the provided order. This testes are run for the * NetCDF reader and the ImageMosaicReader. */ private void checkRasterData(GeneralParameterValue[] parameters, int[]... expected) throws Exception { checkRasterData(readCoverageUsingNetCdfReader(parameters), expected); checkRasterData(readCoverageUsingImageMosaicReader(parameters), expected); } /** * Helper method that simply checks that the raster contains the expected data. The number of bands * should match the number of expected banks in the provided order. */ private void checkRasterData(Raster data, int[]... expected) { // we should have a number of bands equal to the number of banks abd equal to number of expected results assertThat(data.getNumBands(), is(expected.length)); assertThat(data.getDataBuffer().getNumBanks(), is(expected.length)); // let's check if the banks values match the expected values for (int i = 0; i < expected.length; i++) { int[] bank = readBank(data.getDataBuffer(), i); checkArrayContainsArray(bank, expected[i]); } } /** * Checks that arrayA contains arrayB. */ private void checkArrayContainsArray(int[] arrayA, int[] arrayB) { for (int i = 0; i < arrayB.length; i++) { boolean found = false; for (int j = 0; j < arrayA.length; j++) { if (arrayB[i] == arrayA[j]) { found = true; } } assertThat(found, is(true)); } } /** * Helper method that reads stationA data set using the NetCdf reader directly. * Some basic checks are also made. */ private Raster readCoverageUsingNetCdfReader(GeneralParameterValue[] readParameters) throws Exception { // create test directory for this test removing any existing one File testDirectory = new File(TestData.file(this, "."), "MultipleBandsDimensionTest"); FileUtils.deleteQuietly(testDirectory); assertThat(testDirectory.mkdirs(), is(true)); // just keeping a reference to the reader so we can close it in the finally block NetCDFReader reader = null; try { // move test files to the test directory FileUtils.copyFileToDirectory(TestData.file(this, "stations.nc"), testDirectory); FileUtils.copyFileToDirectory(TestData.file(this, "stations.xml"), testDirectory); File netCdfFile = new File(testDirectory, "stations.nc"); File auxiliaryFile = new File(testDirectory, "stations.xml"); // instantiate the netcdf reader, add the auxiliary file as an hint for the reader final Hints hints = new Hints(Utils.AUXILIARY_FILES_PATH, auxiliaryFile.getPath()); reader = new NetCDFReader(netCdfFile, hints); // checking that we have four coverages (only the first station has values others stations values are zero) List<String> names = Arrays.asList(reader.getGridCoverageNames()); assertThat(names.contains("stationA"), is(true)); assertThat(names.contains("stationB"), is(true)); assertThat(names.contains("stationC"), is(true)); assertThat(names.contains("stationD"), is(true)); // reading stationA data set GridCoverage2D coverage = reader.read("stationA", readParameters); assertThat(coverage, notNullValue()); return PlanarImage.wrapRenderedImage(coverage.getRenderedImage()).getData(); } finally { // cleaning the tests directory FileUtils.deleteQuietly(testDirectory); if (reader != null) { reader.dispose(); } } } /** * Helper method that reads stationA data set using the image mosaic reader directly. * Some basic checks are also made. */ private Raster readCoverageUsingImageMosaicReader(GeneralParameterValue[] readParameters) throws Exception { // create test directory for this test removing any existing one File testDirectory = new File(TestData.file(this, "."), "MultipleBandsDimensionTest"); FileUtils.deleteQuietly(testDirectory); assertThat(testDirectory.mkdirs(), is(true)); // just keeping a reference to the reader so we can close it in the finally block ImageMosaicReader reader = null; try { // move test files to the test directory FileUtils.copyFileToDirectory(TestData.file(this, "stations.nc"), testDirectory); FileUtils.copyFileToDirectory(TestData.file(this, "stations_mosaic_indexer.xml"), testDirectory); FileUtils.copyFileToDirectory(TestData.file(this, "stations_netcdf_auxiliary.xml"), testDirectory); FileUtils.copyFileToDirectory(TestData.file(this, "stations_datastore.properties"), testDirectory); FileUtils.moveFile(new File(testDirectory, "stations_mosaic_indexer.xml"), new File(testDirectory, "indexer.xml")); FileUtils.moveFile(new File(testDirectory, "stations_netcdf_auxiliary.xml"), new File(testDirectory, "netcdf_auxiliary.xml")); FileUtils.moveFile(new File(testDirectory, "stations_datastore.properties"), new File(testDirectory, "datastore.properties")); // instantiate the image mosaic reader ImageMosaicFormat format = new ImageMosaicFormat(); reader = format.getReader(testDirectory); // reading stationA data set GridCoverage2D coverage = reader.read("stationA", readParameters); assertThat(coverage, notNullValue()); PlanarImage image = PlanarImage.wrapRenderedImage(coverage.getRenderedImage()); return image.getData(); } finally { // cleaning the tests directory FileUtils.deleteQuietly(testDirectory); if (reader != null) { reader.dispose(); } } } /** * Helper method that simply reads a bank of data from a data buffer. */ private int[] readBank(DataBuffer dataBuffer, int bank) { int[] data = new int[dataBuffer.getSize()]; for (int i = 0; i < dataBuffer.getSize(); i++) { data[i] = dataBuffer.getElem(bank, i); } return data; } }