This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit 8ba711cc91f1d09df0e6e7d25837578c82fa0c01
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Fri Nov 24 19:00:26 2023 +0100

    Add a `GridCoverageProcessor.appendDimension(…)` method.
---
 .../sis/coverage/grid/DimensionAppender.java       | 152 +++++++++++++++++++++
 .../sis/coverage/grid/GridCoverageProcessor.java   |  28 +++-
 .../org/apache/sis/feature/internal/Resources.java |   5 +
 .../sis/feature/internal/Resources.properties      |   1 +
 .../sis/feature/internal/Resources_fr.properties   |   1 +
 5 files changed, 186 insertions(+), 1 deletion(-)

diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/DimensionAppender.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/DimensionAppender.java
new file mode 100644
index 0000000000..4deb4f4a1c
--- /dev/null
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/DimensionAppender.java
@@ -0,0 +1,152 @@
+/*
+ * 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.coverage.grid;
+
+import java.awt.image.RenderedImage;
+import org.opengis.util.FactoryException;
+import org.apache.sis.image.DataType;
+import org.apache.sis.util.ArraysExt;
+import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.Workaround;
+import org.apache.sis.util.internal.Numerics;
+import org.apache.sis.feature.internal.Resources;
+import org.apache.sis.coverage.SubspaceNotSpecifiedException;
+
+// Specific to the geoapi-3.1 and geoapi-4.0 branches:
+import org.opengis.coverage.CannotEvaluateException;
+
+
+/**
+ * A grid coverage with extra dimensions appended.
+ * All extra dimensions have a grid size of one cell.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ */
+final class DimensionAppender extends GridCoverage {
+    /**
+     * The source grid coverage for which to append extra dimensions.
+     */
+    private final GridCoverage source;
+
+    /**
+     * The dimensions added to the source grid coverage.
+     * Should have a grid size of one cell in all dimensions.
+     */
+    private final GridGeometry dimToAdd;
+
+    /**
+     * Creates a new dimension appender for the given grid coverage.
+     * The grid extent of {@code dimToAdd} shall have a grid size of one cell 
in all dimensions.
+     *
+     * @param  source    the source grid coverage for which to append extra 
dimensions.
+     * @param  dimToAdd  the dimensions to add to the source grid coverage.
+     * @throws FactoryException if the compound CRS cannot be created.
+     * @throws IllegalGridGeometryException if a dimension has more than one 
grid cell.
+     * @throws IllegalArgumentException if the concatenation results in 
duplicated
+     *         {@linkplain GridExtent#getAxisType(int) grid axis types}.
+     */
+    private DimensionAppender(final GridCoverage source, final GridGeometry 
dimToAdd) throws FactoryException {
+        super(source, new GridGeometry(source.getGridGeometry(), dimToAdd));
+        this.source   = source;
+        this.dimToAdd = dimToAdd;
+        final GridExtent extent = dimToAdd.getExtent();
+        for (int i = extent.getDimension(); --i >= 0;) {
+            final long size = extent.getSize(i);
+            if (size != 1) {
+                throw new 
IllegalGridGeometryException(Resources.format(Resources.Keys.NotASlice_2,
+                        extent.getAxisIdentification(i,i), size));
+            }
+        }
+    }
+
+    /**
+     * Work around for RFE #4093999 in Sun's bug database
+     * ("Relax constraint on placement of this()/super() call in 
constructors").
+     */
+    @Workaround(library="JDK", version="1.7")
+    static DimensionAppender create(GridCoverage source, GridGeometry 
dimToAdd) throws FactoryException {
+        if (source instanceof DimensionAppender) {
+            final var a = (DimensionAppender) source;
+            dimToAdd = new GridGeometry(a.dimToAdd, dimToAdd);
+            source = a.source;
+        }
+        return new DimensionAppender(source, dimToAdd);
+    }
+
+    /**
+     * Returns the data type identifying the primitive type used for storing 
sample values in each band.
+     */
+    @Override
+    final DataType getBandType() {
+        return source.getBandType();
+    }
+
+    /**
+     * Creates the grid coverage instance for the converted or packed values.
+     * This method is invoked only when first needed, and the result is cached 
by the caller.
+     */
+    @Override
+    protected GridCoverage createConvertedValues(final boolean converted) {
+        try {
+            return new DimensionAppender(source.forConvertedValues(converted), 
dimToAdd);
+        } catch (FactoryException e) {
+            throw new CannotEvaluateException(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * Creates a new function for computing or interpolating sample values at 
given locations.
+     * This implementation returns the evaluator of the source coverage on the 
assumption that
+     * it should be able to do dimensionality reduction of the coordinates 
given to it.
+     */
+    @Override
+    public Evaluator evaluator() {
+        return source.evaluator();
+    }
+
+    /**
+     * Returns a two-dimensional slice of grid data as a rendered image.
+     *
+     * @param  sliceExtent  a subspace of this grid coverage where all 
dimensions except two have a size of 1 cell.
+     *         May be {@code null} if this grid coverage has only two 
dimensions with a size greater than 1 cell.
+     * @return the grid slice as a rendered image. Image location is relative 
to {@code sliceExtent}.
+     */
+    @Override
+    public RenderedImage render(GridExtent sliceExtent) {
+        if (sliceExtent != null) {
+            final int sourceDim = source.getGridGeometry().getDimension();
+            final int dimension = dimToAdd.getDimension() + sourceDim;
+            ArgumentChecks.ensureDimensionMatches("sliceExtent", dimension, 
sliceExtent);
+            for (int i=sourceDim; i<dimension; i++) {
+                final long size = sliceExtent.getSize(i);
+                if (size != 1) {
+                    throw new 
SubspaceNotSpecifiedException(Resources.format(Resources.Keys.NoNDimensionalSlice_3,
+                                sourceDim, 
sliceExtent.getAxisIdentification(i,i), Numerics.toUnsignedDouble(size)));
+                }
+                if (dimToAdd.extent != null) {
+                    final long actual = sliceExtent.getLow(i);
+                    final long expected = dimToAdd.extent.getLow(i - 
sourceDim);
+                    if (actual != expected) {
+                        throw new 
DisjointExtentException(sliceExtent.getAxisIdentification(i,i), expected, 
expected, actual, actual);
+                    }
+                }
+            }
+            sliceExtent = sliceExtent.selectDimensions(ArraysExt.range(0, 
sourceDim));
+        }
+        return source.render(sliceExtent);
+    }
+}
diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridCoverageProcessor.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridCoverageProcessor.java
index 1fe3f23034..d61f6a4b18 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridCoverageProcessor.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridCoverageProcessor.java
@@ -591,7 +591,7 @@ public class GridCoverageProcessor implements Cloneable {
                 throw e;
             }
         } catch (FactoryException e) {
-            throw new TransformException(e);
+            throw new TransformException(e.getMessage(), e);
         }
         return resampled.forConvertedValues(isConverted);
     }
@@ -619,6 +619,32 @@ public class GridCoverageProcessor implements Cloneable {
         return resample(source, new GridGeometry(null, 
PixelInCell.CELL_CENTER, null, target));
     }
 
+    /**
+     * Appends the specified grid dimensions after the dimensions of the given 
source coverage.
+     * This method is typically invoked for adding a vertical or temporal axis 
to a two-dimensional coverage.
+     * The grid extent must have a size of one cell in all the specified 
additional dimensions.
+     *
+     * @param  source    the source on which to append dimensions.
+     * @param  dimToAdd  the dimensions to append. The grid extent size must 
be 1 cell in all dimensions.
+     * @return a coverage with the specified dimensions added.
+     * @throws IllegalGridGeometryException if a dimension has more than one 
grid cell, or concatenation
+     *         would result in duplicated {@linkplain 
GridExtent#getAxisType(int) grid axis types},
+     *         or the compound CRS cannot be created.
+     *
+     * @since 1.5
+     */
+    public GridCoverage appendDimensions(final GridCoverage source, final 
GridGeometry dimToAdd) {
+        ArgumentChecks.ensureNonNull("source",   source);
+        ArgumentChecks.ensureNonNull("dimToAdd", dimToAdd);
+        try {
+            return DimensionAppender.create(source, dimToAdd);
+        } catch (IllegalGridGeometryException e) {
+            throw e;
+        } catch (FactoryException | IllegalArgumentException e) {
+            throw new IllegalGridGeometryException(e.getMessage(), e);
+        }
+    }
+
     /**
      * Automatically reduces a grid coverage dimensionality by removing all 
grid axes with an extent size of 1.
      * Axes in the reduced grid coverage will be in the same order than in the 
source coverage.
diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/internal/Resources.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/internal/Resources.java
index 769fa14109..7d934b4d39 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/internal/Resources.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/internal/Resources.java
@@ -368,6 +368,11 @@ public class Resources extends IndexedResourceBundle {
          */
         public static final short NotASingleton_1 = 53;
 
+        /**
+         * Not a slice. Dimension “{0}” has {1} cells.
+         */
+        public static final short NotASlice_2 = 90;
+
         /**
          * The specified dimensions are not in strictly ascending order.
          */
diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/internal/Resources.properties
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/internal/Resources.properties
index 6f1591f2f9..897c5809d8 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/internal/Resources.properties
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/internal/Resources.properties
@@ -80,6 +80,7 @@ NonLinearInDimensions_1           = non-linear in {0} 
dimension{0,choice,1#|2#s}
 NonSeparableReducedDimensions     = The dimensions to reduce cannot be 
separated.
 NotAGeometryAtFirstExpression     = Value provided by first expression is not 
a geometry.
 NotASingleton_1                   = Property \u201c{0}\u201d contains more 
than one value.
+NotASlice_2                       = Not a slice. Dimension \u201c{0}\u201d has 
{1} cells.
 NotStrictlyOrderedDimensions      = The specified dimensions are not in 
strictly ascending order.
 OperationRequiresSingleBand       = This operation requires an image with only 
one band.
 OptionalLibraryNotFound_2         = The {0} optional library is not available. 
Geometric operations will ignore that library.\nCause is {1}.
diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/internal/Resources_fr.properties
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/internal/Resources_fr.properties
index cdfb25398e..3d685e17ac 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/internal/Resources_fr.properties
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/internal/Resources_fr.properties
@@ -85,6 +85,7 @@ NonLinearInDimensions_1           = non-lin\u00e9aire dans 
{0} dimension{0,choic
 NonSeparableReducedDimensions     = Les dimensions \u00e0 r\u00e9duire ne 
peuvent pas \u00eatre s\u00e9par\u00e9es.
 NotAGeometryAtFirstExpression     = La valeur fournie par la premi\u00e8re 
expression n\u2019est pas une g\u00e9om\u00e9trie.
 NotASingleton_1                   = La propri\u00e9t\u00e9 
\u00ab\u202f{0}\u202f\u00bb contient plus de une valeur.
+NotASlice_2                       = Ce n\u2019est pas une tranche. La 
dimension \u00ab\u202f{0}\u202f\u00bb a {1} cellules.
 NotStrictlyOrderedDimensions      = Les dimensions sp\u00e9cifi\u00e9es ne 
sont pas en ordre strictement croissant.
 OperationRequiresSingleBand       = Cette op\u00e9ration n\u00e9cessite une 
image avec une seule bande.
 OptionalLibraryNotFound_2         = La biblioth\u00e8que optionnelle {0} 
n\u2019est pas disponible. Les op\u00e9rations g\u00e9om\u00e9triques 
ignoreront cette biblioth\u00e8que.\nLa cause est {1}.

Reply via email to