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 <[email protected]>
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,