You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2023/11/24 18:06:16 UTC

(sis) branch geoapi-4.0 updated (57c14cd312 -> 8ba711cc91)

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

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


    from 57c14cd312 fix(Shapefile): fix combining multiple subset
     new e0588cac36 Minor cleaning (documentation, removal of a deprecated method).
     new c25766bdff Move `getEnvelope()` default implementation from `AbstractGridCoverageResource` class to `GridCoverageResource` interface.
     new ca8241da59 Add a `GridGeometry` constructor doing the concatenation of two grid geometries. Opportunistic migration of JUnit 4 to JUnit 5 for the relevant tests.
     new 8ba711cc91 Add a `GridCoverageProcessor.appendDimension(…)` method.

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../sis/coverage/grid/DimensionAppender.java       | 152 +++++++++++++++++++++
 .../sis/coverage/grid/GridCoverageProcessor.java   |  28 +++-
 .../org/apache/sis/coverage/grid/GridExtent.java   |  29 +++-
 .../org/apache/sis/coverage/grid/GridGeometry.java |  63 ++++++++-
 .../org/apache/sis/feature/internal/Resources.java |   5 +
 .../sis/feature/internal/Resources.properties      |   1 +
 .../sis/feature/internal/Resources_fr.properties   |   1 +
 .../org/apache/sis/filter/ComparisonFilter.java    |   2 +-
 .../apache/sis/coverage/grid/GridExtentTest.java   | 113 ++++++++-------
 .../apache/sis/coverage/grid/GridGeometryTest.java | 140 ++++++++++++-------
 .../factory/CommonAuthorityFactory.java            |   4 +-
 .../sis/storage/AbstractGridCoverageResource.java  |  21 +--
 .../apache/sis/storage/GridCoverageResource.java   |  23 +++-
 .../sis/storage/aggregate/CoverageAggregator.java  |  13 +-
 .../apache/sis/storage/aggregate/package-info.java |   2 +-
 .../org/apache/sis/storage/esri/RasterStore.java   |  14 --
 .../main/org/apache/sis/util/ArraysExt.java        |  20 ++-
 17 files changed, 476 insertions(+), 155 deletions(-)
 create mode 100644 endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/DimensionAppender.java


(sis) 03/04: Add a `GridGeometry` constructor doing the concatenation of two grid geometries. Opportunistic migration of JUnit 4 to JUnit 5 for the relevant tests.

Posted by de...@apache.org.
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 ca8241da59f6885fc6d5446ee9589890c2d3cebb
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Fri Nov 24 16:28:54 2023 +0100

    Add a `GridGeometry` constructor doing the concatenation of two grid geometries.
    Opportunistic migration of JUnit 4 to JUnit 5 for the relevant tests.
---
 .../org/apache/sis/coverage/grid/GridExtent.java   |  29 ++++-
 .../org/apache/sis/coverage/grid/GridGeometry.java |  63 +++++++++-
 .../apache/sis/coverage/grid/GridExtentTest.java   | 113 +++++++++--------
 .../apache/sis/coverage/grid/GridGeometryTest.java | 140 +++++++++++++--------
 .../main/org/apache/sis/util/ArraysExt.java        |  20 ++-
 5 files changed, 260 insertions(+), 105 deletions(-)

diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridExtent.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridExtent.java
index 352247f403..62d68bb38b 100644
--- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridExtent.java
+++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridExtent.java
@@ -91,7 +91,7 @@ import org.opengis.coverage.grid.GridCoordinates;
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @author  Alexis Manin (Geomatys)
  * @author  Johann Sorel (Geomatys)
- * @version 1.4
+ * @version 1.5
  * @since   1.0
  */
 public class GridExtent implements GridEnvelope, LenientComparable, Serializable {
@@ -354,6 +354,33 @@ public class GridExtent implements GridEnvelope, LenientComparable, Serializable
         validateCoordinates();
     }
 
