/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2011-2012, Open Source Geospatial Foundation (OSGeo)
* (C) 2011-2012, Geomatys
*
* 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.geotoolkit.image.io.plugin;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.awt.image.RenderedImage;
import org.opengis.util.FactoryException;
import org.opengis.coverage.grid.GridEnvelope;
import org.opengis.referencing.operation.Matrix;
import org.opengis.referencing.operation.MathTransform;
import org.apache.sis.measure.NumberRange;
import org.geotoolkit.coverage.Category;
import org.geotoolkit.coverage.GridSampleDimension;
import org.geotoolkit.coverage.grid.GridGeometry2D;
import org.geotoolkit.coverage.grid.GridCoverage2D;
import org.geotoolkit.coverage.io.ImageCoverageReader;
import org.geotoolkit.coverage.io.CoverageStoreException;
import org.geotoolkit.image.io.metadata.SpatialMetadata;
import org.apache.sis.referencing.operation.transform.LinearTransform;
import org.geotoolkit.referencing.operation.transform.DimensionFilter;
import org.apache.sis.test.TestUtilities;
import org.junit.*;
import static org.geotoolkit.test.Assert.*;
import static org.geotoolkit.test.Commons.*;
import static org.geotoolkit.image.io.metadata.SpatialMetadataFormat.GEOTK_FORMAT_NAME;
/**
* Tests reading a format in which the data are already geophysics.
*
* @author Martin Desruisseaux (Geomatys)
* @version 3.20
*
* @since 3.19
*/
public final strictfp class GeophysicsFormatTest extends NetcdfImageReaderTestBase {
/**
* Returns the file to test, which is optional. If the test file is not present,
* the test will be interrupted by the JUnit {@link org.junit.Assume} class.
*
* @return The test file (never null).
*/
public static File getTestFile() {
return getLocallyInstalledFile("Norway/b_cf.nc");
}
/**
* Creates a reader and initializes its input to the test file defined in
* {@link #getTestFile()}. This method is invoked by each tests inherited
* from the parent class, and by the tests defined in this class.
*/
@Override
protected void prepareImageReader(final boolean setInput) throws IOException {
if (reader == null) {
reader = new NetcdfImageReader(null);
}
if (setInput) {
reader.setInput(getTestFile());
}
}
/**
* Tests the metadata tree.
*
* @throws IOException if an error occurred while reading the file.
* @throws CoverageStoreException Should never happen.
*/
@Test
public void testMetadata() throws IOException, CoverageStoreException {
prepareImageReader(true);
final NetcdfImageReader reader = (NetcdfImageReader) this.reader;
final SpatialMetadata metadata = reader.getImageMetadata(0);
final String asTree = metadata.toString();
assertNotNull(metadata);
assertMultilinesEquals(decodeQuotes(
GEOTK_FORMAT_NAME + '\n' +
"├───RectifiedGridDomain\n" +
"│ ├───origin=“6.0 68.0 55.0 73.0”\n" +
"│ ├───Limits\n" +
"│ │ ├───low=“0 0 0 0”\n" +
"│ │ └───high=“128 65 0 107”\n" +
"│ ├───OffsetVectors\n" +
"│ │ ├───OffsetVector\n" +
"│ │ │ └───values=“0.5 0.0 0.0 0.0”\n" +
"│ │ ├───OffsetVector\n" +
"│ │ │ └───values=“0.0 0.2 0.0 0.0”\n" +
"│ │ ├───OffsetVector\n" +
"│ │ │ └───values=“0.0 0.0 NaN 0.0”\n" +
"│ │ └───OffsetVector\n" +
"│ │ └───values=“0.0 0.0 0.0 NaN”\n" +
"│ └───CoordinateReferenceSystem\n" +
"│ ├───name=“NetCDF:time depth lat lon”\n" +
"│ └───CoordinateSystem\n" +
"│ ├───name=“NetCDF:time depth lat lon”\n" +
"│ ├───dimension=“4”\n" +
"│ └───Axes\n" +
"│ ├───CoordinateSystemAxis\n" +
"│ │ ├───name=“NetCDF:lon”\n" +
"│ │ ├───axisAbbrev=“λ”\n" +
"│ │ ├───direction=“east”\n" +
"│ │ ├───minimumValue=“6.0”\n" +
"│ │ ├───maximumValue=“70.0”\n" +
"│ │ └───unit=“°”\n" +
"│ ├───CoordinateSystemAxis\n" +
"│ │ ├───name=“NetCDF:lat”\n" +
"│ │ ├───axisAbbrev=“φ”\n" +
"│ │ ├───direction=“north”\n" +
"│ │ ├───minimumValue=“68.0”\n" +
"│ │ ├───maximumValue=“81.0”\n" +
"│ │ └───unit=“°”\n" +
"│ ├───CoordinateSystemAxis\n" +
"│ │ ├───name=“NetCDF:depth”\n" +
"│ │ ├───axisAbbrev=“d”\n" +
"│ │ ├───direction=“down”\n" +
"│ │ ├───minimumValue=“55.0”\n" +
"│ │ ├───maximumValue=“55.0”\n" +
"│ │ └───unit=“m”\n" +
"│ └───CoordinateSystemAxis\n" +
"│ ├───name=“NetCDF:time”\n" +
"│ ├───axisAbbrev=“t”\n" +
"│ ├───direction=“future”\n" +
"│ ├───minimumValue=“73.0”\n" +
"│ ├───maximumValue=“9845.0”\n" +
"│ └───unit=“d”\n" +
"├───SpatialRepresentation\n" +
"│ ├───numberOfDimensions=“4”\n" +
"│ ├───centerPoint=“38.0 74.5 55.0 4959.0”\n" +
"│ └───pointInPixel=“center”\n" +
"└───ImageDescription\n" +
" └───Dimensions\n" +
" └───Dimension\n" +
" ├───descriptor=“temp”\n" +
" ├───units=“Celcius”\n" +
" ├───minValue=“-2.0”\n" +
" ├───maxValue=“30.0”\n" +
" ├───validSampleValues=“[-2 … 30]”\n" +
" └───fillSampleValues=“-99.99”\n"), asTree);
}
/**
* Tests reading the data with the {@link ImageCoverageReader}.
*
* @throws IOException if an error occurred while reading the file.
* @throws CoverageStoreException Should never happen.
* @throws FactoryException Should never happen.
*/
@Test
public void testCoverageReader() throws IOException, CoverageStoreException, FactoryException {
prepareImageReader(true);
final ImageCoverageReader reader = new ImageCoverageReader();
reader.setInput(this.reader);
assertEquals("temp", TestUtilities.getSingleton(reader.getCoverageNames()).toString());
final GridCoverage2D coverage = reader.read(0, null);
reader.dispose(); // Dispose also the NetcdfImageReader.
//
// Inspect the sample dimensions.
//
final GridSampleDimension band = coverage.getSampleDimension(0);
assertTrue("Expected geophysics data.", band.getSampleToGeophysics().isIdentity());
final List<Category> categories = band.getCategories();
assertEquals(2, categories.size());
//
// Quantitative category
//
Category category = categories.get(0);
NumberRange<?> range = category.getRange();
assertEquals("temp", category.getName().toString());
assertEquals("temp", -2.0, range.getMinDouble(), 0.0);
assertEquals("temp", 30.0, range.getMaxDouble(), 0.0);
//
// "No data" category.
//
category = categories.get(1);
range = category.getRange();
assertTrue(Double.isNaN(range.getMinDouble()));
assertTrue(Double.isNaN(range.getMaxDouble()));
category = category.geophysics(false);
range = category.getRange();
assertEquals(-99.99, range.getMinDouble(), 0.001);
assertEquals(-99.99, range.getMaxDouble(), 0.001);
//
// The raster should contains only values in the [-2 .. 30] range.
// If some -99.99 values have not been properly converted to NaN,
// then this test will fail.
//
final RenderedImage image = coverage.getRenderedImage();
assertSampleValuesInRange(-2, 30, image);
//
// Check the grid geometry.
//
final GridGeometry2D gridGeometry = coverage.getGridGeometry();
final GridEnvelope gridExtent = gridGeometry.getExtent();
assertEquals("GridEnvelope.getDimension()", 4, gridExtent.getDimension());
assertArrayEquals("GridEnvelope.getLow()", new int[4], gridExtent.getLow().getCoordinateValues());
assertArrayEquals("GridEnvelope.getHigh()", new int[] {128, 65, 0, 0}, // TODO: last value should be 107.
gridExtent.getHigh().getCoordinateValues());
//
// Check the scale and translation factors of the 2 first dimensions.
// Note that the transform as a whole is an instance of NetcdfGridToCRS,
// so we need to extract the first dimensions in order to get the scale factors.
//
MathTransform tr = gridGeometry.getGridToCRS();
assertFalse(tr.getClass().getName(), tr instanceof LinearTransform);
final DimensionFilter filter = new DimensionFilter(tr);
filter.addSourceDimensions(0, 1);
tr = filter.separate();
assertInstanceOf("DimensionFilter.separate(gridToCRS)", LinearTransform.class, tr);
final Matrix gridToCRS = ((LinearTransform) tr).getMatrix();
assertEquals("Scale X", 0.5, gridToCRS.getElement(0, 0), 0.0);
assertEquals("Scale Y", 0.2, gridToCRS.getElement(1, 1), 0.0);
assertEquals("Translate X", 6.0, gridToCRS.getElement(0, 2), 0.0);
assertEquals("Translate Y", 68.0, gridToCRS.getElement(1, 2), 0.0);
}
}