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 cd3eb5eaf8377414343ef631a09db3c3a1531987
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Wed Jan 22 11:07:46 2025 +0100

    Move `ReshapedImage` to an internal package for reuse by other modules, and 
add a constructor for creating a translated image.
    It will be needed for work on aggregation in later commit.
---
 .../sis/coverage/grid/BufferedGridCoverage.java    |  4 +-
 .../apache/sis/coverage/grid/GridCoverage2D.java   | 23 +++++-----
 .../grid => image/privy}/ReshapedImage.java        | 51 +++++++++++++++++-----
 .../coverage/grid/ResampledGridCoverageTest.java   |  1 +
 .../grid => image/privy}/ReshapedImageTest.java    | 12 ++---
 5 files changed, 60 insertions(+), 31 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/BufferedGridCoverage.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/BufferedGridCoverage.java
index 098515b9c8..e4105667ea 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/BufferedGridCoverage.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/BufferedGridCoverage.java
@@ -166,7 +166,7 @@ public class BufferedGridCoverage extends GridCoverage {
         final long expectedSize = getSampleCount(extent, numBands);
         final long bufferSize = Math.multiplyFull(data.getSize(), numBanks);
         if (bufferSize < expectedSize) {
-            final StringBuilder b = new StringBuilder();
+            final var b = new StringBuilder();
             for (int i=0; i < extent.getDimension(); i++) {
                 if (i != 0) b.append(" × ");
                 b.append(extent.getSize(i));
@@ -254,7 +254,7 @@ public class BufferedGridCoverage extends GridCoverage {
         }
         try {
             return cachedRenderings.computeIfAbsent(sliceExtent, (slice) -> {
-                ImageRenderer renderer = new ImageRenderer(this, slice);
+                var renderer = new ImageRenderer(this, slice);
                 renderer.setData(data);
                 return renderer.createImage();
             });
diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridCoverage2D.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridCoverage2D.java
index 90753bb89a..e3bd525acd 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridCoverage2D.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridCoverage2D.java
@@ -45,6 +45,7 @@ import org.opengis.referencing.operation.MathTransform1D;
 import org.apache.sis.image.DataType;
 import org.apache.sis.coverage.SampleDimension;
 import org.apache.sis.image.privy.ImageUtilities;
+import org.apache.sis.image.privy.ReshapedImage;
 import org.apache.sis.feature.internal.Resources;
 import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.Debug;
@@ -90,7 +91,7 @@ import org.opengis.coverage.PointOutsideCoverageException;
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Johann Sorel (Geomatys)
  * @author  Alexis Manin (Geomatys)
- * @version 1.4
+ * @version 1.5
  * @since   1.1
  */
 public class GridCoverage2D extends GridCoverage {
@@ -274,7 +275,7 @@ public class GridCoverage2D extends GridCoverage {
      */
     private static RenderedImage unwrapIfSameSize(RenderedImage data) {
         if (data instanceof ReshapedImage) {
-            final RenderedImage source = ((ReshapedImage) data).source;
+            final var source = ((ReshapedImage) data).source;
             if (source.getWidth() == data.getWidth() && source.getHeight() == 
data.getHeight()) {
                 data = source;
             }
@@ -347,8 +348,8 @@ public class GridCoverage2D extends GridCoverage {
      * @param  crs        coordinate reference system, or {@code null} if none.
      */
     private static GridExtent createExtent(final int dimension, final 
Rectangle bounds, final CoordinateReferenceSystem crs) {
-        final long[] low  = new long[dimension];
-        final long[] high = new long[dimension];
+        final var low  = new long[dimension];
+        final var high = new long[dimension];
         low [0] = bounds.x;
         low [1] = bounds.y;
         high[0] = bounds.width  + low[0] - 1;        // Inclusive.
@@ -588,11 +589,11 @@ public class GridCoverage2D extends GridCoverage {
             /*
              * Convert the coordinates from this grid coverage coordinate 
system to the image coordinate system.
              * The coverage coordinates may require 64 bits integers, but 
after translation the (x,y) coordinates
-             * should be in 32 bits integers range. Do not cast to 32 bits now 
however; this will be done later.
+             * should be in 32 bits integers range. Do not cast to 32 bits now 
however, this will be done later.
              */
             final long xmin = addExact(sliceExtent.getLow (xDimension), 
gridToImageX);
             final long ymin = addExact(sliceExtent.getLow (yDimension), 
gridToImageY);
-            final long xmax = addExact(sliceExtent.getHigh(xDimension), 
gridToImageX);
+            final long xmax = addExact(sliceExtent.getHigh(xDimension), 
gridToImageX);    // Inclusive
             final long ymax = addExact(sliceExtent.getHigh(yDimension), 
gridToImageY);
             /*
              * BufferedImage.getSubimage() returns a new image with upper-left 
coordinate at (0,0),
@@ -600,7 +601,7 @@ public class GridCoverage2D extends GridCoverage {
              * upper-left point is inside the image.
              */
             if (data instanceof BufferedImage) {
-                BufferedImage result = (BufferedImage) data;
+                var result = (BufferedImage) data;
                 /*
                  * BufferedImage origin should be (0, 0). But for consistency 
with image API,
                  * we consider it as variable.
@@ -645,7 +646,7 @@ public class GridCoverage2D extends GridCoverage {
              * with Raster.createChild(…), but that would force us to invoke 
RenderedImage.getTile(…) which
              * may force data loading earlier than desired.
              */
-            final ReshapedImage result = new ReshapedImage(data, xmin, ymin, 
xmax, ymax);
+            final var result = new ReshapedImage(data, xmin, ymin, xmax, ymax);
             return result.isIdentity() ? data : result;
         } catch (ArithmeticException e) {
             throw new CannotEvaluateException(e.getMessage(), e);
@@ -665,9 +666,9 @@ public class GridCoverage2D extends GridCoverage {
     void appendDataLayout(final TreeTable.Node root, final Vocabulary 
vocabulary, final TableColumn<CharSequence> column) {
         final TreeTable.Node branch = root.newChild();
         branch.setValue(column, 
vocabulary.getString(Vocabulary.Keys.ImageLayout));
-        final NumberFormat nf = 
NumberFormat.getIntegerInstance(vocabulary.getLocale());
-        final FieldPosition pos = new FieldPosition(0);
-        final StringBuffer buffer = new StringBuffer();
+        final var nf = NumberFormat.getIntegerInstance(vocabulary.getLocale());
+        final var pos = new FieldPosition(0);
+        final var buffer = new StringBuffer();
 write:  for (int item=0; ; item++) try {
             switch (item) {
                 case 0: {
diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/ReshapedImage.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/ReshapedImage.java
similarity index 87%
rename from 
endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/ReshapedImage.java
rename to 
endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/ReshapedImage.java
index 2091cd364a..f131176aae 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/ReshapedImage.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/ReshapedImage.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.sis.coverage.grid;
+package org.apache.sis.image.privy;
 
 import java.util.Vector;
 import java.util.Objects;
@@ -35,18 +35,18 @@ import org.apache.sis.image.PlanarImage;
 
 /**
  * A view over another image with the origin relocated to a new position.
- * Only the pixel coordinates are changed; the tile indices stay the same.
+ * Only the pixel coordinates are changed, the tile indices stay the same.
  * However, the image view may expose less tiles than the wrapped image.
  * This wrapper does not change image size otherwise than by an integer number 
of tiles.
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
  */
-final class ReshapedImage extends PlanarImage {
+public final class ReshapedImage extends PlanarImage {
     /**
      * The image to translate.
      */
-    final RenderedImage source;
+    public final RenderedImage source;
 
     /**
      * Value to add for converting a column index from the coordinate system 
of the wrapped image
@@ -79,6 +79,33 @@ final class ReshapedImage extends PlanarImage {
      */
     private final int minTileX, minTileY;
 
+    /**
+     * Creates an image with the data of the given image translated by the 
given amount.
+     * The number of tiles and their indexes are unchanged.
+     *
+     * @param  source  the image to translate.
+     * @param  tx      the translation to apply on <var>x</var> coordinates.
+     * @param  ty      the translation to apply on <var>y</var> coordinates.
+     * @throws ArithmeticException if image indices would overflow 32-bits 
integer capacity.
+     */
+    public ReshapedImage(RenderedImage source, long tx, long ty) {
+        while (source instanceof ReshapedImage) {
+            final var r = (ReshapedImage) source;
+            tx = addExact(r.offsetX, tx);
+            ty = addExact(r.offsetY, ty);
+            source = r.source;
+        }
+        this.source = source;
+        offsetX  = toIntExact(tx);
+        offsetY  = toIntExact(ty);
+        minX     = toIntExact(tx + source.getMinX());
+        minY     = toIntExact(ty + source.getMinY());
+        width    = source.getWidth();
+        height   = source.getHeight();
+        minTileX = source.getMinTileX();
+        minTileY = source.getMinTileY();
+    }
+
     /**
      * Creates a new image with the same data as the given image but located 
at different coordinates.
      * In addition, this constructor can reduce the number of tiles.
@@ -88,9 +115,9 @@ final class ReshapedImage extends PlanarImage {
      * @param  ymin    minimal <var>y</var> coordinate of the requested 
region, inclusive.
      * @param  xmax    maximal <var>x</var> coordinate of the requested 
region, inclusive.
      * @param  ymax    maximal <var>y</var> coordinate of the requested 
region, inclusive.
-     * @throws ArithmeticException if image indices would overflow 32 bits 
integer capacity.
+     * @throws ArithmeticException if image indices would overflow 32-bits 
integer capacity.
      */
-    ReshapedImage(final RenderedImage source, final long xmin, final long 
ymin, final long xmax, final long ymax) {
+    public ReshapedImage(final RenderedImage source, final long xmin, final 
long ymin, final long xmax, final long ymax) {
         this.source = source;
         /*
          * Compute indices of all tiles to retain in this image. All local 
fields are `long` in order to force
@@ -106,14 +133,14 @@ final class ReshapedImage extends PlanarImage {
         final long th     = source.getTileHeight();
         final long xo     = source.getTileGridXOffset();
         final long yo     = source.getTileGridYOffset();
-        final long minTX  = floorDiv(max(lowerX, xmin) - xo, tw);   // Indices 
of the first tile to retain.
-        final long minTY  = floorDiv(max(lowerY, ymin) - yo, th);
-        final long maxTX  = floorDiv(min(upperX, xmax) - xo, tw);   // Indices 
of the last tile to retain (inclusive).
-        final long maxTY  = floorDiv(min(upperY, ymax) - yo, th);
+        final long minTX  = floorDiv(max(xmin, lowerX)   - xo, tw);   // 
Indices of the first tile to retain.
+        final long minTY  = floorDiv(max(ymin, lowerY)   - yo, th);
+        final long maxTX  = floorDiv(min(xmax, upperX-1) - xo, tw);   // 
Indices of the last tile to retain (inclusive).
+        final long maxTY  = floorDiv(min(ymax, upperY-1) - yo, th);
         /*
          * Coordinates in source image of the first pixel to show in this 
relocated image.
          * They are the coordinates of the upper-left corner of the first tile 
to retain,
-         * clamped to image bounds if needed. This is not yet coordinates of 
this image.
+         * clamped to image bounds if needed. This is not yet the coordinates 
of this image.
          */
         final long sx = max(lowerX, minTX * tw + xo);
         final long sy = max(lowerY, minTY * th + yo);
@@ -137,7 +164,7 @@ final class ReshapedImage extends PlanarImage {
     /**
      * Returns {@code true} if this image does not move and does not subset 
the wrapped image.
      */
-    final boolean isIdentity() {
+    public boolean isIdentity() {
         // The use of >= is a paranoiac check, but the > case should never 
happen actually.
         return offsetX == 0 && offsetY == 0 && width >= source.getWidth() && 
height >= source.getHeight();
     }
diff --git 
a/endorsed/src/org.apache.sis.feature/test/org/apache/sis/coverage/grid/ResampledGridCoverageTest.java
 
b/endorsed/src/org.apache.sis.feature/test/org/apache/sis/coverage/grid/ResampledGridCoverageTest.java
index 7fbf205b5f..f0530b7ddb 100644
--- 
a/endorsed/src/org.apache.sis.feature/test/org/apache/sis/coverage/grid/ResampledGridCoverageTest.java
+++ 
b/endorsed/src/org.apache.sis.feature/test/org/apache/sis/coverage/grid/ResampledGridCoverageTest.java
@@ -37,6 +37,7 @@ import org.apache.sis.geometry.DirectPosition2D;
 import org.apache.sis.geometry.ImmutableEnvelope;
 import org.apache.sis.image.Interpolation;
 import org.apache.sis.image.privy.TiledImage;
+import org.apache.sis.image.privy.ReshapedImage;
 import org.apache.sis.referencing.CommonCRS;
 import org.apache.sis.referencing.privy.Formulas;
 import org.apache.sis.referencing.privy.AffineTransform2D;
diff --git 
a/endorsed/src/org.apache.sis.feature/test/org/apache/sis/coverage/grid/ReshapedImageTest.java
 
b/endorsed/src/org.apache.sis.feature/test/org/apache/sis/image/privy/ReshapedImageTest.java
similarity index 94%
rename from 
endorsed/src/org.apache.sis.feature/test/org/apache/sis/coverage/grid/ReshapedImageTest.java
rename to 
endorsed/src/org.apache.sis.feature/test/org/apache/sis/image/privy/ReshapedImageTest.java
index 6bc4c17ba0..c2aa208379 100644
--- 
a/endorsed/src/org.apache.sis.feature/test/org/apache/sis/coverage/grid/ReshapedImageTest.java
+++ 
b/endorsed/src/org.apache.sis.feature/test/org/apache/sis/image/privy/ReshapedImageTest.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.sis.coverage.grid;
+package org.apache.sis.image.privy;
 
 import java.util.Random;
 import java.awt.image.DataBuffer;
@@ -145,7 +145,7 @@ public final class ReshapedImageTest extends TestCase {
      */
     @Test
     public void testMultiTiles() {
-        final Random random = 
TestUtilities.createRandomNumberGenerator(219970242558564L);
+        final Random random = TestUtilities.createRandomNumberGenerator();
         final int dataMinX, dataMinY;
         dataMinX  = random.nextInt(20) - 10;
         dataMinY  = random.nextInt(20) - 10;
@@ -155,9 +155,9 @@ public final class ReshapedImageTest extends TestCase {
         numYTiles = 4;
         width     = numXTiles * TILE_WIDTH;
         height    = numYTiles * TILE_HEIGHT;
-        final TiledImageMock data = new TiledImageMock(DataBuffer.TYPE_USHORT, 
1, dataMinX, dataMinY,
-                                        width, height, TILE_WIDTH, 
TILE_HEIGHT, minTileX, minTileY,
-                                        random.nextBoolean());  // Banded or 
interleaved sample model
+        final var data = new TiledImageMock(DataBuffer.TYPE_USHORT, 1, 
dataMinX, dataMinY,
+                width, height, TILE_WIDTH, TILE_HEIGHT, minTileX, minTileY,
+                random.nextBoolean());  // Banded or interleaved sample model
         data.validate();
         data.initializeAllTiles(0);
         /*
@@ -165,7 +165,7 @@ public final class ReshapedImageTest extends TestCase {
          */
         tileXOffset = (minX =  7) - minTileX * TILE_WIDTH;
         tileYOffset = (minY = 13) - minTileY * TILE_HEIGHT;
-        ReshapedImage image = new ReshapedImage(data, dataMinX - 7, dataMinY - 
13, 100, 100);
+        var image = new ReshapedImage(data, dataMinX - 7, dataMinY - 13, 100, 
100);
         verifyLayout(image);
         assertValuesEqual(image.getData(), 0, new int[][] {
             { 100,  101,  102  ,   200,  201,  202  ,   300,  301,  302  ,   
400,  401,  402  ,   500,  501,  502},

Reply via email to