+    /**
+     * Creates a new grid extent as the concatenation of the two specified grid extent.
+     * The number of dimensions of the new extent is the sum of the number of dimensions
+     * of the two specified extents. The dimensions of the lower extent are first,
+     * followed by the dimensions of the upper extent.
+     *
+     * @param  lower  the grid extent providing the lowest dimensions.
+     * @param  upper  the grid extent providing the highest dimensions.
+     * @throws IllegalArgumentException if the concatenation results in duplicated {@linkplain #getAxisType(int) axis types}.
+     *
+     * @since 1.5
+     */
+    public GridExtent(final GridExtent lower, final GridExtent upper) {
+        final int d1  = lower.getDimension();
+        final int d2  = upper.getDimension();
+        final int dim = d1 + d2;
+        final var axisTypes = new DimensionNameType[dim];
+        if (lower.types != null) System.arraycopy(lower.types, 0, axisTypes,  0, d1);
+        if (upper.types != null) System.arraycopy(upper.types, 0, axisTypes, d1, d2);
+        types = validateAxisTypes(axisTypes);
+        coordinates = allocate(dim);
+        System.arraycopy(lower.coordinates,  0, coordinates,      0, d1);
+        System.arraycopy(upper.coordinates,  0, coordinates,     d1, d2);
+        System.arraycopy(lower.coordinates, d1, coordinates, dim,    d1);
+        System.arraycopy(upper.coordinates, d2, coordinates, dim+d1, d2);
+    }
+
     /**
      * Infers the axis types from the given coordinate reference system.
      * This method is the converse of {@link GridExtentCRS}.
diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridGeometry.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridGeometry.java
index 3389b1a534..464b9644bd 100644
--- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridGeometry.java
+++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridGeometry.java
@@ -747,6 +747,66 @@ public class GridGeometry implements LenientComparable, Serializable {
         }
     }
 
+    /**
+     * Creates a new grid geometry as the concatenation of the two specified grid geometries.
+     * The number of dimensions of the new grid geometry is the sum of the number of dimensions
+     * of the two specified grid geometries. The dimensions of the lower grid geometry are first,
+     * followed by the dimensions of the upper grid geometry.
+     *
+     * @param  lower  the grid geometry providing the lowest dimensions.
+     * @param  upper  the grid geometry providing the highest dimensions.
+     * @throws IncompleteGridGeometryException if a property presents in one grid geometry is absent in the other.
+     * @throws IllegalArgumentException if the concatenation results in duplicated
+     *         {@linkplain GridExtent#getAxisType(int) grid axis types}.
+     * @throws FactoryException if the geodetic factory failed to create the compound CRS.
+     *
+     * @see #selectDimensions(int...)
+     *
+     * @since 1.5
+     */
+    public GridGeometry(final GridGeometry lower, final GridGeometry upper) throws FactoryException {
+        /*
+         * Concatenate the extents first because they perform a check for axis duplication.
+         * We set the extent to null only if both `lower` and `upper` have a null extent.
+         * Otherwise, invoke `getExtent()` for causing an `IncompleteGridGeometryException`
+         * to be thrown if only one grid geometry has an extent.
+         */
+        extent = (lower.extent == null && upper.extent == null) ? null
+               : new GridExtent(lower.getExtent(), upper.getExtent());
+        /*
+         * Concatenate the "grid to CRS" transforms and derived information
+         * (resolutions and non-linearity).
+         */
+        if (lower.gridToCRS == null && upper.gridToCRS == null) {
+            gridToCRS   = null;
+            cornerToCRS = null;
+        } else {
+            gridToCRS   = compound(lower, upper, PixelInCell.CELL_CENTER);
+            cornerToCRS = compound(lower, upper, PixelInCell.CELL_CORNER);
+        }
+        nonLinears = lower.nonLinears | (upper.nonLinears << lower.getDimension());
+        resolution = (lower.resolution == null && upper.resolution == null) ? null
+                   : ArraysExt.concatenate(lower.getResolution(true), upper.getResolution(true));
+        /*
+         * The check for presence/absence of envelope is more complex because an envelope
+         * may be considered missing, but still be non-null in order to store the CRS.
+         */
+        if (lower.envelope == null && upper.envelope == null) {
+            envelope = null;
+        } else {
+            Envelope e1 = lower.envelope; if (e1 == null) e1 = lower.getEnvelope();
+            Envelope e2 = upper.envelope; if (e2 == null) e2 = upper.getEnvelope();
+            envelope = ImmutableEnvelope.castOrCopy(Envelopes.compound(e1, e2));
+        }
+    }
+
+    /**
+     * Aggregates the dimensions of the "grid to CRS" transforms of the given grid geometries.
+     */
+    private static MathTransform compound(final GridGeometry lower, final GridGeometry upper, final PixelInCell anchor) {
+        return MathTransforms.compound(lower.getGridToCRS(anchor), upper.getGridToCRS(anchor));
+    }
+
     /**
      * Converts a "grid to CRS" transform from "cell corner" convention to "cell center" convention.
      * This is a helper method for use of {@link #GridGeometry(GridExtent, MathTransform, MathTransform,
@@ -1542,7 +1602,8 @@ public class GridGeometry implements LenientComparable, Serializable {
      * The number of dimensions of the sub grid geometry will be {@code dimensions.length}.
      *
      * <p>This method performs a <cite>dimensionality reduction</cite>.
-     * This method cannot be used for changing dimension order.</p>
+     * This method cannot be used for changing dimension order.
+     * The converse operation is the {@linkplain #GridGeometry(GridGeometry, GridGeometry) concatenation}.</p>
      *
      * @param  indices  the grid (not CRS) dimensions to select, in strictly increasing order.
      * @return the sub-grid geometry, or {@code this} if the given array contains all dimensions of this grid geometry.
diff --git a/endorsed/src/org.apache.sis.feature/test/org/apache/sis/coverage/grid/GridExtentTest.java b/endorsed/src/org.apache.sis.feature/test/org/apache/sis/coverage/grid/GridExtentTest.java
index b9f3646dae..c9afd55f9b 100644
--- a/endorsed/src/org.apache.sis.feature/test/org/apache/sis/coverage/grid/GridExtentTest.java
+++ b/endorsed/src/org.apache.sis.feature/test/org/apache/sis/coverage/grid/GridExtentTest.java
@@ -37,7 +37,8 @@ import org.apache.sis.util.internal.Numerics;
 
 // Test dependencies
 import org.junit.Test;
-import static org.junit.Assert.*;
+import org.junit.jupiter.api.DisplayName;
+import static org.junit.jupiter.api.Assertions.*;
 import org.apache.sis.test.TestCase;
 import org.apache.sis.referencing.crs.HardCodedCRS;
 import static org.apache.sis.test.Assertions.assertMapEquals;
@@ -77,10 +78,10 @@ public final class GridExtentTest extends TestCase {
      * Verifies the low and high values in the specified dimension of the given extent
      */
     static void assertExtentEquals(final GridExtent extent, final int dimension, final int low, final int high) {
-        assertEquals("low",    low,  extent.getLow (dimension));
-        assertEquals("high",   high, extent.getHigh(dimension));
-        assertEquals("size",   high - low + 1, extent.getSize(dimension));
-        assertEquals("median", Numerics.ceilDiv(high + low, 2), extent.getMedian(dimension));
+        assertEquals(low,  extent.getLow (dimension), "low");
+        assertEquals(high, extent.getHigh(dimension), "high");
+        assertEquals(high - low + 1, extent.getSize(dimension), "size");
+        assertEquals(Numerics.ceilDiv(high + low, 2), extent.getMedian(dimension), "median");
     }
 
     /**
@@ -185,7 +186,7 @@ public final class GridExtentTest extends TestCase {
         GridExtent extent = new GridExtent(new DimensionNameType[] {DimensionNameType.COLUMN, DimensionNameType.ROW},
                                            new long[] {100, 200}, new long[] {500, 800}, true);
         extent = extent.insertDimension(offset, DimensionNameType.TIME, 40, 50, false);
-        assertEquals("dimension", 3, extent.getDimension());
+        assertEquals(3, extent.getDimension(), "dimension");
         assertExtentEquals(extent, 0,        100, 500);
         assertExtentEquals(extent, rowIndex, 200, 800);
         assertExtentEquals(extent, offset,    40,  49);
@@ -201,14 +202,14 @@ public final class GridExtentTest extends TestCase {
     public void testSelectDimensions() {
         final GridExtent extent = create3D();
         GridExtent reduced = extent.selectDimensions(0, 1);
-        assertEquals("dimension", 2, reduced.getDimension());
+        assertEquals(2, reduced.getDimension(), "dimension");
         assertExtentEquals(reduced, 0, 100, 499);
         assertExtentEquals(reduced, 1, 200, 799);
         assertEquals(DimensionNameType.COLUMN, reduced.getAxisType(0).get());
         assertEquals(DimensionNameType.ROW,    reduced.getAxisType(1).get());
 
         reduced = extent.selectDimensions(2);
-        assertEquals("dimension", 1, reduced.getDimension());
+        assertEquals(1, reduced.getDimension(), "dimension");
         assertExtentEquals(reduced, 0, 40, 49);
         assertEquals(DimensionNameType.TIME, reduced.getAxisType(0).get());
     }
@@ -294,12 +295,8 @@ public final class GridExtentTest extends TestCase {
         assertExtentEquals(extent, 2, 40,  46);
         assertSame(extent.intersect(domain), extent);
         final GridExtent disjoint = domain.translate(0, 1000);
-        try {
-            extent.intersect(disjoint);
-            fail("Expected DisjointExtentException.");
-        } catch (DisjointExtentException e) {
-            assertNotNull(e.getMessage());
-        }
+        String message = assertThrows(DisjointExtentException.class, () -> extent.intersect(disjoint)).getMessage();
+        assertNotNull(message);
     }
 
     /**
@@ -325,12 +322,30 @@ public final class GridExtentTest extends TestCase {
         final GridExtent other = new GridExtent(
                 new DimensionNameType[] {DimensionNameType.COLUMN, DimensionNameType.TRACK, DimensionNameType.TIME},
                 new long[] {100, 200, 40}, new long[] {500, 800, 50}, false);
-        try {
-            domain.intersect(other);
-            fail("Should not be allowed");
-        } catch (IllegalArgumentException e) {
-            assertNotNull(e.getMessage());
-        }
+
+        String message = assertThrows(IllegalArgumentException.class, () -> domain.intersect(other)).getMessage();
+        assertNotNull(message);
+    }
+
+    /**
+     * Tests {@link GridExtent#GridExtent(GridExtent, GridExtent)}.
+     */
+    @Test
+    public void testConcatenate() {
+        final GridExtent domain = create3D();
+        final GridExtent other = new GridExtent(
+                new DimensionNameType[] {DimensionNameType.VERTICAL},
+                new long[] {-4}, new long[] {17}, true);
+        final GridExtent extent = new GridExtent(domain, other);
+
+        assertArrayEquals(new DimensionNameType[] {
+            DimensionNameType.COLUMN, DimensionNameType.ROW, DimensionNameType.TIME, DimensionNameType.VERTICAL
+        }, extent.getAxisTypes());
+
+        assertArrayEquals(new long[] {
+            100, 200, 40, -4,
+            499, 799, 49, 17
+        }, extent.getCoordinates());
     }
 
     /**
@@ -341,7 +356,7 @@ public final class GridExtentTest extends TestCase {
         final GeneralDirectPosition slicePoint = new GeneralDirectPosition(226.7, 47.2);
         final GridExtent extent = create3D();
         final GridExtent slice  = extent.slice(slicePoint, new int[] {1, 2});
-        assertEquals("dimension", 3, slice.getDimension());
+        assertEquals(3, slice.getDimension(), "dimension");
         assertExtentEquals(slice, 0, 100, 499);
         assertExtentEquals(slice, 1, 227, 227);
         assertExtentEquals(slice, 2,  47,  47);
@@ -352,13 +367,8 @@ public final class GridExtentTest extends TestCase {
          * change in future SIS version).
          */
         slicePoint.setOrdinate(0, 900);
