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


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new 4e676ada33 Bug fix: need to take subsampling in account when computing 
the destination region.
4e676ada33 is described below

commit 4e676ada331f7d6e006cba18f719325dbe3f0e9d
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Sun Sep 15 19:19:38 2024 +0200

    Bug fix: need to take subsampling in account when computing the destination 
region.
---
 .../org/apache/sis/storage/geotiff/DataSubset.java |  2 +-
 .../apache/sis/storage/base/TiledGridCoverage.java | 41 ++++++++++++++++------
 .../org/apache/sis/storage/gdal/TiledCoverage.java | 14 ++++----
 .../org/apache/sis/storage/gdal/TiledResource.java |  3 +-
 4 files changed, 42 insertions(+), 18 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DataSubset.java
 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DataSubset.java
index b1e5ca3be0..668cb11692 100644
--- 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DataSubset.java
+++ 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DataSubset.java
@@ -378,7 +378,7 @@ class DataSubset extends TiledGridCoverage implements 
Localized {
                 try (Closeable finisher  = createInflater()) {
                     for (int i=0; i<numMissings; i++) {
                         final Tile tile = missings[i];
-                        if (tile.getRegionInsideTile(lower, upper, 
subsampling, BIDIMENSIONAL)) {
+                        if (tile.getRegionInsideTile(lower, upper, 
subsampling, false)) {
                             origin.x = tile.originX;
                             origin.y = tile.originY;
                             tile.copyTileInfo(tileOffsets,    offsets,    
includedBanks, numTiles);
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/TiledGridCoverage.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/TiledGridCoverage.java
index c54f888654..eccfd9f5c5 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/TiledGridCoverage.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/TiledGridCoverage.java
@@ -663,19 +663,27 @@ public abstract class TiledGridCoverage extends 
GridCoverage {
         }
 
         /**
-         * Returns the coordinates of the pixels to read <em>inside</em> the 
tile, ignoring subsampling.
+         * Returns the coordinates of the pixels to read <em>inside</em> the 
tile.
          * The tile upper-left corner is assumed (0,0). Therefore, the lower 
coordinates computed by this
          * method are usually (0,0) and the rectangle size is usually the tile 
size, but those values may
          * be different if the enclosing {@link TiledGridCoverage} contains 
only one (potentially big) tile.
          * The rectangle may also be smaller when reading tiles on the last 
row or column of the tile matrix.
          *
+         * <p>If the {@code subsampled} argument is {@code false}, then this 
method returns coordinates
+         * relative to the tile in the originating {@link TiledGridResource}, 
i.e. without subsampling.
+         * If {@code subsampled} is {@code true}, then this method returns 
coordinates relative to the
+         * {@linkplain #createRaster() raster}, i.e. with {@linkplain 
#getSubsampling(int) subsampling}.
+         * Note that the {@linkplain Raster#getMinX() raster origin} still 
needs to be added to the
+         * {@linkplain Rectangle#getLocation() rectangle location} for 
obtaining coordinates in the raster space.</p>
+         *
+         * @param  subsampled  whether to return coordinates with subsampling 
applied.
          * @return pixel to read inside the tile, or {@code null} if the 
region is empty.
          * @throws ArithmeticException if the tile coordinates overflow 32 
bits integer capacity.
          */
-        public Rectangle getRegionInsideTile() {
+        public Rectangle getRegionInsideTile(final boolean subsampled) {
             final long[] lower = new long[BIDIMENSIONAL];
             final long[] upper = new long[BIDIMENSIONAL];
-            if (getRegionInsideTile(lower, upper, null, BIDIMENSIONAL)) {
+            if (getRegionInsideTile(lower, upper, null, subsampled)) {
                 return new Rectangle(
                         toIntExact(lower[X_DIMENSION]),
                         toIntExact(lower[Y_DIMENSION]),
@@ -686,7 +694,7 @@ public abstract class TiledGridCoverage extends 
GridCoverage {
         }
 
         /**
-         * Returns the coordinates of the pixels to read <em>inside</em> the 
tile, ignoring subsampling.
+         * Returns the coordinates of the pixels to read <em>inside</em> the 
tile.
          * The tile upper-left corner is assumed (0,0). Therefore, the lower 
coordinates computed by this
          * method are usually (0,0) and the upper coordinates are usually the 
tile size, but those values
          * may be different if the enclosing {@link TiledGridCoverage} 
contains only one (potentially big) tile.
@@ -697,15 +705,23 @@ public abstract class TiledGridCoverage extends 
GridCoverage {
          * but is constant for all tiles regardless the subregion to read.
          * The same values can be obtained by {@link #getSubsampling(int)}.</p>
          *
-         * <p>This method is a generalization of {@link 
#getRegionInsideTile()} to any number of dimensions.</p>
+         * <p>If the {@code subsampled} argument is {@code false}, then this 
method returns coordinates
+         * relative to the tile in the originating {@link TiledGridResource}, 
i.e. without subsampling.
+         * If {@code subsampled} is {@code true}, then this method returns 
coordinates relative to the
+         * tile resulting from the read operation, i.e. with {@linkplain 
#getSubsampling(int) subsampling}.</p>
+         *
+         * <p>This method is a generalization of {@link 
#getRegionInsideTile(boolean)} to any number of dimensions.</p>
          *
          * @param  lower        a pre-allocated array where to store relative 
coordinates of the first pixel.
          * @param  upper        a pre-allocated array where to store relative 
coordinates after the last pixel.
          * @param  subsampling  a pre-allocated array where to store 
subsampling, or {@code null} if not needed.
-         * @param  dimension    number of elements to write in the {@code 
lower} and {@code upper} arrays.
+         * @param  subsampled   whether to return coordinates with subsampling 
applied.
          * @return {@code true} on success, or {@code false} if the tile is 
empty.
          */
-        public boolean getRegionInsideTile(final long[] lower, final long[] 
upper, final int[] subsampling, int dimension) {
+        public boolean getRegionInsideTile(final long[] lower, final long[] 
upper,
+                final int[] subsampling, final boolean subsampled)
+        {
+            int dimension = Math.min(lower.length, upper.length);
             final TiledGridCoverage coverage = getCoverage();
             if (subsampling != null) {
                 System.arraycopy(coverage.subsampling, 0, subsampling, 0, 
dimension);
@@ -749,6 +765,11 @@ public abstract class TiledGridCoverage extends 
GridCoverage {
                 if (dimension == X_DIMENSION && coverage.forceTileSize) {
                     limit = tileSize;
                 }
+                if (subsampled) {
+                    final int s = coverage.getSubsampling(dimension);
+                    offset /= s;        // Round toward 0 because we should 
not have negative coordinates.
+                    limit = (limit - 1) / s + 1;
+                }
                 lower[dimension] = offset;
                 upper[dimension] = limit;
             }
@@ -789,8 +810,8 @@ public abstract class TiledGridCoverage extends 
GridCoverage {
         private final int[] offsetAOI;
 
         /**
-         * Pixel coordinates of current iterator position relative to the Area 
Of Interest specified by user.
-         * Those coordinates are in units of the full resolution image.
+         * Cell coordinates of current iterator position relative to the Area 
Of Interest specified by user.
+         * Those coordinates are in units of the coverage at full resolution.
          * Initial position is {@link #offsetAOI} multiplied by {@link 
#subsampling}.
          * This array is modified by calls to {@link #next()}.
          */
@@ -925,7 +946,7 @@ public abstract class TiledGridCoverage extends 
GridCoverage {
              * to the next tile. The tile seems "too far", but it will either 
be discarded at a later step
              * (because of empty intersection with AOI) or compensated by the 
offset caused by subsampling.
              * At first the index values seem inconsistent, but after we 
discard the tiles where
-             * `getRegionInsideTile(…)` returns `false` they become consistent.
+             * `getRegionInsideTile(…)` returns `false`, they become 
consistent.
              */
             return toIntExact(ceilDiv(tileOffsetFull[dimension], 
getSubsampling(dimension)));
         }
diff --git 
a/incubator/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/TiledCoverage.java
 
b/incubator/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/TiledCoverage.java
index e4eccc4ec2..733e42d4aa 100644
--- 
a/incubator/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/TiledCoverage.java
+++ 
b/incubator/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/TiledCoverage.java
@@ -86,12 +86,14 @@ final class TiledCoverage extends TiledGridCoverage {
                 final MemorySegment transferBuffer = 
arena.allocate(getTileLength());
                 do {
                     final WritableRaster tile = iterator.createRaster();
-                    final Rectangle target = iterator.getRegionInsideTile();
-                    target.x = Math.addExact(target.x, tile.getMinX());
-                    target.y = Math.addExact(target.y, tile.getMinY());
-                    final Rectangle source = 
pixelToResourceCoordinates(target);
-                    if (!Band.transfer(gdal, OpenFlag.READ, bands, 
owner.dataType, source, tile, target, transferBuffer)) {
-                        break;      // Exception will be thrown by 
`throwOnFailure(…)`
+                    final Rectangle target = 
iterator.getRegionInsideTile(true);
+                    if (target != null) {
+                        target.x = Math.addExact(target.x, tile.getMinX());
+                        target.y = Math.addExact(target.y, tile.getMinY());
+                        final Rectangle source = 
pixelToResourceCoordinates(target);
+                        if (!Band.transfer(gdal, OpenFlag.READ, bands, 
owner.dataType, source, tile, target, transferBuffer)) {
+                            break;      // Exception will be thrown by 
`throwOnFailure(…)`
+                        }
                     }
                     result[iterator.getTileIndexInResultArray()] = tile;
                 } while (iterator.next());
diff --git 
a/incubator/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/TiledResource.java
 
b/incubator/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/TiledResource.java
index 0c9d7fa60f..dc9316db6f 100644
--- 
a/incubator/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/TiledResource.java
+++ 
b/incubator/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/TiledResource.java
@@ -231,6 +231,7 @@ final class TiledResource extends TiledGridResource {
             var name = Vocabulary.formatInternational(Vocabulary.Keys.Image_1, 
count + 1);
             rasters[count++] = new TiledResource(parent, entry.getKey(), 
entry.getValue(), name);
         }
+        // Search for the main image and, if found, move it first.
         for (int i=0; i<count; i++) {
             final TiledResource main = rasters[i];
             if (main.width == mainWidth && main.height == mainHeight) {
@@ -432,7 +433,7 @@ final class TiledResource extends TiledGridResource {
             final double max = band.getValue(gdal.getRasterMaximum, 
MemorySegment.NULL);
             colorModel = ColorModelFactory.createGrayScale(dataType.imageType, 
selectedBands.length, gray, min, max);
         }
-        sampleModel = new BandedSampleModel(dataType.imageType, width, height, 
selectedBands.length);
+        sampleModel = new BandedSampleModel(dataType.imageType, tileWidth, 
tileHeight, selectedBands.length);
         selectedBandIndices = bandIndices;
     }
 

Reply via email to