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 0cc353e1194cb494c69ad51852c022e5fe0a92a0
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Wed Jan 22 10:50:23 2025 +0100

    Complete the translation (or "grid shift") methods by convenience methods 
doing the translation in the reverse direction.
    It avoids the need for the caller to negate the value, and in extreme case 
can avoid an integer overflow.
---
 .../org/apache/sis/coverage/grid/GridExtent.java   | 38 ++++++++++++++++-----
 .../org/apache/sis/coverage/grid/GridGeometry.java | 39 +++++++++++++++++-----
 .../apache/sis/storage/image/WritableStore.java    |  6 +---
 .../main/org/apache/sis/gui/map/StatusBar.java     |  6 ++--
 4 files changed, 64 insertions(+), 25 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 2356f535d7..072ed3aada 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
@@ -1714,9 +1714,8 @@ public class GridExtent implements GridEnvelope, 
LenientComparable, Serializable
 
     /**
      * Creates a new grid extent upsampled by the given number of cells along 
each grid dimensions.
-     * This method multiplies {@linkplain #getLow(int) low} and {@linkplain 
#getHigh(int) high} coordinates
-     * by the given periods.
-     *
+     * This method multiplies the {@linkplain #getLow(int) low coordinates}
+     * and the {@linkplain #getSize(int) size} by the given periods.
      * This method does not change the number of dimensions of the grid extent.
      *
      * <h4>Number of arguments</h4>
@@ -1885,8 +1884,8 @@ public class GridExtent implements GridEnvelope, 
LenientComparable, Serializable
      * If the array is shorter, missing values default to 0 (i.e. no 
translation in unspecified dimensions).
      * If the array is longer, extraneous values are ignored.
      *
-     * @param  translation  translation to apply on each axis in order.
-     * @return a grid extent whose coordinates (both low and high ones) have 
been translated by given amounts.
+     * @param  translation  translation to apply on each axis in order. Can be 
an array of any length.
+     * @return a grid extent whose coordinates (both low and high ones) have 
been translated by the given numbers.
      *         If the given translation is a no-op (no value or only 0 ones), 
then this extent is returned as is.
      * @throws ArithmeticException if the translation results in coordinates 
that overflow 64-bits integer.
      *
@@ -1895,7 +1894,24 @@ public class GridExtent implements GridEnvelope, 
LenientComparable, Serializable
      *
      * @since 1.1
      */