-        try {
-            extent.slice(slicePoint, new int[] {1, 2});
-            fail("Expected PointOutsideCoverageException");
-        } catch (PointOutsideCoverageException e) {
-            final String message = e.getLocalizedMessage();
-            assertTrue(message, message.contains("(900, 47)"));     // See above comment.
-        }
+        String message = assertThrows(PointOutsideCoverageException.class, () -> extent.slice(slicePoint, new int[] {1, 2})).getLocalizedMessage();
+        assertTrue(message.contains("(900, 47)"), message);         // See above comment.
     }
 
     /**
@@ -372,12 +382,8 @@ public final class GridExtentTest extends TestCase {
         assertSubspaceEquals(extent, 0,  2  );
         assertSubspaceEquals(extent, 0,1,2  );
         assertSubspaceEquals(extent, 0,1,2,3);
-        try {
-            extent.getSubspaceDimensions(1);
-            fail("Should not reduce to 1 dimension.");
-        } catch (SubspaceNotSpecifiedException e) {
-            assertNotNull(e.getMessage());
-        }
+        String message = assertThrows(SubspaceNotSpecifiedException.class, () -> extent.getSubspaceDimensions(1)).getMessage();
+        assertNotNull(message);
     }
 
     /**
@@ -508,11 +514,12 @@ public final class GridExtentTest extends TestCase {
      * Verifies that a translation of zero cell results in the same {@link GridExtent} instance.
      */
     @Test
