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 552126a Coverage : add forConvertedValues method
552126a is described below
commit 552126a91bdb98ed5c255c1ecb69bd20fb2da77e
Author: jsorel <[email protected]>
AuthorDate: Mon Apr 8 11:53:08 2019 +0200
Coverage : add forConvertedValues method
---
.../org/apache/sis/coverage/grid/GridCoverage.java | 14 +
.../internal/coverage/BufferedGridCoverage.java | 97 +++++
.../internal/coverage/ConvertedGridCoverage.java | 427 +++++++++++++++++++++
.../coverage/BufferedGridCoverageTest.java | 95 +++++
.../org/apache/sis/test/suite/RasterTestSuite.java | 3 +-
.../org/apache/sis/internal/netcdf/Raster.java | 7 +
6 files changed, 642 insertions(+), 1 deletion(-)
diff --git
a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridCoverage.java
b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridCoverage.java
index 5a6b2fb..a7ef211 100644
---
a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridCoverage.java
+++
b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridCoverage.java
@@ -125,6 +125,20 @@ public abstract class GridCoverage {
}
/**
+ * Returns a grid coverage that describes real values or sample values,
depending if {@code converted} is {@code true}
+ * or {@code false} respectively. If there are no converted values
defined by sample dimensions, then this method
+ * returns {@code this}.
+ * As a result the {@linkplain RenderedImage} produced by {@linkplain
GridCoverage#render(org.apache.sis.coverage.grid.GridExtent) }
+ * will be changed to contain the real or sample values.
+ *
+ * @param converted {@code true} for a coverage representing converted
values,
+ * or {@code false} for a coverage representing sample
values.
+ * @return a coverage representing converted or sample values, depending
on {@code converted} argument value.
+ * May be {@code this} but never {@code null}.
+ */
+ public abstract GridCoverage forConvertedValues(boolean converted);
+
+ /**
* Returns a two-dimensional slice of grid data as a rendered image. The
given {@code sliceExtent} argument specifies
* the coordinates of the slice in all dimensions that are not in the
two-dimensional image. For example if this grid
* coverage has
<i>(<var>x</var>,<var>y</var>,<var>z</var>,<var>t</var>)</i> dimensions and we
want to render an image
diff --git
a/core/sis-raster/src/main/java/org/apache/sis/internal/coverage/BufferedGridCoverage.java
b/core/sis-raster/src/main/java/org/apache/sis/internal/coverage/BufferedGridCoverage.java
new file mode 100644
index 0000000..fb559ef
--- /dev/null
+++
b/core/sis-raster/src/main/java/org/apache/sis/internal/coverage/BufferedGridCoverage.java
@@ -0,0 +1,97 @@
+/*
+ * 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.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.DataBufferDouble;
+import java.awt.image.DataBufferFloat;
+import java.awt.image.DataBufferInt;
+import java.awt.image.DataBufferShort;
+import java.awt.image.DataBufferUShort;
+import java.awt.image.RasterFormatException;
+import java.awt.image.RenderedImage;
+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.coverage.grid.ImageRenderer;
+import org.opengis.coverage.CannotEvaluateException;
+
+/**
+ * A GridCoverage which datas are stored in an in-memory buffer.
+ *
+ * @author Johann Sorel (Geomatys)
+ */
+public final class BufferedGridCoverage extends GridCoverage {
+
+ private final DataBuffer data;
+ private GridCoverage converted;
+
+ /**
+ * Constructs a grid coverage using the specified grid geometry, sample
dimensions and data type.
+ *
+ * @param grid the grid extent, CRS and conversion from cell indices to
CRS.
+ * @param bands sample dimensions for each image band.
+ * @param dataType One of DataBuffer.TYPE_* , the native data type used to
store the coverage values.
+ */
+ public BufferedGridCoverage(final GridGeometry grid, final Collection<?
extends SampleDimension> bands, int dataType) {
+ super(grid, bands);
+ long nbSamples = bands.size();
+ GridExtent extent = grid.getExtent();
+ for (int i = 0; i<grid.getDimension(); i++) {
+ nbSamples *= extent.getSize(i);
+ }
+ final int nbSamplesi = Math.toIntExact(nbSamples);
+
+ switch (dataType) {
+ case DataBuffer.TYPE_BYTE : this.data = new
DataBufferByte(nbSamplesi); break;
+ case DataBuffer.TYPE_SHORT : this.data = new
DataBufferShort(nbSamplesi); break;
+ case DataBuffer.TYPE_USHORT : this.data = new
DataBufferUShort(nbSamplesi); break;
+ case DataBuffer.TYPE_INT : this.data = new
DataBufferInt(nbSamplesi); break;
+ case DataBuffer.TYPE_FLOAT : this.data = new
DataBufferFloat(nbSamplesi); break;
+ case DataBuffer.TYPE_DOUBLE : this.data = new
DataBufferDouble(nbSamplesi); break;
+ default: throw new IllegalArgumentException("Unsupported data type
"+ dataType);
+ }
+ }
+
+ @Override
+ public RenderedImage render(GridExtent sliceExtent) throws
CannotEvaluateException {
+ try {
+ final ImageRenderer renderer = new ImageRenderer(this,
sliceExtent);
+ renderer.setData(data);
+ return renderer.image();
+ } catch (IllegalArgumentException | ArithmeticException |
RasterFormatException e) {
+ throw new CannotEvaluateException(e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public GridCoverage forConvertedValues(boolean converted) {
+ if (converted) {
+ synchronized (this) {
+ if (this.converted == null) {
+ this.converted = ConvertedGridCoverage.convert(this);
+ }
+ return this.converted;
+ }
+ }
+ return this;
+ }
+
+}
diff --git
a/core/sis-raster/src/main/java/org/apache/sis/internal/coverage/ConvertedGridCoverage.java
b/core/sis-raster/src/main/java/org/apache/sis/internal/coverage/ConvertedGridCoverage.java
new file mode 100644
index 0000000..82e8b95
--- /dev/null
+++
b/core/sis-raster/src/main/java/org/apache/sis/internal/coverage/ConvertedGridCoverage.java
@@ -0,0 +1,427 @@
+/*
+ * 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.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferInt;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.awt.image.SampleModel;
+import java.awt.image.WritableRaster;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.apache.sis.coverage.SampleDimension;
+import org.apache.sis.coverage.grid.GridCoverage;
+import org.apache.sis.coverage.grid.GridExtent;
+import org.apache.sis.measure.NumberRange;
+import org.apache.sis.referencing.operation.transform.MathTransforms;
+import org.opengis.coverage.CannotEvaluateException;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.MathTransform1D;
+import org.opengis.referencing.operation.NoninvertibleTransformException;
+import org.opengis.referencing.operation.TransformException;
+
+/**
+ * Warning : experimental class.
+ *
+ * Decorates a GridCoverage to convert values on the fly.
+ * This class produces a special {@linkplain SampleModel} which may cause
+ * issues in processing operations if the {@linkplain SampleModel} is not
properly used as a fallback.
+ *
+ * @author Johann Sorel (Geomatys)
+ */
+public final class ConvertedGridCoverage extends GridCoverage {
+
+ public static GridCoverage convert(GridCoverage coverage) {
+ final List<SampleDimension> sds = coverage.getSampleDimensions();
+ final List<SampleDimension> cfs = new ArrayList<>(sds.size());
+ for (SampleDimension sd : sds) {
+ cfs.add(sd.forConvertedValues(true));
+ }
+ return new ConvertedGridCoverage(coverage, cfs);
+ }
+
+ private final GridCoverage coverage;
+
+ private ConvertedGridCoverage(GridCoverage base, List<SampleDimension>
sampleDims) {
+ super(base.getGridGeometry(), sampleDims);
+ this.coverage = base;
+ }
+
+ @Override
+ public RenderedImage render(GridExtent sliceExtent) throws
CannotEvaluateException {
+ final BufferedImage render = (BufferedImage)
coverage.render(sliceExtent);
+ final List<SampleDimension> sampleDimensions = getSampleDimensions();
+ final int numBands = sampleDimensions.size();
+ final MathTransform1D[] transforms = new MathTransform1D[numBands];
+ final MathTransform1D[] ivtransforms = new MathTransform1D[numBands];
+ boolean isIdentity = true;
+ for (int i = 0; i < numBands; i++) {
+ MathTransform1D transform =
sampleDimensions.get(i).forConvertedValues(false).getTransferFunction().orElse(null);
+ if (transform == null) transform = (MathTransform1D)
MathTransforms.linear(1.0, 0.0);
+ transforms[i] = transform;
+ try {
+ ivtransforms[i] = transform.inverse();
+ } catch (NoninvertibleTransformException ex) {
+ ivtransforms[i] = (MathTransform1D)
MathTransforms.linear(Double.NaN, 0.0);
+ }
+ isIdentity &= transform.isIdentity();
+ }
+ if (isIdentity) {
+ return render;
+ }
+
+ final WritableRaster raster = render.getRaster();
+ final SampleModel baseSm = raster.getSampleModel();
+ final DataBuffer dataBuffer = raster.getDataBuffer();
+ final ConvertedSampleModel convSm = new ConvertedSampleModel(baseSm,
transforms, ivtransforms);
+
+ //default color models have a lot of constraints
+ final WritableRaster convRaster =
WritableRaster.createWritableRaster(convSm, dataBuffer, new Point(0, 0));
+ final ColorModel cm = new ConvertedColorModel(32,
sampleDimensions.get(0).getSampleRange().get());
+
+ return new BufferedImage(cm, convRaster, false, null);
+ }
+
+ @Override
+ public GridCoverage forConvertedValues(boolean converted) {
+ return converted ? this : coverage;
+ }
+
+ private static final class ConvertedSampleModel extends SampleModel {
+
+ private final SampleModel base;
+ private final int baseDataType;
+ private final MathTransform1D[] bandTransforms;
+ private final MathTransform1D[] bandIvtransforms;
+ private final MathTransform pixelTransform;
+ private final MathTransform pixelIvTransform;
+
+ public ConvertedSampleModel(SampleModel base, MathTransform1D[]
transforms, MathTransform1D[] ivtransforms) {
+ super(DataBuffer.TYPE_FLOAT, base.getWidth(), base.getHeight(),
base.getNumBands());
+ this.base = base;
+ this.baseDataType = base.getDataType();
+ this.bandTransforms = transforms;
+ this.bandIvtransforms = ivtransforms;
+ this.pixelTransform = MathTransforms.compound(bandTransforms);
+ this.pixelIvTransform = MathTransforms.compound(bandIvtransforms);
+ }
+
+ @Override
+ public int getNumDataElements() {
+ return base.getNumDataElements();
+ }
+
+ @Override
+ public Object getDataElements(int x, int y, Object obj, DataBuffer
data) {
+ Object buffer = base.getDataElements(x, y, null, data);
+ float[] pixel;
+ if (obj == null) {
+ pixel = new float[numBands];
+ } else if (!(obj instanceof float[])) {
+ throw new ClassCastException("Unsupported array type,
expecting a float array.");
+ } else {
+ pixel = (float[]) obj;
+ }
+
+ switch (baseDataType) {
+ case DataBuffer.TYPE_BYTE : {
+ final byte[] b = (byte[]) buffer;
+ for (int i = 0; i < b.length; i++) pixel[i] = b[i];
+ } break;
+ case DataBuffer.TYPE_SHORT : {
+ final short[] b = (short[]) buffer;
+ for (int i = 0; i < b.length; i++) pixel[i] = b[i];
+ } break;
+ case DataBuffer.TYPE_USHORT : {
+ final short[] b = (short[]) buffer;
+ for (int i = 0; i < b.length; i++) pixel[i] = b[i] &
0xFFFF;
+ } break;
+ case DataBuffer.TYPE_INT : {
+ final int[] b = (int[]) buffer;
+ for (int i = 0; i < b.length; i++) pixel[i] = b[i];
+ } break;
+ case DataBuffer.TYPE_FLOAT : {
+ final float[] b = (float[]) buffer;
+ for (int i = 0; i < b.length; i++) pixel[i] = b[i];
+ } break;
+ case DataBuffer.TYPE_DOUBLE : {
+ final double[] b = (double[]) buffer;
+ for (int i = 0; i < b.length; i++) pixel[i] = (float) b[i];
+ } break;
+ default: {
+ throw new ClassCastException("Unsupported base array
type.");
+ }
+ }
+
+ try {
+ pixelTransform.transform(pixel, 0, pixel, 0, 1);
+ } catch (TransformException ex) {
+ Arrays.fill(pixel, Float.NaN);
+ }
+ return pixel;
+ }
+
+ @Override
+ public void setDataElements(int x, int y, Object obj, DataBuffer data)
{
+ float[] pixel;
+ if (obj == null) {
+ throw new ClassCastException("Null array values");
+ } else if (!(obj instanceof float[])) {
+ throw new ClassCastException("Unsupported array type,
expecting a float array.");
+ } else {
+ pixel = (float[]) obj;
+ }
+
+ try {
+ pixelIvTransform.transform(pixel, 0, pixel, 0, 1);
+ } catch (TransformException ex) {
+ Arrays.fill(pixel, Float.NaN);
+ }
+
+ switch (baseDataType) {
+ case DataBuffer.TYPE_BYTE : {
+ final byte[] b = new byte[pixel.length];
+ for (int i = 0; i < b.length; i++) b[i] = (byte) pixel[i];
+ base.setDataElements(x, y, b, data);
+ } break;
+ case DataBuffer.TYPE_SHORT : {
+ final short[] b = new short[pixel.length];
+ for (int i = 0; i < b.length; i++) b[i] = (short) pixel[i];
+ base.setDataElements(x, y, b, data);
+ } break;
+ case DataBuffer.TYPE_USHORT : {
+ final short[] b = new short[pixel.length];
+ for (int i = 0; i < b.length; i++) b[i] = (short) pixel[i];
+ base.setDataElements(x, y, b, data);
+ } break;
+ case DataBuffer.TYPE_INT : {
+ final int[] b = new int[pixel.length];
+ for (int i = 0; i < b.length; i++) b[i] = (int) pixel[i];
+ base.setDataElements(x, y, b, data);
+ } break;
+ case DataBuffer.TYPE_FLOAT : {
+ base.setDataElements(x, y, pixel, data);
+ } break;
+ case DataBuffer.TYPE_DOUBLE : {
+ final double[] b = new double[pixel.length];
+ for (int i = 0 ;i < b.length; i++) b[i] = pixel[i];
+ base.setDataElements(x, y, b, data);
+ } break;
+ default: {
+ throw new ClassCastException("Unsupported base array
type.");
+ }
+ }
+ }
+
+ @Override
+ public int getSample(int x, int y, int b, DataBuffer data) {
+ return (int) getSampleDouble(x, y, b, data);
+ }
+
+ @Override
+ public float getSampleFloat(int x, int y, int b, DataBuffer data) {
+ try {
+ return (float)
bandTransforms[b].transform(base.getSampleFloat(x, y, b, data));
+ } catch (TransformException ex) {
+ return Float.NaN;
+ }
+ }
+
+ @Override
+ public double getSampleDouble(int x, int y, int b, DataBuffer data) {
+ try {
+ return bandTransforms[b].transform(base.getSampleDouble(x, y,
b, data));
+ } catch (TransformException ex) {
+ return Double.NaN;
+ }
+ }
+
+ @Override
+ public void setSample(int x, int y, int b, int s, DataBuffer data) {
+ setSample(x,y,b, (double) s, data);
+ }
+
+ @Override
+ public void setSample(int x, int y, int b, double s, DataBuffer data) {
+ try {
+ s = bandIvtransforms[b].transform(s);
+ } catch (TransformException ex) {
+ s = Double.NaN;
+ }
+ base.setSample(x, y, b, s, data);
+ }
+
+ @Override
+ public void setSample(int x, int y, int b, float s, DataBuffer data) {
+ setSample(x, y, b, (double) s, data);
+ }
+
+ @Override
+ public SampleModel createCompatibleSampleModel(int w, int h) {
+ final SampleModel cp = base.createCompatibleSampleModel(w, h);
+ return new ConvertedSampleModel(cp, bandTransforms,
bandIvtransforms);
+ }
+
+ @Override
+ public SampleModel createSubsetSampleModel(int[] bands) {
+ final SampleModel cp = base.createSubsetSampleModel(bands);
+ final MathTransform1D[] trs = new MathTransform1D[bands.length];
+ final MathTransform1D[] ivtrs = new MathTransform1D[bands.length];
+ for (int i=0; i<bands.length;i++) {
+ trs[i] = bandTransforms[bands[i]];
+ ivtrs[i] = bandIvtransforms[bands[i]];
+ }
+ return new ConvertedSampleModel(cp, trs, ivtrs);
+ }
+
+ @Override
+ public DataBuffer createDataBuffer() {
+ return base.createDataBuffer();
+ }
+
+ @Override
+ public int[] getSampleSize() {
+ final int[] sizes = new int[numBands];
+ Arrays.fill(sizes, 32);
+ return sizes;
+ }
+
+ @Override
+ public int getSampleSize(int band) {
+ return 32;
+ }
+
+ }
+
+ private static final class ConvertedColorModel extends ColorModel {
+
+ private final float scale;
+ private final float offset;
+
+ /**
+ * @param nbbits
+ * @param fct : Interpolate or Categorize function
+ */
+ public ConvertedColorModel(final int nbbits, final NumberRange range){
+ super(nbbits);
+ final double scale = (255.0) / (range.getMaxDouble() -
range.getMinDouble());
+ this.scale = (float) scale;
+ this.offset = (float) (range.getMinDouble() / scale);
+ }
+
+ @Override
+ public boolean isCompatibleRaster(Raster raster) {
+ return true;
+ }
+
+ @Override
+ public boolean isCompatibleSampleModel(SampleModel sm) {
+ return true;
+ }
+
+ @Override
+ public int getRGB(Object inData) {
+ float value;
+ // Most used cases. Compatible color model is designed for cases
where indexColorModel cannot do the job (float or int samples).
+ if (inData instanceof float[]) {
+ value = ((float[]) inData)[0];
+ } else if (inData instanceof int[]) {
+ value = ((int[]) inData)[0];
+ } else if (inData instanceof double[]) {
+ value = (float) ((double[]) inData)[0];
+ } else if (inData instanceof byte[]) {
+ value = ((byte[]) inData)[0];
+ } else if (inData instanceof short[]) {
+ value = ((short[]) inData)[0];
+ } else if (inData instanceof long[]) {
+ value = ((long[]) inData)[0];
+ } else if (inData instanceof Number[]) {
+ value = ((Number[]) inData)[0].floatValue();
+ } else if (inData instanceof Byte[]) {
+ value = ((Byte[]) inData)[0];
+ } else {
+ value = 0.0f;
+ }
+
+ int c = (int) ((value - offset) * scale);
+ if (c < 0) c = 0;
+ else if (c > 255) c = 255;
+
+ return (255 << 24) | (c << 16) | (c << 8) | c;
+ }
+
+ @Override
+ public int getRed(int pixel) {
+ final int argb = getRGB((Object) pixel);
+ return 0xFF & (argb >> 16);
+ }
+
+ @Override
+ public int getGreen(int pixel) {
+ final int argb = getRGB((Object) pixel);
+ return 0xFF & ( argb >> 8);
+ }
+
+ @Override
+ public int getBlue(int pixel) {
+ final int argb = getRGB((Object) pixel);
+ return 0xFF & ( argb >> 0);
+ }
+
+ @Override
+ public int getAlpha(int pixel) {
+ final int argb = getRGB((Object) pixel);
+ return 0xFF & ( argb >> 24);
+ }
+
+ @Override
+ public int getRed(Object pixel) {
+ final int argb = getRGB((Object) pixel);
+ return 0xFF & (argb >> 16);
+ }
+
+ @Override
+ public int getGreen(Object pixel) {
+ final int argb = getRGB((Object) pixel);
+ return 0xFF & ( argb >> 8);
+ }
+
+ @Override
+ public int getBlue(Object pixel) {
+ final int argb = getRGB((Object) pixel);
+ return 0xFF & ( argb >> 0);
+ }
+
+ @Override
+ public int getAlpha(Object pixel) {
+ final int argb = getRGB((Object) pixel);
+ return 0xFF & ( argb >> 24);
+ }
+
+ @Override
+ public WritableRaster createCompatibleWritableRaster(int w, int h) {
+ return Raster.createPackedRaster(new
DataBufferInt(w*h),w,h,16,null);
+ }
+
+ }
+
+}
diff --git
a/core/sis-raster/src/test/java/org/apache/sis/internal/coverage/BufferedGridCoverageTest.java
b/core/sis-raster/src/test/java/org/apache/sis/internal/coverage/BufferedGridCoverageTest.java
new file mode 100644
index 0000000..608ca36
--- /dev/null
+++
b/core/sis-raster/src/test/java/org/apache/sis/internal/coverage/BufferedGridCoverageTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.DataBuffer;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.util.Arrays;
+import org.apache.sis.coverage.SampleDimension;
+import org.apache.sis.coverage.grid.GridExtent;
+import org.apache.sis.coverage.grid.GridGeometry;
+import org.apache.sis.internal.referencing.j2d.AffineTransform2D;
+import org.apache.sis.measure.NumberRange;
+import org.apache.sis.measure.Units;
+import org.apache.sis.referencing.CommonCRS;
+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.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.datum.PixelInCell;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.MathTransform1D;
+
+/**
+ * Tests the {@link BufferedGridCoverage} implementation.
+ *
+ * @author Johann Sorel (Geomatys)
+ */
+public class BufferedGridCoverageTest extends TestCase {
+
+ @Test
+ public void testCoverage2D() {
+
+ //create coverage
+ final GridExtent extent = new GridExtent(null, new long[]{0,0}, new
long[]{1,1}, true);
+ final MathTransform gridToCrs = new AffineTransform2D(1, 0, 0, 1, 0,
0);
+ final CoordinateReferenceSystem crs =
CommonCRS.WGS84.normalizedGeographic();
+ final GridGeometry gridgeom = new GridGeometry(extent,
PixelInCell.CELL_CENTER, gridToCrs, crs);
+
+ 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();
+
+ final BufferedGridCoverage coverage = new
BufferedGridCoverage(gridgeom, Arrays.asList(sd), DataBuffer.TYPE_SHORT);
+
+ BufferedImage img = (BufferedImage) coverage.render(null);
+ img.getRaster().setSample(0, 0, 0, 0);
+ img.getRaster().setSample(1, 0, 0, 5);
+ img.getRaster().setSample(0, 1, 0, -5);
+ img.getRaster().setSample(1, 1, 0, -10);
+
+ //test not converted values
+ RenderedImage notConverted = (BufferedImage) coverage.render(null);
+ testSamples(notConverted, new double[][]{{0,5},{-5,-10}});
+
+ //test converted values
+ org.apache.sis.coverage.grid.GridCoverage convertedCoverage =
coverage.forConvertedValues(true);
+ BufferedImage converted = (BufferedImage)
convertedCoverage.render(null);
+ testSamples(converted, new double[][]{{100,102.5},{97.5,95}});
+
+ //test writing in geophysic
+ converted.getRaster().setSample(0, 0, 0, 70); // 70 = x * 0.5 + 100 //
(70-100)/0.5 = x // x = -60
+ converted.getRaster().setSample(1, 0, 0, 2.5);
+ converted.getRaster().setSample(0, 1, 0, -8);
+ converted.getRaster().setSample(1, 1, 0, -90);
+ testSamples(notConverted, new double[][]{{-60,-195},{-216,-380}});
+
+ }
+
+ private void testSamples(RenderedImage image, double[][] values) {
+ final Raster raster = image.getData();
+ for (int y=0;y<values.length;y++) {
+ for (int x=0;x<values[0].length;x++) {
+ double value = raster.getSampleDouble(x, y, 0);
+ Assert.assertEquals(values[y][x], value, 0.0);
+ }
+ }
+ }
+
+}
diff --git
a/core/sis-raster/src/test/java/org/apache/sis/test/suite/RasterTestSuite.java
b/core/sis-raster/src/test/java/org/apache/sis/test/suite/RasterTestSuite.java
index f6ad622..fedcc58 100644
---
a/core/sis-raster/src/test/java/org/apache/sis/test/suite/RasterTestSuite.java
+++
b/core/sis-raster/src/test/java/org/apache/sis/test/suite/RasterTestSuite.java
@@ -39,7 +39,8 @@ import org.junit.BeforeClass;
org.apache.sis.coverage.CategoryTest.class,
org.apache.sis.coverage.CategoryListTest.class,
org.apache.sis.coverage.SampleDimensionTest.class,
- org.apache.sis.internal.raster.ScaledColorSpaceTest.class
+ org.apache.sis.internal.raster.ScaledColorSpaceTest.class,
+ org.apache.sis.internal.coverage.BufferedGridCoverageTest.class
})
public final strictfp class RasterTestSuite extends TestSuite {
/**
diff --git
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Raster.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Raster.java
index 54fc45d..a9f6f2f 100644
---
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Raster.java
+++
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Raster.java
@@ -26,6 +26,7 @@ import org.apache.sis.coverage.grid.GridCoverage;
import org.apache.sis.coverage.grid.GridGeometry;
import org.apache.sis.coverage.grid.GridExtent;
import org.apache.sis.coverage.grid.ImageRenderer;
+import org.apache.sis.internal.coverage.ConvertedGridCoverage;
/**
@@ -95,4 +96,10 @@ final class Raster extends GridCoverage {
throw new
CannotEvaluateException(Resources.format(Resources.Keys.CanNotRender_2, label,
e), e);
}
}
+
+ @Override
+ public GridCoverage forConvertedValues(boolean converted) {
+ return converted ? ConvertedGridCoverage.convert(this) : this;
+ }
+
}