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