This is an automated email from the ASF dual-hosted git repository.
jsorel pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git
The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
new adafeb6 Coverage : add GridCoverage implementation based on a
RenderedImage
adafeb6 is described below
commit adafeb67371ae6c19acbc47bf678824996d12590
Author: jsorel <[email protected]>
AuthorDate: Thu Nov 14 11:38:50 2019 +0100
Coverage : add GridCoverage implementation based on a RenderedImage
---
.../sis/internal/coverage/GridCoverage2D.java | 117 +++++++++++++++++++
.../sis/internal/coverage/GridCoverage2DTest.java | 126 +++++++++++++++++++++
.../apache/sis/test/suite/FeatureTestSuite.java | 3 +-
3 files changed, 245 insertions(+), 1 deletion(-)
diff --git
a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/GridCoverage2D.java
b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/GridCoverage2D.java
new file mode 100644
index 0000000..842ca9d
--- /dev/null
+++
b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/GridCoverage2D.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.internal.coverage;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.RenderedImage;
+import java.awt.image.WritableRaster;
+import java.util.Collection;
+import org.apache.sis.coverage.SampleDimension;
+import org.apache.sis.coverage.grid.GridCoverage;
+import org.apache.sis.coverage.grid.GridExtent;
+import org.apache.sis.coverage.grid.GridGeometry;
+import org.apache.sis.util.ArgumentChecks;
+import org.opengis.coverage.CannotEvaluateException;
+
+/**
+ * A {@link GridCoverage} with data stored in a {@link RenderedImage}.
+ *
+ * @author Johann Sorel (Geomatys)
+ * @version 2.0
+ * @since 2.0
+ * @module
+ */
+public class GridCoverage2D extends GridCoverage {
+ /**
+ * The sample values, stored as a RenderedImage.
+ */
+ protected final RenderedImage image;
+
+ /**
+ * Result of the call to {@link #forConvertedValues(boolean)}, created
when first needed.
+ */
+ private GridCoverage converted;
+
+ /**
+ *
+ * @param grid the grid extent, CRS and conversion from cell indices to
CRS.
+ * @param bands sample dimensions for each image band.
+ * @param image the sample values as a RenderedImage, potentially
multi-banded in packed view.
+ */
+ public GridCoverage2D(final GridGeometry grid, final Collection<? extends
SampleDimension> bands, final RenderedImage image) {
+ super(grid, bands);
+ this.image = image;
+ ArgumentChecks.ensureNonNull("image", image);
+ }
+
+ /**
+ * Returns a grid coverage that contains real values or sample values,
depending if {@code converted} is {@code true}
+ * or {@code false} respectively.
+ *
+ * If the given value is {@code false}, then the default implementation
returns a grid coverage which produces
+ * {@link RenderedImage} views. Those views convert each sample value on
the fly. This is known to be very slow
+ * if an entire raster needs to be processed, but this is temporary until
another implementation is provided in
+ * a future SIS release.
+ *
+ * @return a coverage containing converted or packed values, depending on
{@code converted} argument value.
+ */
+ @Override
+ public GridCoverage forConvertedValues(final boolean converted) {
+ if (converted) {
+ synchronized (this) {
+ if (this.converted == null) {
+ this.converted = BufferedGridCoverage.convert(this);
+ }
+ return this.converted;
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Returns a two-dimensional slice of grid data as a rendered image.
+ * This method may return a view or a copy.
+ *
+ * @return the grid slice as a rendered image.
+ */
+ @Override
+ public RenderedImage render(GridExtent sliceExtent) throws
CannotEvaluateException {
+ if (sliceExtent == null ||
sliceExtent.equals(getGridGeometry().getExtent())) {
+ return image;
+ } else {
+ final int[] imgAxes = sliceExtent.getSubspaceDimensions(2);
+ final int subX = Math.toIntExact(sliceExtent.getLow(imgAxes[0]));
+ final int subY = Math.toIntExact(sliceExtent.getLow(imgAxes[1]));
+ final int subWidth =
Math.toIntExact(Math.round(sliceExtent.getSize(imgAxes[0])));
+ final int subHeight =
Math.toIntExact(Math.round(sliceExtent.getSize(imgAxes[1])));
+
+ if (image instanceof BufferedImage) {
+ final BufferedImage bi = (BufferedImage) image;
+ return bi.getSubimage(subX, subY, subWidth, subHeight);
+ } else {
+ //todo : current approach makes a copy of the datas, a better
solution should be found
+ final WritableRaster raster =
image.getTile(image.getMinTileX(),
image.getMinTileY()).createCompatibleWritableRaster(subWidth, subHeight);
+ final WritableRaster derivate =
raster.createWritableTranslatedChild(subX, subY);
+ image.copyData(derivate);
+ ColorModel cm = image.getColorModel();
+ return new BufferedImage(cm, raster,
cm.isAlphaPremultiplied(), null);
+ }
+ }
+ }
+
+}
diff --git
a/core/sis-feature/src/test/java/org/apache/sis/internal/coverage/GridCoverage2DTest.java
b/core/sis-feature/src/test/java/org/apache/sis/internal/coverage/GridCoverage2DTest.java
new file mode 100644
index 0000000..ed6d759
--- /dev/null
+++
b/core/sis-feature/src/test/java/org/apache/sis/internal/coverage/GridCoverage2DTest.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.internal.coverage;
+
+import java.awt.Point;
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+import java.util.Arrays;
+import java.util.Hashtable;
+import org.apache.sis.coverage.SampleDimension;
+import org.apache.sis.coverage.grid.GridCoverage;
+import org.apache.sis.coverage.grid.GridExtent;
+import org.apache.sis.coverage.grid.GridGeometry;
+import org.apache.sis.measure.NumberRange;
+import org.apache.sis.measure.Units;
+import org.apache.sis.referencing.crs.HardCodedCRS;
+import org.apache.sis.referencing.operation.transform.MathTransforms;
+import org.apache.sis.test.TestCase;
+import org.junit.Assert;
+import org.junit.Test;
+import org.opengis.referencing.datum.PixelInCell;
+import org.opengis.referencing.operation.MathTransform1D;
+
+
+/**
+ * Tests the {@link GridCoverage2D} implementation.
+ *
+ * @author Johann Sorel (Geomatys)
+ * @version 2.0
+ * @since 2.0
+ * @module
+ */
+public class GridCoverage2DTest extends TestCase {
+ /**
+ * Tests with a two-dimensional coverage.
+ */
+ @Test
+ public void testCoverage2D() {
+ /*
+ * Create coverage of 2×2 pixels with an identity "grid to CRS"
transform.
+ * The range of sample values will be [-10 … +10]°C.
+ */
+ final GridGeometry grid = new GridGeometry(new GridExtent(2, 2),
+ PixelInCell.CELL_CENTER, MathTransforms.identity(2),
HardCodedCRS.WGS84);
+
+ final MathTransform1D toUnits = (MathTransform1D)
MathTransforms.linear(0.5, 100);
+ final SampleDimension sd = new SampleDimension.Builder().setName("t")
+ .addQuantitative("data", NumberRange.create(-10, true, 10,
true), toUnits, Units.CELSIUS)
+ .build();
+ /*
+ * Create the grid coverage, make an image and set values directly as
integers.
+ */
+ WritableRaster raster =
WritableRaster.createBandedRaster(DataBuffer.TYPE_INT, 2, 2, 1, new Point(0,0));
+ final ColorSpace colors = ColorModelFactory.createColorSpace(1, 0,
-10, 10);
+ final ColorModel cm = new ComponentColorModel(colors, false, false,
Transparency.OPAQUE, DataBuffer.TYPE_INT);
+ BufferedImage image = new BufferedImage(cm, raster, false, new
Hashtable<>());
+ GridCoverage coverage = new GridCoverage2D(grid, Arrays.asList(sd),
image);
+ raster.setSample(0, 0, 0, 0);
+ raster.setSample(1, 0, 0, 5);
+ raster.setSample(0, 1, 0, -5);
+ raster.setSample(1, 1, 0, -10);
+ /*
+ * Verify packed values.
+ */
+ assertSamplesEqual(coverage, new double[][] {
+ { 0, 5},
+ {-5, -10}
+ });
+ /*
+ * Verify converted values.
+ */
+ coverage = coverage.forConvertedValues(true);
+ assertSamplesEqual(coverage, new double[][] {
+ {100.0, 102.5},
+ { 97.5, 95.0}
+ });
+ /*
+ * Test writing converted values and verify the result in the packed
coverage.
+ * For example for the sample value at (0,0), we have (x is the packed
value):
+ *
+ * 70 = x * 0.5 + 100 → (70-100)/0.5 = x → x = -60
+ */
+ raster = ((BufferedImage) coverage.render(null)).getRaster();
+ raster.setSample(0, 0, 0, 70);
+ raster.setSample(1, 0, 0, 2.5);
+ raster.setSample(0, 1, 0, -8);
+ raster.setSample(1, 1, 0, -90);
+ assertSamplesEqual(coverage.forConvertedValues(false), new double[][] {
+ { -60, -195},
+ {-216, -380}
+ });
+ }
+
+ /**
+ * assert that the sample values in the given coverage are equal to the
expected values.
+ */
+ private static void assertSamplesEqual(final GridCoverage coverage, final
double[][] expected) {
+ final Raster raster = coverage.render(null).getData();
+ for (int y=0; y<expected.length; y++) {
+ for (int x=0; x<expected[y].length; x++) {
+ double value = raster.getSampleDouble(x, y, 0);
+ Assert.assertEquals(expected[y][x], value, STRICT);
+ }
+ }
+ }
+}
diff --git
a/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
b/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
index 12cf52e..9bf8ffa 100644
---
a/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
+++
b/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
@@ -85,7 +85,8 @@ import org.junit.runners.Suite;
org.apache.sis.coverage.SampleDimensionTest.class,
org.apache.sis.coverage.SampleRangeFormatTest.class,
org.apache.sis.internal.coverage.ScaledColorSpaceTest.class,
- org.apache.sis.internal.coverage.BufferedGridCoverageTest.class
+ org.apache.sis.internal.coverage.BufferedGridCoverageTest.class,
+ org.apache.sis.internal.coverage.GridCoverage2DTest.class
})
public final strictfp class FeatureTestSuite extends TestSuite {
/**