sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jso...@apache.org
Subject [sis] branch geoapi-4.0 updated: Coverage : add forConvertedValues method
Date Mon, 08 Apr 2019 09:56:10 GMT
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 <johann.sorel@geomatys.com>
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;
+    }
+
 }


Mime
View raw message