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 95ab3d9cd6 Add upsample methods on GridExtent and GridGeometry
95ab3d9cd6 is described below

commit 95ab3d9cd627f8d9f64d9ca68431d197d7b3a0db
Author: jsorel <johann.so...@geomatys.com>
AuthorDate: Thu Sep 8 15:12:08 2022 +0200

    Add upsample methods on GridExtent and GridGeometry
---
 .../org/apache/sis/coverage/grid/GridExtent.java   | 43 +++++++++++++++++
 .../org/apache/sis/coverage/grid/GridGeometry.java | 56 ++++++++++++++++++++++
 .../apache/sis/coverage/grid/GridExtentTest.java   | 12 +++++
 .../apache/sis/coverage/grid/GridGeometryTest.java | 34 +++++++++++++
 4 files changed, 145 insertions(+)

diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridExtent.java 
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridExtent.java
index a27bbcf327..d0488546cb 100644
--- 
a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridExtent.java
+++ 
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridExtent.java
@@ -1510,6 +1510,49 @@ public class GridExtent implements GridEnvelope, 
LenientComparable, Serializable
         return Arrays.equals(coordinates, sub.coordinates) ? this : sub;
     }
 
+    /**
+     * Creates a new grid extent upsampled by the given amount of cells along 
each grid dimensions.
+     * This method multiplies {@linkplain #getLow(int) low coordinates} and 
{@linkplain #getSize(int) grid sizes}
+     * by the given periods.
+     *
+     * <div class="note"><b>Note:</b>
+     * The envelope computed from a grid extent is preserved after upsampling.
+     * </div>
+     *
+     * This method does not change the number of dimensions of the grid extent.
+     *
+     * <h4>Number of arguments</h4>
+     * The {@code periods} array length should be equal to the {@linkplain 
#getDimension() number of dimensions}.
+     * If the array is shorter, missing values default to 1 (i.e. samplings in 
unspecified dimensions are unchanged).
+     * If the array is longer, extraneous values are ignored.
+     *
+     * @param  periods  the upsampling. Length shall be equal to the number of 
dimension and all values shall be greater than zero.
+     * @return the upsampled extent, or {@code this} is upsampling results in 
the same extent.
+     * @throws IllegalArgumentException if a period is not greater than zero.
+     */
+    public GridExtent upsample(int... periods) {
+        ArgumentChecks.ensureNonNull("periods", periods);
+        final int m = getDimension();
+        final int length = Math.min(m, periods.length);
+        final GridExtent sub = new GridExtent(this);
+        for (int i=0; i<length; i++) {
+            final long s = periods[i];
+            if (s > 1) {
+                final int j = i + m;
+                long low  = coordinates[i];
+                long size = coordinates[j] - low + 1;                      // 
Result is an unsigned number.
+                if (size == 0) {
+                    throw new 
ArithmeticException(Errors.format(Errors.Keys.IntegerOverflow_1, Long.SIZE));
+                }
+                sub.coordinates[i] = low * s;
+                sub.coordinates[j] = sub.coordinates[i] + size * s -1;
+            } else if (s <= 0) {
+                throw new 
IllegalArgumentException(Errors.format(Errors.Keys.ValueNotGreaterThanZero_2, 
Strings.toIndexed("periods", i), s));
+            }
+        }
+        return Arrays.equals(coordinates, sub.coordinates) ? this : sub;
+    }
+
     /**
      * Returns a slice of this grid extent computed by a ratio between 0 and 1 
inclusive.
      * This is a helper method for {@link GridDerivation#sliceByRatio(double, 
int...)} implementation.
diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java 
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
index 6456f230c1..8ebb22fb70 100644
--- 
a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
+++ 
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
@@ -1470,6 +1470,62 @@ public class GridGeometry implements LenientComparable, 
Serializable {
         return this;
     }
 
+    /**
+     * Creates a new grid geometry upsampling the GridExtent by the given 
amount of cells along each grid dimensions.
+     * This method multiplies {@linkplain GridExtent#getLow(int) low 
coordinates} and {@linkplain GridExtent#getSize(int) grid sizes}
+     * by the given periods.
+     *
+     * <div class="note"><b>Note:</b>
+     * The envelope of the new grid geometry is preserved after upsampling.
+     * </div>
+     *
+     * This method does not change the number of dimensions of the grid 
geometry.
+     *
+     * <h4>Number of arguments</h4>
+     * The {@code periods} array length should be equal to the {@linkplain 
#getDimension() number of dimensions}.
+     * If the array is shorter, missing values default to 1 (i.e. samplings in 
unspecified dimensions are unchanged).
+     * If the array is longer, extraneous values are ignored.
+     *
+     * @param  periods  the upsampling. Length shall be equal to the number of 
dimension and all values shall be greater than zero.
+     * @return the upsampled grid geometry, or {@code this} is upsampling 
results in the same extent.
+     * @throws IllegalArgumentException if a period is not greater than zero.
+     *
+     * @see GridExtent#upsample(int...)
+     */
+    public GridGeometry upsample(int... periods) {
+
+        final GridExtent extent = getExtent();
+        final GridExtent upExtent = extent.upsample(periods);
+        if (upExtent == extent) {
+            //unchanged
+            return this;
+        }
+        final int dimension = upExtent.getDimension();
+
+        final MathTransform gridToCrs = getGridToCRS(PixelInCell.CELL_CORNER);
+        final MathTransform upGridToCrs;
+        if (gridToCrs instanceof LinearTransform) {
+            /*
+            By dividing the matrix elements directly we avoid some numeric 
errors.
+            */
+            final LinearTransform lnt = (LinearTransform) gridToCrs;
+            final MatrixSIS matrix = Matrices.copy(lnt.getMatrix());
+            for (int i = 0; i < dimension; i++) {
+                for (int k = 0; k < dimension; k++) {
+                    matrix.setElement(k, i, matrix.getElement(k, i) / 
periods[i]);
+                }
+            }
+            upGridToCrs = MathTransforms.linear(matrix);
+        } else {
+            final double[] scaling = new double[dimension];
+            for (int i = 0; i < dimension; i++) {
+                scaling[i] = 1.0 / periods[i];
+            }
+            upGridToCrs = 
MathTransforms.concatenate(MathTransforms.scale(scaling), gridToCrs);
+        }
+        return new GridGeometry(upExtent, PixelInCell.CELL_CORNER, 
upGridToCrs, getCoordinateReferenceSystem());
+    }
+
     /**
      * Creates a one-, two- or three-dimensional coordinate reference system 
for cell indices in the grid.
      * This method returns a CRS which is derived from the "real world" CRS or 
a subset of it.
diff --git 
a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridExtentTest.java
 
b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridExtentTest.java
index 65cec4bcf4..430d76647d 100644
--- 
a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridExtentTest.java
+++ 
b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridExtentTest.java
@@ -83,6 +83,18 @@ public final strictfp class GridExtentTest extends TestCase {
         assertExtentEquals(extent, 2,  4,   5);                 //   2 cells
     }
 
+    /**
+     * Tests the {@link GridExtent#upsample(int...)}.
+     */
+    @Test
+    public void testUpsample() {
+        GridExtent extent = create3D();
+        extent = extent.upsample(4, 3, 9);
+        assertExtentEquals(extent, 0, 400, 1999);               // 1600 cells
+        assertExtentEquals(extent, 1, 600, 2399);               // 1800 cells
+        assertExtentEquals(extent, 2, 360,  449);               //   90 cells
+    }
+
     /**
      * Tests the {@link GridExtent#GridExtent(AbstractEnvelope,
      * GridRoundingMode, int[], int[], GridExtent, int[])} constructor.
diff --git 
a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridGeometryTest.java
 
b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridGeometryTest.java
index 87ef02e1ac..02e8b6a86b 100644
--- 
a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridGeometryTest.java
+++ 
b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridGeometryTest.java
@@ -561,6 +561,40 @@ public final strictfp class GridGeometryTest extends 
TestCase {
         verifyGridToCRS(grid);
     }
 
+    /**
+     * Tests {@link GridGeometry#upsample(int...)}.
+     */
+    @Test
+    public void testUpsample() {
+
+        final GridGeometry grid;
+        { //grid
+            final GridExtent extent = new GridExtent(null, new long[]{10,-8}, 
new long[]{100, 50}, false);
+            final Matrix3 mat = new Matrix3(
+                    1,  0, 10,
+                    0, -2, 50,
+                    0,  0,  1);
+            final MathTransform gridToCRS = MathTransforms.linear(mat);
+            grid = new GridGeometry(extent, PixelInCell.CELL_CENTER, 
gridToCRS, HardCodedCRS.CARTESIAN_2D);
+        }
+
+        final GridGeometry surSampling = grid.upsample(4, 4);
+
+        final GridGeometry expected;
+        { //expected grid
+            GridExtent extent = new GridExtent(null, new long[]{40,-32}, new 
long[]{400, 200}, false);
+            final Matrix3 mat = new Matrix3(
+                    0.25,  0,  9.625,
+                    0,  -0.5, 50.750,
+                    0,     0,      1);
+            final MathTransform gridToCRS = MathTransforms.linear(mat);
+            expected = new GridGeometry(extent, PixelInCell.CELL_CENTER, 
gridToCRS, HardCodedCRS.CARTESIAN_2D);
+        }
+
+        assertEquals(grid.getEnvelope(), surSampling.getEnvelope());
+        assertEquals(expected, surSampling);
+    }
+
     /**
      * Tests {@link GridGeometry#reduce(int...)} with a {@code gridToCRS} 
transform having a constant value
      * in one dimension. This method tests indirectly {@link 
SliceGeometry#findTargetDimensions(MathTransform,

Reply via email to