-    public void empty_translation_returns_same_extent_instance() {
+    @DisplayName("Empty translation returns same extent instance")
+    public void testZeroTranslation() {
         final GridExtent extent = new GridExtent(10, 10);
-        assertSame("Same instance returned in case of no-op", extent, extent.translate());
-        assertSame("Same instance returned in case of no-op", extent, extent.translate(0));
-        assertSame("Same instance returned in case of no-op", extent, extent.translate(0, 0));
+        assertSame(extent, extent.translate());
+        assertSame(extent, extent.translate(0));
+        assertSame(extent, extent.translate(0, 0));
     }
 
     /**
@@ -520,26 +527,27 @@ public final class GridExtentTest extends TestCase {
      * than the extent number of dimensions. No translation shall be applied in missing dimensions.
      */
     @Test
-    public void translating_only_first_dimensions_leave_others_untouched() {
+    @DisplayName("Translating only first dimensions leave others untouched")
+    public void testTranslateOneDimension() {
         final GridExtent base = new GridExtent(null, new long[] {
             0, 0, 0,
             2, 2, 2
         });
         final GridExtent translatedByX = base.translate(1);
-        assertArrayEquals("Lower corner", new long[] {1, 0, 0}, translatedByX.getLow() .getCoordinateValues());
-        assertArrayEquals("Upper corner", new long[] {3, 2, 2}, translatedByX.getHigh().getCoordinateValues());
+        assertArrayEquals(new long[] {1, 0, 0}, translatedByX.getLow() .getCoordinateValues(), "Lower corner");
+        assertArrayEquals(new long[] {3, 2, 2}, translatedByX.getHigh().getCoordinateValues(), "Upper corner");
 
         final GridExtent translatedByY = base.translate(0, -1);
-        assertArrayEquals("Lower corner", new long[] {0, -1, 0}, translatedByY.getLow() .getCoordinateValues());
-        assertArrayEquals("Upper corner", new long[] {2,  1, 2}, translatedByY.getHigh().getCoordinateValues());
+        assertArrayEquals(new long[] {0, -1, 0}, translatedByY.getLow() .getCoordinateValues(), "Lower corner");
+        assertArrayEquals(new long[] {2,  1, 2}, translatedByY.getHigh().getCoordinateValues(), "Upper corner");
 
         final GridExtent translatedByXAndY = base.translate(-1, 4);
-        assertArrayEquals("Lower corner", new long[] {-1, 4, 0}, translatedByXAndY.getLow() .getCoordinateValues());
-        assertArrayEquals("Upper corner", new long[] { 1, 6, 2}, translatedByXAndY.getHigh().getCoordinateValues());
+        assertArrayEquals(new long[] {-1, 4, 0}, translatedByXAndY.getLow() .getCoordinateValues(), "Lower corner");
+        assertArrayEquals(new long[] { 1, 6, 2}, translatedByXAndY.getHigh().getCoordinateValues(), "Upper corner");
 
         // Paranoiac check: ensure that base extent has been left untouched.
-        assertArrayEquals("Base lower corner", new long[] {0, 0, 0}, base.getLow() .getCoordinateValues());
-        assertArrayEquals("Base lower corner", new long[] {2, 2, 2}, base.getHigh().getCoordinateValues());
+        assertArrayEquals(new long[] {0, 0, 0}, base.getLow() .getCoordinateValues(), "Base lower corner");
+        assertArrayEquals(new long[] {2, 2, 2}, base.getHigh().getCoordinateValues(), "Base lower corner");
     }
 
     /**
@@ -547,17 +555,18 @@ public final class GridExtentTest extends TestCase {
      * when the given vector is long enough.
      */
     @Test
-    public void translating_all_dimensions() {
+    @DisplayName("Translating all dimensions")
+    public void testTranslateAllDimensions() {
         final GridExtent base = new GridExtent(null, new long[] {
             -1, -1, -2, 10,
              2,  2,  2, 20
         });
         final GridExtent translated = base.translate(-2, 1, 1, 100);
-        assertArrayEquals("Lower corner", new long[] {-3, 0, -1, 110}, translated.getLow() .getCoordinateValues());
-        assertArrayEquals("Upper corner", new long[] { 0, 3,  3, 120}, translated.getHigh().getCoordinateValues());
+        assertArrayEquals(new long[] {-3, 0, -1, 110}, translated.getLow() .getCoordinateValues(), "Lower corner");
+        assertArrayEquals(new long[] { 0, 3,  3, 120}, translated.getHigh().getCoordinateValues(), "Upper corner");
 
         // Paranoiac check: ensure that base extent has been left untouched.
-        assertArrayEquals("Base lower corner", new long[] {-1, -1, -2, 10}, base.getLow() .getCoordinateValues());
-        assertArrayEquals("Base lower corner", new long[] { 2,  2,  2, 20}, base.getHigh().getCoordinateValues());
+        assertArrayEquals(new long[] {-1, -1, -2, 10}, base.getLow() .getCoordinateValues(), "Base lower corner");
+        assertArrayEquals(new long[] { 2,  2,  2, 20}, base.getHigh().getCoordinateValues(), "Base lower corner");
     }
 }
diff --git a/endorsed/src/org.apache.sis.feature/test/org/apache/sis/coverage/grid/GridGeometryTest.java b/endorsed/src/org.apache.sis.feature/test/org/apache/sis/coverage/grid/GridGeometryTest.java
index e0823cdc82..5c2d342226 100644
--- a/endorsed/src/org.apache.sis.feature/test/org/apache/sis/coverage/grid/GridGeometryTest.java
+++ b/endorsed/src/org.apache.sis.feature/test/org/apache/sis/coverage/grid/GridGeometryTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.coverage.grid;
 
+import org.opengis.util.FactoryException;
 import org.opengis.geometry.Envelope;
 import org.opengis.metadata.spatial.DimensionNameType;
 import org.opengis.referencing.crs.DerivedCRS;
@@ -32,10 +33,11 @@ import org.apache.sis.referencing.operation.matrix.Matrices;
 import org.apache.sis.referencing.operation.matrix.MatrixSIS;
 import org.apache.sis.referencing.operation.transform.MathTransforms;
 import org.apache.sis.referencing.util.ExtendedPrecisionMatrix;
+import org.apache.sis.util.ComparisonMode;
 
 // Test dependencies
 import org.junit.Test;
-import static org.junit.Assert.*;
+import static org.junit.jupiter.api.Assertions.*;
 import org.apache.sis.test.TestCase;
 import org.apache.sis.test.DependsOn;
 import org.apache.sis.referencing.crs.HardCodedCRS;
@@ -64,8 +66,8 @@ public final class GridGeometryTest extends TestCase {
      * Verifies grid extent coordinates.
      */
     static void assertExtentEquals(final long[] low, final long[] high, final GridExtent extent) {
-        assertArrayEquals("extent.low",  low,  extent.getLow() .getCoordinateValues());
-        assertArrayEquals("extent.high", high, extent.getHigh().getCoordinateValues());
+        assertArrayEquals(low,  extent.getLow() .getCoordinateValues(), "extent.low");
+        assertArrayEquals(high, extent.getHigh().getCoordinateValues(), "extent.high");
     }
 
     /**
@@ -123,16 +125,16 @@ public final class GridGeometryTest extends TestCase {
          * Verify properties that should be stored "as-is".
          */
         final MathTransform trCorner = grid.getGridToCRS(PixelInCell.CELL_CORNER);
-        assertSame("gridToCRS", identity, trCorner);
+        assertSame(identity, trCorner, "gridToCRS");
         assertExtentEquals(low, high, grid.getExtent());
         /*
          * Verify computed math transform.
          */
         final MathTransform trCenter = grid.getGridToCRS(PixelInCell.CELL_CENTER);
         assertNotSame(trCenter, trCorner);
-        assertFalse ("gridToCRS.isIdentity",          trCenter.isIdentity());
-        assertEquals("gridToCRS.sourceDimensions", 4, trCenter.getSourceDimensions());
-        assertEquals("gridToCRS.targetDimensions", 4, trCenter.getTargetDimensions());
+        assertFalse (trCenter.isIdentity(), "gridToCRS.isIdentity");
+        assertEquals(4, trCenter.getSourceDimensions(), "gridToCRS.sourceDimensions");
+        assertEquals(4, trCenter.getTargetDimensions(), "gridToCRS.targetDimensions");
         assertMatrixEquals("gridToCRS", Matrices.create(5, 5, new double[] {
                 1, 0, 0, 0, 0.5,
                 0, 1, 0, 0, 0.5,
@@ -148,8 +150,8 @@ public final class GridGeometryTest extends TestCase {
         /*
          * Verify other computed properties.
          */
-        assertArrayEquals("resolution", new double[] {1, 1, 1, 1}, grid.getResolution(false), STRICT);
-        assertTrue("isConversionLinear", grid.isConversionLinear(0, 1, 2, 3));
+        assertArrayEquals(new double[] {1, 1, 1, 1}, grid.getResolution(false), "resolution");
+        assertTrue(grid.isConversionLinear(0, 1, 2, 3), "isConversionLinear");
         verifyGridToCRS(grid);
     }
 
@@ -168,16 +170,16 @@ public final class GridGeometryTest extends TestCase {
          * Verify properties that should be stored "as-is".
          */
         final MathTransform trCenter = grid.getGridToCRS(PixelInCell.CELL_CENTER);
-        assertSame("gridToCRS", identity, trCenter);
+        assertSame(identity, trCenter, "gridToCRS");
         assertExtentEquals(low, high, grid.getExtent());
         /*
          * Verify computed math transform.
          */
         final MathTransform trCorner = grid.getGridToCRS(PixelInCell.CELL_CORNER);
         assertNotSame(trCenter, trCorner);
-        assertFalse ("gridToCRS.isIdentity",          trCorner.isIdentity());
-        assertEquals("gridToCRS.sourceDimensions", 3, trCorner.getSourceDimensions());
-        assertEquals("gridToCRS.targetDimensions", 3, trCorner.getTargetDimensions());
+        assertFalse (trCorner.isIdentity(), "gridToCRS.isIdentity");
+        assertEquals(3, trCorner.getSourceDimensions(), "gridToCRS.sourceDimensions");
+        assertEquals(3, trCorner.getTargetDimensions(), "gridToCRS.targetDimensions");
         assertMatrixEquals("gridToCRS", new Matrix4(
                 1, 0, 0, -0.5,
                 0, 1, 0, -0.5,
@@ -192,8 +194,8 @@ public final class GridGeometryTest extends TestCase {
         /*
          * Verify other computed properties.
          */
-        assertArrayEquals("resolution", new double[] {1, 1, 1}, grid.getResolution(false), STRICT);
-        assertTrue("isConversionLinear", grid.isConversionLinear(0, 1, 2));
+        assertArrayEquals(new double[] {1, 1, 1}, grid.getResolution(false), "resolution");
+        assertTrue(grid.isConversionLinear(0, 1, 2), "isConversionLinear");
         verifyGridToCRS(grid);
     }
 
@@ -224,8 +226,8 @@ public final class GridGeometryTest extends TestCase {
         /*
          * Verify other computed properties.
          */
-        assertArrayEquals("resolution", new double[] {2, 1, 3}, grid.getResolution(false), STRICT);
-        assertTrue("isConversionLinear", grid.isConversionLinear(0, 1, 2));
+        assertArrayEquals(new double[] {2, 1, 3}, grid.getResolution(false), "resolution");
+        assertTrue(grid.isConversionLinear(0, 1, 2), "isConversionLinear");
         verifyGridToCRS(grid);
     }
 
@@ -275,7 +277,7 @@ public final class GridGeometryTest extends TestCase {
                 0, 1, 0.5,
                 0, 0, 1));
         final GridGeometry grid = new GridGeometry(extent, PixelInCell.CELL_CENTER, gridToCRS, null);
-        assertTrue("gridToCRS.isIdentity", grid.getGridToCRS(PixelInCell.CELL_CORNER).isIdentity());
+        assertTrue(grid.getGridToCRS(PixelInCell.CELL_CORNER).isIdentity(), "gridToCRS.isIdentity");
         verifyGridToCRS(grid);
     }
 
@@ -301,10 +303,10 @@ public final class GridGeometryTest extends TestCase {
         final MathTransform temporal  = MathTransforms.linear(3600, 60);
         final MathTransform gridToCRS = MathTransforms.compound(horizontal, vertical, temporal);
         final GridGeometry  grid      = new GridGeometry(extent, PixelInCell.CELL_CENTER, gridToCRS, null);
-        assertArrayEquals("resolution", new double[] {0.5, 0.25,        6.0, 3600}, grid.getResolution(true),  STRICT);
-        assertArrayEquals("resolution", new double[] {0.5, 0.25, Double.NaN, 3600}, grid.getResolution(false), STRICT);
-        assertFalse("isConversionLinear", grid.isConversionLinear(0, 1, 2, 3));
-        assertTrue ("isConversionLinear", grid.isConversionLinear(0, 1,    3));
+        assertArrayEquals(new double[] {0.5, 0.25,        6.0, 3600}, grid.getResolution(true),  "resolution");
+        assertArrayEquals(new double[] {0.5, 0.25, Double.NaN, 3600}, grid.getResolution(false), "resolution");
+        assertFalse(grid.isConversionLinear(0, 1, 2, 3), "isConversionLinear");
+        assertTrue (grid.isConversionLinear(0, 1,    3), "isConversionLinear");
     }
 
     /**
@@ -327,7 +329,7 @@ public final class GridGeometryTest extends TestCase {
         assertEnvelopeEquals(new GeneralEnvelope(
                 new double[] {-70,  5},
                 new double[] {+80, 15}), grid.getEnvelope(), STRICT);
-        assertArrayEquals("resolution", new double[] {0.5, 0.5}, grid.getResolution(false), STRICT);
+        assertArrayEquals(new double[] {0.5, 0.5}, grid.getResolution(false), "resolution");
         assertMatrixEquals("gridToCRS", new Matrix3(
                 0,   0.5, -89.75,
                 0.5, 0,  -179.75,
@@ -335,8 +337,8 @@ public final class GridGeometryTest extends TestCase {
         /*
          * Verify other computed properties.
          */
-        assertArrayEquals("resolution", new double[] {0.5, 0.5}, grid.getResolution(false), STRICT);
-        assertTrue("isConversionLinear", grid.isConversionLinear(0, 1));
+        assertArrayEquals(new double[] {0.5, 0.5}, grid.getResolution(false), "resolution");
+        assertTrue(grid.isConversionLinear(0, 1), "isConversionLinear");
         verifyGridToCRS(grid);
     }
 
@@ -366,9 +368,9 @@ public final class GridGeometryTest extends TestCase {
                 0,    0,    1), matrix, STRICT);
 
         // Verify other computed properties.
-        assertArrayEquals("resolution", new double[] {0.5, 2}, grid.getResolution(false), STRICT);
-        assertTrue("isConversionLinear", grid.isConversionLinear(0, 1));
-        assertSame("extent", extent, grid.getExtent());
+        assertArrayEquals(new double[] {0.5, 2}, grid.getResolution(false), "resolution");
+        assertTrue(grid.isConversionLinear(0, 1), "isConversionLinear");
+        assertSame(extent, grid.getExtent(), "extent");
         verifyGridToCRS(grid);
         /*
          * Same envelope and extent, but flip Y axis.
@@ -382,9 +384,9 @@ public final class GridGeometryTest extends TestCase {
                 0,    0,    1), matrix, STRICT);
 
         // Verify other computed properties.
-        assertArrayEquals("resolution", new double[] {0.5, 2}, grid.getResolution(false), STRICT);
-        assertTrue("isConversionLinear", grid.isConversionLinear(0, 1));
-        assertSame("extent", extent, grid.getExtent());
+        assertArrayEquals(new double[] {0.5, 2}, grid.getResolution(false), "resolution");
+        assertTrue(grid.isConversionLinear(0, 1), "isConversionLinear");
+        assertSame(extent, grid.getExtent(), "extent");
         verifyGridToCRS(grid);
         /*
          * The use of `DISPLAY` mode in this particular case should be equivalent ro `REFLECTION_Y`.
@@ -423,9 +425,9 @@ public final class GridGeometryTest extends TestCase {
                 0,    0,    1), matrix, STRICT);
 
         // Verify other computed properties.
-        assertArrayEquals("resolution", new double[] {0.5, 2}, grid.getResolution(false), STRICT);
-        assertTrue("isConversionLinear", grid.isConversionLinear(0, 1));
-        assertSame("extent", extent, grid.getExtent());
+        assertArrayEquals(new double[] {0.5, 2}, grid.getResolution(false), "resolution");
+        assertTrue(grid.isConversionLinear(0, 1), "isConversionLinear");
+        assertSame(extent, grid.getExtent(), "extent");
         verifyGridToCRS(grid);
         /*
          * Same extent and envelope, but reordering extend dimensions
@@ -443,9 +445,9 @@ public final class GridGeometryTest extends TestCase {
                 new long[] {  9,  14}, grid.getExtent());
 
         // Verify other computed properties.
-        assertArrayEquals("resolution", new double[] {0.5, 2}, grid.getResolution(false), STRICT);
-        assertTrue("isConversionLinear", grid.isConversionLinear(0, 1));
-        assertNotSame("extent", extent, grid.getExtent());
+        assertArrayEquals(new double[] {0.5, 2}, grid.getResolution(false), "resolution");
+        assertTrue(grid.isConversionLinear(0, 1), "isConversionLinear");
+        assertNotSame(extent, grid.getExtent(), "extent");
         verifyGridToCRS(grid);
     }
 
@@ -467,7 +469,7 @@ public final class GridGeometryTest extends TestCase {
         final Matrix   gridToCRS = MathTransforms.getMatrix(grid.getGridToCRS(PixelInCell.CELL_CORNER));
         final Number[] numbers   = ((ExtendedPrecisionMatrix) gridToCRS).getElementAsNumbers(false);
         final double[] elements  = MatrixSIS.castOrCopy(gridToCRS).getElements();
-        assertArrayEquals(new double[] {360, 0, 0, -180, 0, 180, 0, -90, 0, 0, 3000, -1000, 0, 0, 0, 1}, elements, STRICT);
+        assertArrayEquals(new double[] {360, 0, 0, -180, 0, 180, 0, -90, 0, 0, 3000, -1000, 0, 0, 0, 1}, elements);
         assertEquals(elements.length, numbers.length);
         for (int i=0; i<elements.length; i++) {
             final double expected = elements[i];
@@ -475,7 +477,7 @@ public final class GridGeometryTest extends TestCase {
             if (expected == 0) {
                 assertNull(actual);
             } else {
-                assertEquals(expected, actual.doubleValue(), STRICT);
+                assertEquals(expected, actual.doubleValue());
             }
         }
     }
@@ -539,9 +541,9 @@ public final class GridGeometryTest extends TestCase {
             final MathTransform gridToCRS = MathTransforms.linear(mat);
             expected = new GridGeometry(extent, PixelInCell.CELL_CENTER, gridToCRS, HardCodedCRS.CARTESIAN_2D);
         }
-        assertSame("envelope", grid.getEnvelope(), upsampled.getEnvelope());
-        assertEquals("GridGeometry", expected, upsampled);
-        assertArrayEquals("resolution", new double[] {0.25, 0.5}, expected.getResolution(false), STRICT);
+        assertSame(grid.getEnvelope(), upsampled.getEnvelope(), "envelope");
+        assertEquals(expected, upsampled, "GridGeometry");
+        assertArrayEquals(new double[] {0.25, 0.5}, expected.getResolution(false), "resolution");
     }
 
     /**
@@ -613,8 +615,8 @@ public final class GridGeometryTest extends TestCase {
         GridGeometry reduced = grid.selectDimensions(0, 1);
         assertNotSame(grid, reduced);
         assertExtentEquals(new long[] {336, 20}, new long[] {401, 419}, reduced.getExtent());
-        assertSame("CRS", HardCodedCRS.WGS84, reduced.getCoordinateReferenceSystem());
-        assertArrayEquals("resolution", new double[] {0.5, 0.5}, reduced.getResolution(false), STRICT);
+        assertSame(HardCodedCRS.WGS84, reduced.getCoordinateReferenceSystem(), "CRS");
+        assertArrayEquals(new double[] {0.5, 0.5}, reduced.getResolution(false), "resolution");
         assertMatrixEquals("gridToCRS", new Matrix3(
                   0, 0.5,  -90,
                   0.5, 0, -180,
@@ -625,16 +627,16 @@ public final class GridGeometryTest extends TestCase {
         reduced = grid.selectDimensions(2);
         assertNotSame(grid, reduced);
         assertExtentEquals(new long[] {4}, new long[] {10}, reduced.getExtent());
-        assertSame("CRS", HardCodedCRS.GRAVITY_RELATED_HEIGHT, reduced.getCoordinateReferenceSystem());
-        assertArrayEquals("resolution", new double[] {2}, reduced.getResolution(false), STRICT);
+        assertSame(HardCodedCRS.GRAVITY_RELATED_HEIGHT, reduced.getCoordinateReferenceSystem(), "CRS");
+        assertArrayEquals(new double[] {2}, reduced.getResolution(false), "resolution");
         assertMatrixEquals("gridToCRS", new Matrix2(
                   2, 3,
                   0, 1), MathTransforms.getMatrix(reduced.getGridToCRS(PixelInCell.CELL_CORNER)), STRICT);
         /*
          * Verify other computed properties.
          */
-        assertArrayEquals("resolution", new double[] {0.5, 0.5, 2}, grid.getResolution(false), STRICT);
-        assertTrue("isConversionLinear", grid.isConversionLinear(0, 1, 2));
+        assertArrayEquals(new double[] {0.5, 0.5, 2}, grid.getResolution(false), "resolution");
+        assertTrue(grid.isConversionLinear(0, 1, 2), "isConversionLinear");
         verifyGridToCRS(grid);
     }
 
@@ -668,8 +670,8 @@ public final class GridGeometryTest extends TestCase {
         /*
          * Verify other computed properties.
          */
-        assertArrayEquals("resolution", new double[] {0.5, 0.5}, reduced.getResolution(false), STRICT);
-        assertTrue("isConversionLinear", reduced.isConversionLinear(0, 1));
+        assertArrayEquals(new double[] {0.5, 0.5}, reduced.getResolution(false), "resolution");
+        assertTrue(reduced.isConversionLinear(0, 1), "isConversionLinear");
         verifyGridToCRS(reduced);
         /*
          * Test again by keeping the dimension without scale instead of discarding it.
@@ -680,6 +682,44 @@ public final class GridGeometryTest extends TestCase {
         assertMatrixEquals("gridToCRS", new Matrix2(0, 3, 0, 1), MathTransforms.getMatrix(tr), STRICT);
     }
 
+    /**
+     * Tests {@link GridGeometry#GridGeometry(GridGeometry, GridGeometry)}.
+     *
+     * @throws FactoryException if the constructor could not combine the CRS.
+     */
+    @Test
+    public void testConcatenate() throws FactoryException {
+        final GridGeometry lower = new GridGeometry(
+                new GridExtent(null, null, new long[] {17, 10}, true),
+                PixelInCell.CELL_CENTER,
+                MathTransforms.linear(new Matrix3(
+                    1,   0,  -7,
+                    0,  -1,  50,
+                    0,   0,   1)),
+                HardCodedCRS.WGS84);
+
+        final GridGeometry upper = new GridGeometry(
+                new GridExtent(null, null, new long[] {4}, true),
+                PixelInCell.CELL_CENTER,
+                MathTransforms.linear(new Matrix2(
+                    8, 20,
+                    0,  1)),
+                HardCodedCRS.TIME);
+
+        final GridGeometry expected = new GridGeometry(
+                new GridExtent(null, null, new long[] {17, 10, 4}, true),
+                PixelInCell.CELL_CENTER,
+                MathTransforms.linear(new Matrix4(
+                    1,   0,  0, -7,
+                    0,  -1,  0, 50,
+                    0,   0,  8, 20,
+                    0,   0,  0,  1)),
+                HardCodedCRS.WGS84_WITH_TIME);
+
+        final GridGeometry actual = new GridGeometry(lower, upper);
+        assertTrue(actual.equals(expected, ComparisonMode.DEBUG));
+    }
+
     /**
      * Tests {@link GridGeometry#createImageCRS(String, PixelInCell)}.
      */
diff --git a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/ArraysExt.java b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/ArraysExt.java
index e6baf24db0..87ccac229d 100644
--- a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/ArraysExt.java
+++ b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/ArraysExt.java
@@ -67,7 +67,7 @@ import java.lang.reflect.Array;
  * objects.
  *
  * @author Martin Desruisseaux (IRD, Geomatys)
- * @version 1.4
+ * @version 1.5
  *
  * @see Arrays
  *
@@ -1219,6 +1219,24 @@ public final class ArraysExt extends Static {
         return copy;
     }
 
+    /**
+     * Returns the concatenation of the given arrays.
+     * If any of the supplied arrays is null or empty, then the other array is returned directly (not copied).
+     *
+     * @param  a1  the first array to concatenate, or {@code null}.
+     * @param  a2  the second array to concatenate, or {@code null}.
+     * @return the concatenation of given arrays. May be one of the given arrays returned without copying.
+     *
+     * @since 1.5
+     */
+    public static double[] concatenate(final double[] a1, final double[] a2) {
+        if (a1 == null || a1.length == 0) return a2;
+        if (a2 == null || a2.length == 0) return a1;
+        final double[] copy = Arrays.copyOf(a1, a1.length + a2.length);
+        System.arraycopy(a2, 0, copy, a1.length, a2.length);
+        return copy;
+    }
+
     /**
      * Removes the duplicated elements in the given array. This method should be invoked only for small arrays,
      * typically less than 10 distinct elements. For larger arrays, use {@link java.util.LinkedHashSet} instead.


(sis) 02/04: Move `getEnvelope()` default implementation from `AbstractGridCoverageResource` class to `GridCoverageResource` interface.

Posted by de...@apache.org.
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 c25766bdff4714df6d4cd9a639fb1b43ae711d2f
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Fri Nov 24 12:50:24 2023 +0100

    Move `getEnvelope()` default implementation from `AbstractGridCoverageResource` class to `GridCoverageResource` interface.
---
 .../sis/storage/AbstractGridCoverageResource.java  | 21 +-------------------
 .../apache/sis/storage/GridCoverageResource.java   | 23 +++++++++++++++++++++-
 .../org/apache/sis/storage/esri/RasterStore.java   | 14 -------------
 3 files changed, 23 insertions(+), 35 deletions(-)

diff --git a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/AbstractGridCoverageResource.java b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/AbstractGridCoverageResource.java
index 33e5bb4e49..862133bc4f 100644
--- a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/AbstractGridCoverageResource.java
+++ b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/AbstractGridCoverageResource.java
@@ -17,7 +17,6 @@
 package org.apache.sis.storage;
 
 import java.util.Locale;
-import java.util.Optional;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.logging.LogRecord;
@@ -60,7 +59,7 @@ import org.apache.sis.storage.internal.Resources;
  * </ul>
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.4
+ * @version 1.5
  * @since   1.2
  */
 public abstract class AbstractGridCoverageResource extends AbstractResource implements GridCoverageResource {
@@ -97,24 +96,6 @@ public abstract class AbstractGridCoverageResource extends AbstractResource impl
         super(parentListeners, hidden);
     }
 
-    /**
-     * Returns the envelope of the grid geometry if known.
-     * The envelope is absent if the grid geometry does not provide this information.
-     *
-     * @return the grid geometry envelope.
-     * @throws DataStoreException if an error occurred while computing the grid geometry.
-     *
-     * @see GridGeometry#getEnvelope()
-     */
-    @Override
-    public Optional<Envelope> getEnvelope() throws DataStoreException {
-        final GridGeometry gg = getGridGeometry();
-        if (gg != null && gg.isDefined(GridGeometry.ENVELOPE)) {
-            return Optional.of(gg.getEnvelope());
-        }
-        return Optional.empty();
-    }
-
     /**
      * Invoked in a synchronized block the first time that {@code getMetadata()} is invoked.
      * The default implementation populates metadata based on information provided by
diff --git a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/GridCoverageResource.java b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/GridCoverageResource.java
index caeb0b193d..8921547408 100644
--- a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/GridCoverageResource.java
+++ b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/GridCoverageResource.java
@@ -17,6 +17,8 @@
 package org.apache.sis.storage;
 
 import java.util.List;
+import java.util.Optional;
+import org.opengis.geometry.Envelope;
 import org.apache.sis.coverage.SampleDimension;
 import org.apache.sis.coverage.grid.GridGeometry;
 import org.apache.sis.coverage.grid.GridCoverage;
@@ -40,10 +42,29 @@ import org.apache.sis.util.ArraysExt;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Johann Sorel (Geomatys)
- * @version 1.4
+ * @version 1.5
  * @since   1.0
  */
 public interface GridCoverageResource extends DataSet {
+    /**
+     * Returns the spatiotemporal extent of this resource in its most natural coordinate reference system.
+     * The default implementation fetches this information from the {@linkplain #getGridGeometry() grid geometry},
+     * if presents.
+     *
+     * @return the spatiotemporal resource extent. May be absent if none or too costly to compute.
+     * @throws DataStoreException if an error occurred while reading or computing the envelope.
+     *
+     * @see GridGeometry#getEnvelope()
+     */
+    @Override
+    default Optional<Envelope> getEnvelope() throws DataStoreException {
+        final GridGeometry gg = getGridGeometry();
+        if (gg != null && gg.isDefined(GridGeometry.ENVELOPE)) {
+            return Optional.of(gg.getEnvelope());
+        }
+        return Optional.empty();
+    }
+
     /**
      * Returns the valid extent of grid coordinates together with the conversion from those grid
      * coordinates to real world coordinates. A grid geometry contains the following information:
diff --git a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/RasterStore.java b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/RasterStore.java
index 4d22dfe327..9b8f3cc9dd 100644
--- a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/RasterStore.java
+++ b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/RasterStore.java
@@ -18,7 +18,6 @@ package org.apache.sis.storage.esri;
 
 import java.util.List;
 import java.util.Arrays;
-import java.util.Optional;
 import java.util.Hashtable;
 import java.util.Locale;
 import java.util.logging.Level;
@@ -30,7 +29,6 @@ import java.awt.image.ColorModel;
 import java.awt.image.DataBuffer;
 import java.awt.image.SampleModel;
 import java.awt.image.WritableRaster;
-import org.opengis.geometry.Envelope;
 import org.opengis.metadata.Metadata;
 import org.opengis.metadata.maintenance.ScopeCode;
 import org.apache.sis.metadata.sql.MetadataStoreException;
@@ -143,18 +141,6 @@ abstract class RasterStore extends PRJDataStore implements GridCoverageResource
         return listComponentFiles(PRJ, STX, CLR);
     }
 
-    /**
-     * Returns the spatiotemporal extent of the raster file.
-     *
-     * @return the spatiotemporal resource extent.
-     * @throws DataStoreException if an error occurred while computing the envelope.
-     * @hidden
-     */
-    @Override
-    public Optional<Envelope> getEnvelope() throws DataStoreException {
-        return Optional.ofNullable(getGridGeometry().getEnvelope());
-    }
-
     /**
      * Builds metadata and assigns the result to the {@link #metadata} field.
      *


(sis) 04/04: Add a `GridCoverageProcessor.appendDimension(…)` method.

Posted by de...@apache.org.
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 <ma...@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}.


(sis) 01/04: Minor cleaning (documentation, removal of a deprecated method).

Posted by de...@apache.org.
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 e0588cac363557d30ee941554a6ea291b76f4b14
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Fri Nov 24 12:42:42 2023 +0100

    Minor cleaning (documentation, removal of a deprecated method).
---
 .../main/org/apache/sis/filter/ComparisonFilter.java        |  2 +-
 .../sis/referencing/factory/CommonAuthorityFactory.java     |  4 ++--
 .../apache/sis/storage/aggregate/CoverageAggregator.java    | 13 +++----------
 .../main/org/apache/sis/storage/aggregate/package-info.java |  2 +-
 4 files changed, 7 insertions(+), 14 deletions(-)

diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/ComparisonFilter.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/ComparisonFilter.java
index f3a5dbcbff..a3cf1cf7d3 100644
--- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/ComparisonFilter.java
+++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/ComparisonFilter.java
@@ -50,7 +50,7 @@ import org.opengis.filter.BetweenComparisonOperator;
 /**
  * Comparison operators between two values. Values are converted to the same type before comparison, using a widening
  * conversion (for example from {@link Integer} to {@link Double}). If values cannot be compared because they cannot
- * be converted to a common type, or because a value is null or NaN, then the comparison result if {@code false}.
+ * be converted to a common type, or because a value is null or NaN, then the comparison result is {@code false}.
  * A consequence of this rule is that the conditions {@literal A < B} and {@literal A ≥ B} may be false at the same time.
  *
  * <p>If one operand is a collection, all collection elements may be compared to the other value.
diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/CommonAuthorityFactory.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/CommonAuthorityFactory.java
index 3b0874918e..fdf4182bd9 100644
--- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/CommonAuthorityFactory.java
+++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/CommonAuthorityFactory.java
@@ -687,8 +687,8 @@ public class CommonAuthorityFactory extends GeodeticAuthorityFactory implements
      * @return an exception initialized with an error message built from the specified information.
      */
     private static NoSuchAuthorityCodeException noSuchAuthorityCode(String localCode, String code, Exception cause) {
-        return (NoSuchAuthorityCodeException) new NoSuchAuthorityCodeException(Resources.format(Resources.Keys.NoSuchAuthorityCode_3,
+        return new NoSuchAuthorityCodeException(Resources.format(Resources.Keys.NoSuchAuthorityCode_3,
                 Constants.OGC, CoordinateReferenceSystem.class, localCode),
-                Constants.OGC, localCode, code).initCause(cause);
+                Constants.OGC, localCode, code, cause);
     }
 }
diff --git a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/CoverageAggregator.java b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/CoverageAggregator.java
index 36d63397e3..f2895a55ec 100644
--- a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/CoverageAggregator.java
+++ b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/CoverageAggregator.java
@@ -101,9 +101,10 @@ import org.apache.sis.util.collection.BackingStoreException;
  * and no more addition are in progress.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.4
+ * @version 1.5
  * @since   1.3
  */
+@SuppressWarnings("exports")    // There is no public method using `GroupBySample`.
 public final class CoverageAggregator extends Group<GroupBySample> {
     /**
      * The listeners of the parent resource (typically a {@link DataStore}), or {@code null} if none.
@@ -327,7 +328,7 @@ public final class CoverageAggregator extends Group<GroupBySample> {
      * @since 1.4
      */
     public void addRangeAggregate(final GridCoverageResource... sources) throws DataStoreException {
-        addRangeAggregate(sources, (int[][]) null);
+        addRangeAggregate(sources, null);
     }
 
     /**
@@ -467,12 +468,4 @@ public final class CoverageAggregator extends Group<GroupBySample> {
         }
         return result;
     }
-
-    /**
-     * @deprecated Replaced by {@link #build(GenericName)}.
-     */
-    @Deprecated
-    public Resource build() {
-        return build(null);
-    }
 }
diff --git a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/package-info.java b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/package-info.java
index 6ae0ad3b18..0089c3a22c 100644
--- a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/package-info.java
+++ b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/package-info.java
@@ -22,7 +22,7 @@
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.4
+ * @version 1.5
  * @since   1.3
  */
 package org.apache.sis.storage.aggregate;