-    public GridExtent translate(final long... translation) {
+    public final GridExtent translate(final long... translation) {
+        return translate(translation, false);
+    }
+
+    /**
+     * Returns an extent translated by the given number of cells, optionally 
in the reverse direction.
+     * Invoking this method is equivalent to invoking {@link 
#translate(long...)}, except that this method
+     * use the negative values of the given translation terms if the {@code 
negate} argument is {@code true}.
+     *
+     * @param  translation  translation to apply on each axis in order. Can be 
an array of any length.
+     * @param  negate       whether to use the negative values of the given 
translation terms.
+     * @return a grid extent whose coordinates (both low and high ones) have 
been translated by the given numbers.
+     *         If the given translation is a no-op (no value or only 0 ones), 
then this extent is returned as is.
+     * @throws ArithmeticException if the translation results in coordinates 
that overflow 64-bits integer.
+     *
+     * @since 1.5
+     */
+    public GridExtent translate(final long[] translation, final boolean 
negate) {
         final int m = getDimension();
         final int length = Math.min(m, translation.length);
         if (isZero(translation, length)) {
@@ -1906,8 +1922,14 @@ public class GridExtent implements GridEnvelope, 
LenientComparable, Serializable
         for (int i=0; i < length; i++) {
             final int  j = i + m;
             final long t = translation[i];
-            c[i] = Math.addExact(c[i], t);
-            c[j] = Math.addExact(c[j], t);
+            if (negate) {
+                // Do not negate `t` because it may overflow. Use 
`subtractExact(…)` instead.
+                c[i] = Math.subtractExact(c[i], t);
+                c[j] = Math.subtractExact(c[j], t);
+            } else {
+                c[i] = Math.addExact(c[i], t);
+                c[j] = Math.addExact(c[j], t);
+            }
         }
         return translated;
     }
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 fefcd80525..b8e60e5817 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
@@ -1618,7 +1618,7 @@ public class GridGeometry implements LenientComparable, 
Serializable {
      *
      * @param  translation  translation to apply on each grid axis in order.
      * @return a grid geometry whose coordinates (both low and high ones) and
-     *         the "grid to CRS" transforms have been translated by given 
amounts.
+     *         the "grid to CRS" transforms have been translated by given 
numbers.
      *         If the given translation is a no-op (no value or only 0 ones), 
then this grid is returned as is.
      * @throws ArithmeticException if the translation results in coordinates 
that overflow 64-bits integer.
      *
@@ -1626,11 +1626,29 @@ public class GridGeometry implements LenientComparable, 
Serializable {
      *
      * @since 1.3
      */
-    public GridGeometry shiftGrid(final long... translation) {
+    public final GridGeometry shiftGrid(final long... translation) {
+        return shiftGrid(translation, false);
+    }
+
+    /**
+     * Translates grid coordinates by the given number of cells, optionally in 
the reverse direction.
+     * Invoking this method is equivalent to invoking {@link 
#shiftGrid(long...)}, except that this method
+     * use the negative values of the given translation terms if the {@code 
negate} argument is {@code true}.
+     *
+     * @param  translation  translation to apply on each grid axis in order. 
Can be an array of any length.
+     * @param  negate       whether to use the negative values of the given 
translation terms.
+     * @return a grid geometry whose coordinates (both low and high ones) and
+     *         the "grid to CRS" transforms have been translated by given 
numbers.
+     *         If the given translation is a no-op (no value or only 0 ones), 
then this grid is returned as is.
+     * @throws ArithmeticException if the translation results in coordinates 
that overflow 64-bits integer.
+     *
+     * @since 1.5
+     */
+    public GridGeometry shiftGrid(final long[] translation, final boolean 
negate) {
         ArgumentChecks.ensureNonNull("translation", translation);
         GridExtent newExtent = extent;
         if (newExtent != null) {
-            newExtent = newExtent.translate(translation);
+            newExtent = newExtent.translate(translation, negate);
             if (newExtent == extent) return this;
         }
         MathTransform t1 = gridToCRS;
@@ -1640,7 +1658,8 @@ public class GridGeometry implements LenientComparable, 
Serializable {
             final double[] vector = new double[getDimension()];
             for (int i=Math.min(vector.length, translation.length); --i >= 0;) 
{
                 isZero &= (translation[i] == 0);
-                vector[i] = Math.negateExact(translation[i]);
+                double v = translation[i];
+                vector[i] = negate ? v : -v;    // Really negate if `negate` 
is false.
             }
             if (isZero) return this;
             final MathTransform t = MathTransforms.translation(vector);
@@ -1819,11 +1838,13 @@ public class GridGeometry implements LenientComparable, 
Serializable {
             throws TransformException
     {
         GridExtent result = other.getExtent();
-        final MathTransform tr = other.createTransformTo(this, include);
-        if (!tr.isIdentity()) {
-            final boolean isCenter = (include == PixelInCell.CELL_CENTER);
-            final GeneralEnvelope bounds = result.toEnvelope(tr, isCenter, tr, 
null);
-            result = new GridExtent(bounds, isCenter, rounding, 
GridClippingMode.NONE, null, null, extent, null);
+        if (cornerToCRS != other.cornerToCRS || gridToCRS != other.gridToCRS) 
{   // Quick check for a common case.
+            final MathTransform tr = other.createTransformTo(this, include);
+            if (!tr.isIdentity()) {
+                final boolean isCenter = (include == PixelInCell.CELL_CENTER);
+                final GeneralEnvelope bounds = result.toEnvelope(tr, isCenter, 
tr, null);
+                result = new GridExtent(bounds, isCenter, rounding, 
GridClippingMode.NONE, null, null, extent, null);
+            }
         }
         return result;
     }
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/WritableStore.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/WritableStore.java
index cf94e852c2..3a5372a8d7 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/WritableStore.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/WritableStore.java
@@ -212,11 +212,7 @@ class WritableStore extends WorldFileStore {
          * Must be done before to compare with existing grid.
          */
         final GridExtent extent = gg.getExtent();
-        final long[] translation = new long[extent.getDimension()];
-        for (int i=0; i<translation.length; i++) {
-            translation[i] = Math.negateExact(extent.getLow(i));
-        }
-        gg = gg.shiftGrid(translation);
+        gg = gg.shiftGrid(extent.getLow().getCoordinateValues(), true);
         /*
          * If the data store already contains a coverage, then the given grid 
geometry
          * must be identical to the existing one, in which case there is 
nothing to do.
diff --git 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/StatusBar.java 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/StatusBar.java
index 67f7a05107..5392aa1577 100644
--- a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/StatusBar.java
+++ b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/StatusBar.java
@@ -711,10 +711,10 @@ public class StatusBar extends Widget implements 
EventHandler<MouseEvent> {
             if (sliceExtent != null) {
                 final long[] offset = new long[dimension];
                 for (final int i : getXYDimensions()) {
-                    offset[i] = Math.negateExact(sliceExtent.getLow(i));
+                    offset[i] = sliceExtent.getLow(i);
                 }
-                sliceExtent = sliceExtent.translate(offset);
-                geometry = geometry.shiftGrid(offset);              // Does 
not change the "real world" envelope.
+                sliceExtent = sliceExtent.translate(offset, true);
+                geometry = geometry.shiftGrid(offset, true);        // Does 
not change the "real world" envelope.
                 try {
                     geometry = geometry.relocate(sliceExtent);      // Changes 
the "real world" envelope.
                 } catch (TransformException e) {

Reply via email to