/* * Geotoolkit.org - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2009-2012, Open Source Geospatial Foundation (OSGeo) * (C) 2009-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.coverage.grid; import java.awt.Color; import java.awt.Rectangle; import java.awt.geom.Rectangle2D; import java.awt.image.DataBuffer; import java.awt.image.RenderedImage; import java.awt.image.WritableRaster; import javax.media.jai.RasterFactory; import java.io.IOException; import org.opengis.metadata.content.TransferFunctionType; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.MathTransform1D; import org.geotoolkit.image.SampleImage; import org.geotoolkit.coverage.Category; import org.geotoolkit.coverage.CoverageFactoryFinder; import org.geotoolkit.coverage.GridSampleDimension; import org.apache.sis.geometry.Envelope2D; import org.apache.sis.geometry.GeneralEnvelope; import org.apache.sis.referencing.CommonCRS; import org.apache.sis.referencing.operation.transform.MathTransforms; import org.apache.sis.referencing.operation.transform.TransferFunction; import static java.awt.Color.decode; import static org.apache.sis.measure.Units.*; import static org.apache.sis.measure.NumberRange.create; import static org.junit.Assert.*; /** * Enumeration of sample grid coverages. * * @author Martin Desruisseaux (Geomatys) * @version 3.20 * * @since 3.02 */ public strictfp enum SampleCoverage { /** * Sea Surface Temperature. * This is a raster from Earth observations using a relatively straightforward * conversion formula to geophysics values (a linear transform using the usual * scale and offset parameters, in this case 0.1 and 10 respectively). The * interesting part of this example is that it contains a lot of nodata values. * * {@preformat text * Thematic : Sea Surface Temperature (SST) in °C * Data packaging : Indexed 8-bits * Nodata values : [0 .. 29] and [240 .. 255] inclusive. * Conversion formula : (°C) = (packed value)/10 + 10 * Geographic extent : (41°S, 35°E) - (5°N, 80°E) * Image size : (450 x 460) pixels * } */ SST(SampleImage.INDEXED, CommonCRS.WGS84.normalizedGeographic(), new Rectangle(35, -41, 45, 46), new GridSampleDimension("Measure", new Category[] { new Category("Coast line", decode("#000000"), create( 0, true, 0, true)), new Category("Cloud", decode("#C3C3C3"), create( 1, true, 9, true)), new Category("Unused", decode("#822382"), create( 10, true, 29, true)), new Category("Sea Surface Temperature", null, create( 30, true, 219, true), 0.1, 10.0), new Category("Unused", decode("#A0505C"), create(220, true, 239, true)), new Category("Land", decode("#D2C8A0"), create(240, true, 254, true)), new Category("No data", decode("#FFFFFF"), create(255, true, 255, true)), }, CELSIUS)), /** * Chlorophyl-a concentration. * This is a raster from Earth observations using a more complex conversion * formula to geophysics values (an exponential one). The usual scale and * offset parameters are not enough in this case. * * {@preformat text * Thematic : Chlorophyle-a concentration in mg/m³ * Data packaging : Indexed 8-bits * Nodata values : 0 and 255 * Conversion formula : (mg/m³) = 10 ^ ((packed value)*0.015 - 1.985) * Geographic extent : (34°N, 07°W) - (45°N, 12°E) * Image size : (300 x 175) pixels * } */ CHL(SampleImage.INDEXED_LOGARITHMIC, CommonCRS.WGS84.normalizedGeographic(), new Rectangle(-7, 34, 19, 11), new GridSampleDimension("Measure", new Category[] { new Category("Land", decode("#000000"), create(255, true, 255, true)), new Category("No data", decode("#FFFFFF"), create( 0, true, 0, true)), new Category("Chl-a", null, create( 1, true, 254, true), MathTransforms.concatenate( (MathTransform1D) MathTransforms.linear(0.015, -1.985), exp())) }, KILOGRAM.divide(1E6).divide(CUBIC_METRE))), /** * A float coverage. Because we use only one tile with one band, the code below * is pretty similar to the code we would have if we were just setting the values * in a matrix. */ FLOAT(null, CommonCRS.WGS84.normalizedGeographic(), new Rectangle(35, -41, 45, 46)) { @Override final WritableRaster raster() { final int width = 500; final int height = 500; final WritableRaster raster = RasterFactory.createBandedRaster(DataBuffer.TYPE_FLOAT, width, height, 1, null); for (int y=0; y<height; y++) { for (int x=0; x<width; x++) { raster.setSample(x, y, 0, x+y); } } return raster; } @Override final GridCoverage2D load() { final Color[] colors = new Color[] { Color.BLUE, Color.CYAN, Color.WHITE, Color.YELLOW, Color.RED }; final GridCoverageFactory factory = CoverageFactoryFinder.getGridCoverageFactory(null); return factory.create("Float coverage", raster(), new Envelope2D(this.crs, this.bounds), null, null, null, new Color[][] {colors}, null); } }; private static MathTransform1D exp() { final TransferFunction f = new TransferFunction(); f.setType(TransferFunctionType.EXPONENTIAL); return f.getTransform(); } /** * The enum for the image to load, or {@code null} if the image is computed rather * than loaded. */ private final SampleImage image; /** * The coordinate reference system for the coverage. */ final CoordinateReferenceSystem crs; /** * The envelope in CRS coordinates. */ final Rectangle2D bounds; /** * The sample dimensions to be given to the coverage. */ private final GridSampleDimension[] bands; /** * Creates a new enum loading the given image. */ private SampleCoverage(final SampleImage image, CoordinateReferenceSystem crs, final Rectangle2D bounds, GridSampleDimension... bands) { this.image = image; this.crs = crs; this.bounds = bounds; this.bands = bands; } /** * Loads or computes the raster. * * @return The sample raster. * @throws IOException If the raster can not be read. * * @since 3.20 */ WritableRaster raster() throws IOException { return image.load().getRaster(); } /** * Loads the sample coverage. * * @return The sample coverage. * @throws IOException If the image can not be read. */ GridCoverage2D load() throws IOException { final RenderedImage image = this.image.load(); final GeneralEnvelope envelope = new org.geotoolkit.geometry.GeneralEnvelope(bounds); envelope.setCoordinateReferenceSystem(crs); final GridCoverageFactory factory = CoverageFactoryFinder.getGridCoverageFactory(null); return factory.create(this.image.filename, image, envelope, bands, null, null); } /** * Verifies that the grid geometry of the given coverage is conform to the expected one. * * @param coverage The coverage to verify. * @param eps Tolerance threshold for comparisons of floating point numbers. * * @since 3.20 */ void verifyGridGeometry(final GridCoverage2D coverage, final double eps) { assertSame(crs, coverage.getCoordinateReferenceSystem2D()); assertArrayEquals(new double[] {bounds.getMinX(), bounds.getMinY()}, coverage.getEnvelope2D().getLowerCorner().getCoordinate(), eps); assertArrayEquals(new double[] {bounds.getMaxX(), bounds.getMaxY()}, coverage.getEnvelope2D().getUpperCorner().getCoordinate(), eps); } }