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

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

commit f6e6c072f0606b89675cde7bc2cf4bad1e51a4f1
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Mon Aug 10 12:41:22 2026 +0200

    Add a "todo" note about the use of `prefetch` in context of artificially 
tiled image.
    Minor edition as a side-effect of the review of the situation regarding 
prefetch.
---
 .../org/apache/sis/image/BandedSampleConverter.java |  6 +++---
 .../main/org/apache/sis/image/ComputedImage.java    |  4 ++--
 .../main/org/apache/sis/image/ImageOverlay.java     |  2 +-
 .../org/apache/sis/image/MultiSourcePrefetch.java   |  5 +++--
 .../main/org/apache/sis/image/PlanarImage.java      |  2 ++
 .../main/org/apache/sis/image/PrefetchedImage.java  |  4 ++--
 .../org/apache/sis/image/SourceAlignedImage.java    |  2 +-
 .../image/internal/shared/BatchComputedImage.java   | 21 +++++++++++++++++++--
 .../sis/storage/tiling/ArtificiallyTiledImage.java  | 13 ++++++++++---
 .../storage/tiling/TiledGridCoverageResource.java   |  2 +-
 10 files changed, 44 insertions(+), 17 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/BandedSampleConverter.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/BandedSampleConverter.java
index 9cf90055f5..8a4270ad36 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/BandedSampleConverter.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/BandedSampleConverter.java
@@ -454,10 +454,10 @@ class BandedSampleConverter extends WritableComputedImage 
{
         @Override
         public void setData(final Raster data) {
             final Rectangle bounds = data.getBounds();
-            final WritableRenderedImage target = (WritableRenderedImage) 
getSource();
+            final var target = (WritableRenderedImage) getSource();
             ImageUtilities.clipBounds(target, bounds);
             if (!bounds.isEmpty()) {
-                final TileOpExecutor executor = new TileOpExecutor(target, 
bounds) {
+                final var executor = new TileOpExecutor(target, bounds) {
                     @Override protected void writeTo(final WritableRaster 
target) throws TransformException {
                         final Rectangle aoi = 
target.getBounds().intersection(bounds);
                         Transferer.create(data, target, aoi).compute(inverses);
@@ -506,7 +506,7 @@ class BandedSampleConverter extends WritableComputedImage {
     @Override
     public boolean equals(final Object object) {
         if (equalsBase(object)) {
-            final BandedSampleConverter other = (BandedSampleConverter) object;
+            final var other = (BandedSampleConverter) object;
             return Arrays .equals(converters, other.converters) &&
                    Objects.equals(colorModel, other.colorModel) &&
                    Arrays .equals(sampleResolutions, other.sampleResolutions);
diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/ComputedImage.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/ComputedImage.java
index 7d6ec91caa..986e9b6e98 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/ComputedImage.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/ComputedImage.java
@@ -593,9 +593,9 @@ public abstract class ComputedImage extends PlanarImage 
implements Disposable {
     }
 
     /**
-     * Notifies this image that tiles will be computed soon in the given 
region.
+     * Notifies this image that tiles will be computed soon for the given tile 
indices.
      * This method is invoked by {@link ImageProcessor#prefetch(RenderedImage, 
Rectangle)}
-     * before to request (potentially in multi-threads) all tiles in the area 
of interest.
+     * before to request (potentially in multi-threads) tiles at the specified 
indices.
      * If the returned {@code Disposable} is non-null, {@code ImageProcessor} 
guarantees
      * that the {@link Disposable#dispose()} method will be invoked after the 
prefetch
      * operation completed, successfully or not.
diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/ImageOverlay.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/ImageOverlay.java
index 3c7253e944..29b718e84e 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/ImageOverlay.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/ImageOverlay.java
@@ -399,7 +399,7 @@ final class ImageOverlay extends MultiSourceImage {
      */
     @Override
     protected Raster computeTile(final int tileX, final int tileY, 
WritableRaster target) {
-        final Rectangle aoi = new Rectangle(
+        final var aoi = new Rectangle(
                 ImageUtilities.tileToPixelX(this, tileX),
                 ImageUtilities.tileToPixelY(this, tileY),
                 getTileWidth(),
diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/MultiSourcePrefetch.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/MultiSourcePrefetch.java
index 7f1452b754..d0aa7605bf 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/MultiSourcePrefetch.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/MultiSourcePrefetch.java
@@ -29,7 +29,7 @@ import org.apache.sis.image.internal.shared.ImageUtilities;
 /**
  * A helper class for forwarding a {@code prefetch(…)} operation to multiple 
sources.
  * This implementation assumes that all sources share the same pixel 
coordinates space.
- * However the tile matrix does not need to be the same.
+ * However, the tile matrix does not need to be the same.
  *
  * @author  Martin Desruisseaux (Geomatys)
  */
@@ -102,12 +102,13 @@ final class MultiSourcePrefetch implements Disposable {
      * @param  parallel  whether parallelism is allowed.
      * @return a handler for disposing resources after prefetch, or {@code 
null} if none.
      */
+    @SuppressWarnings("UseSpecificCatch")
     final Disposable run(boolean parallel) {
         switch (count) {
             case 0: return null;
             case 1: parallel = false;
         }
-        @SuppressWarnings({"unchecked","rawtypes"})
+        @SuppressWarnings({"unchecked", "rawtypes"})
         final var workers = (Future<Disposable>[]) (parallel ? new 
Future[count] : null);
         cleaners = new Disposable[count];
         for (int i=0; i<count; i++) {
diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/PlanarImage.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/PlanarImage.java
index 4cadfc431d..8c32509269 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/PlanarImage.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/PlanarImage.java
@@ -25,6 +25,7 @@ import java.awt.image.Raster;
 import java.awt.image.WritableRaster;
 import java.awt.image.WritableRenderedImage;
 import java.awt.image.RenderedImage;
+import java.awt.image.ImagingOpException;
 import java.util.Objects;
 import java.util.Vector;
 import java.util.function.DoubleUnaryOperator;
@@ -633,6 +634,7 @@ public abstract class PlanarImage implements RenderedImage {
      * @param  tiles  indices of the tiles which will be prefetched.
      * @return handler on which to invoke {@code dispose()} after the prefetch 
operation
      *         completed (successfully or not), or {@code null} if none.
+     * @throws ImagingOpException if an error occurred while preparing tile 
computation.
      */
     Disposable prefetch(Rectangle tiles) {
         return null;
diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/PrefetchedImage.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/PrefetchedImage.java
index ee5ac4274e..b8b05b7b10 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/PrefetchedImage.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/PrefetchedImage.java
@@ -35,7 +35,7 @@ import org.apache.sis.util.resources.Errors;
 
 
 /**
- * An image which delegate all tile requests to another image except for some 
tiles that are fetched in advance.
+ * An image which delegates all tile requests to another image except for some 
tiles that are fetched in advance.
  * This image has the same coordinate systems as the source image.
  *
  * @author  Martin Desruisseaux (Geomatys)
@@ -108,7 +108,7 @@ final class PrefetchedImage extends PlanarImage implements 
TileErrorHandler.Exec
                 return;
             }
         }
-        final Worker worker = new Worker(source, areaOfInterest);
+        final var worker = new Worker(source, areaOfInterest);
         final Rectangle ti = worker.getTileIndices();
         minTileX  = ti.x;
         minTileY  = ti.y;
diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/SourceAlignedImage.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/SourceAlignedImage.java
index 96c778b03d..21265e35e1 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/SourceAlignedImage.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/SourceAlignedImage.java
@@ -199,7 +199,7 @@ abstract class SourceAlignedImage extends ComputedImage {
     /**
      * Notifies the source image that tiles will be computed soon in the given 
region.
      * If the source image is an instance of {@link PlanarImage}, then this 
method
-     * forwards the notification to it. Otherwise default implementation does 
nothing.
+     * forwards the notification to it. Otherwise, the default implementation 
does nothing.
      */
     @Override
     protected Disposable prefetch(final Rectangle tiles) {
diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/internal/shared/BatchComputedImage.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/internal/shared/BatchComputedImage.java
index 07aa6ae592..8b24a29c5c 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/internal/shared/BatchComputedImage.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/internal/shared/BatchComputedImage.java
@@ -38,6 +38,9 @@ import org.apache.sis.util.resources.Errors;
  * Implementations should manage their own cache for avoiding to compute the 
same tiles many times.
  * The caching mechanism inherited from {@link ComputedImage} is less useful 
here.
  *
+ * @todo Consider moving as a public class in {@link 
org.apache.sis.image.internal}
+ *       for leveraging {@code MultiSourcePrefetch}.
+ *
  * @author  Martin Desruisseaux (Geomatys)
  */
 public abstract class BatchComputedImage extends ComputedImage {
@@ -76,6 +79,13 @@ public abstract class BatchComputedImage extends 
ComputedImage {
             this.tiles = tiles;
         }
 
+        /**
+         * Tests whether this set of tiles contains the given set.
+         */
+        final boolean contains(final Rectangle other) {
+            return new Rectangle(x, y, width, height).contains(other);
+        }
+
         /** Discards this set of tiles. */
         @Override public void dispose() {
             remove(this);
@@ -179,7 +189,14 @@ public abstract class BatchComputedImage extends 
ComputedImage {
      * @throws ImagingOpException if an error occurred while preparing tile 
computation.
      */
     @Override
-    protected Disposable prefetch(final Rectangle region) {
+    public Disposable prefetch(final Rectangle region) {
+        synchronized (this) {
+            for (Rasters r = prefetched; r != null; r = r.next) {
+                if (r.contains(region)) {
+                    return null;    // Already prefetched.
+                }
+            }
+        }
         final Raster[] tiles;
         try {
             tiles = computeTiles(region);
@@ -188,7 +205,7 @@ public abstract class BatchComputedImage extends 
ComputedImage {
         } catch (Exception e) {
             throw (ImagingOpException) new 
ImagingOpException(e.getMessage()).initCause(e);
         }
-        final Rasters r = new Rasters(region, tiles);
+        final var r = new Rasters(region, tiles);
         synchronized (this) {
             r.next = prefetched;
             prefetched = r;
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/ArtificiallyTiledImage.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/ArtificiallyTiledImage.java
index ba659a2afb..1f6ad12f91 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/ArtificiallyTiledImage.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/ArtificiallyTiledImage.java
@@ -152,11 +152,13 @@ final class ArtificiallyTiledImage extends 
BatchComputedImage {
         int minTileY = Integer.MAX_VALUE;
         int maxTileX = Integer.MIN_VALUE;
         int maxTileY = Integer.MIN_VALUE;
+        final int tilex0    = tiles.x;      // Tile index of the raster at 
index 0 in the returned array.
+        final int tileY0    = tiles.y;
         final int numXTiles = tiles.width;
         final var rasters = new Raster[Math.multiplyExact(numXTiles, 
tiles.height)];
         for (int i = 0; i < rasters.length; i++) {
-            final int x = tiles.x + i % numXTiles;
-            final int y = tiles.y + i / numXTiles;
+            final int x = tilex0 + i % numXTiles;
+            final int y = tileY0 + i / numXTiles;
             if ((rasters[i] = cache.get(new Point(x, y))) == null) {
                 if (x < minTileX) minTileX = x;
                 if (x > maxTileX) maxTileX = x;
@@ -195,6 +197,11 @@ final class ArtificiallyTiledImage extends 
BatchComputedImage {
              * Then, the requested extent is converted to the coverage grid 
coordinate system.
              * Because this is also expected to be an identity operation or at 
most a translation,
              * the rounding more is set to `NEAREST` instead of `ENCLOSING`.
+             *
+             * TODO: we use `RasterLoadingStrategy.AT_GET_TILE_TIME` because 
we don't know if we are going
+             * to use all requested tiles (because the cache in this class may 
make some reading unnecessary).
+             * We should do something more advanced, with a mask (potentially 
made of many rectangles) of the
+             * tiles that we really need to read.
              */
             final GridGeometry request  = domain.relocate(extent.reshape(low, 
high, true));
             final GridCoverage coverage = source.readAtGetTileTime(request, 
requestedBands);
@@ -207,7 +214,7 @@ final class ArtificiallyTiledImage extends 
BatchComputedImage {
             for (int y = minTileY; y <= maxTileY; y++) {
                 for (int x = minTileX; x <= maxTileX; x++) {
                     // No integer arithmetic can overflow in this loop.
-                    final int i = (y - tiles.y) * numXTiles + (x - tiles.x);
+                    final int i = (y - tileY0) * numXTiles + (x - tilex0);
                     if (rasters[i] == null) {
                         rasters[i] = cache.computeIfAbsent(new Point(x, y), 
(key) -> {
                             final int tileWidth  = sampleModel.getWidth();
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverageResource.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverageResource.java
index 7d9655bd5a..c5be80aebe 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverageResource.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverageResource.java
@@ -872,7 +872,7 @@ check:  if (dataType.isInteger()) {
                     if (virtualSize / stride > ImageLayout.MAX_TILE_SIZE) {
                         // Tile is too large, even after subsampling.
                         if (i == xDimension || i == yDimension) {
-                            applyArtificialTiling |= !loadAtReadTime;
+                            applyArtificialTiling = !loadAtReadTime;
                         }
                     }
                     virtualTileSize[i] = virtualSize;

Reply via email to