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 2358b982a043579d645ca8f6fce4fbd17b8bffd4 Author: Martin Desruisseaux <[email protected]> AuthorDate: Thu Feb 12 15:27:12 2026 +0100 Replace `X_DIMENSION` and `Y_DIMENSION` constant by configurable fields. The intend it to reduce the risk of breaking API compatibility in future evolutions. --- .../sis/storage/geotiff/CompressedSubset.java | 12 +- .../org/apache/sis/storage/geotiff/DataCube.java | 2 +- .../org/apache/sis/storage/geotiff/DataSubset.java | 12 +- .../sis/storage/tiling/TiledDeferredImage.java | 12 +- .../sis/storage/tiling/TiledGridCoverage.java | 138 +++++++++++++-------- .../sis/storage/tiling/TiledGridResource.java | 74 +++++++++-- 6 files changed, 171 insertions(+), 79 deletions(-) diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/CompressedSubset.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/CompressedSubset.java index 72c93d2e25..48750c39b0 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/CompressedSubset.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/CompressedSubset.java @@ -102,7 +102,7 @@ final class CompressedSubset extends DataSubset { CompressedSubset(final DataCube source, final TiledGridResource.Subset subset) throws DataStoreException { super(source, subset); long afterLastBand = sourceScanlineStride - sourcePixelStride; - final int between = Math.multiplyExact(sourcePixelStride, Math.toIntExact(getSubsampling(X_DIMENSION) - 1)); + final int between = Math.multiplyExact(sourcePixelStride, Math.toIntExact(getSubsampling(xDimension) - 1)); if (includedBands != null && sourcePixelStride > 1) { final int[] skips = new int[includedBands.length]; final int m = skips.length - 1; @@ -184,12 +184,12 @@ final class CompressedSubset extends DataSubset { final long[] subsampling, final Point location) throws IOException, DataStoreException { final DataType dataType = getDataType(); - final int width = pixelCount(lower, upper, subsampling, X_DIMENSION); - final int height = pixelCount(lower, upper, subsampling, Y_DIMENSION); + final int width = pixelCount(lower, upper, subsampling, xDimension); + final int height = pixelCount(lower, upper, subsampling, yDimension); final int chunksPerRow = width * (targetPixelStride / samplesPerChunk); final int betweenRows = Math.toIntExact(subsampling[1] - 1); - final long head = beforeFirstBand + sourcePixelStride * (lower[X_DIMENSION]); - final long tail = afterLastBand - sourcePixelStride * (lower[X_DIMENSION] + (width-1)*subsampling[X_DIMENSION]); + final long head = beforeFirstBand + sourcePixelStride * (lower[xDimension]); + final long tail = afterLastBand - sourcePixelStride * (lower[xDimension] + (width-1)*subsampling[xDimension]); /* * `head` and `tail` are the number of sample values to skip at the beginning and end of each row. * `betweenPixels` is the number of sample values to skip between each pixel, but the actual skips @@ -211,7 +211,7 @@ final class CompressedSubset extends DataSubset { source.getCompression(), // The compression method. source.getPredictor(), // The mathematical operator to apply after decompression. sourcePixelStride, // Number of sample values per pixel in the source image. - toIntExact(getTileSize(X_DIMENSION)), // Number of pixels in a row of source image. + toIntExact(getTileSize(xDimension)), // Number of pixels in a row of source image. chunksPerRow, // Number of pixels per row in target image. samplesPerChunk, // Number of sample values per pixel. skipAfterChunks, // Number of sample values to skip between pixels. diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DataCube.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DataCube.java index c5ec2f001e..d9fd5c52e5 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DataCube.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DataCube.java @@ -197,7 +197,7 @@ abstract class DataCube extends TiledGridResource implements StoreResource { */ @Override protected final boolean canReadTruncatedTiles(int dim, boolean suggested) { - return suggested | (dim >= 1); // Y_DIMENSION. + return suggested | (dim >= 1); // yDimension = 1. } /** 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 943f67d9dd..1923a65834 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 @@ -512,8 +512,8 @@ class DataSubset extends TiledGridCoverage implements Localized { { final DataType type = getDataType(); final int sampleSize = type.size(); // Assumed same as `SampleModel.getSampleSize(…)` by preconditions. - final long width = subtractExact(upper[X_DIMENSION], lower[X_DIMENSION]); - final long height = subtractExact(upper[Y_DIMENSION], lower[Y_DIMENSION]); + final long width = subtractExact(upper[xDimension], lower[xDimension]); + final long height = subtractExact(upper[yDimension], lower[yDimension]); /* * The number of bytes to read should not be greater than `byteCount`. It may be smaller however if only * a subregion is read. Note that the `length` value may be different than `capacity` if the tile to read @@ -521,15 +521,15 @@ class DataSubset extends TiledGridCoverage implements Localized { * This length is used only for verification purpose so it does not need to be exact. */ final long length = ceilDiv(width * height * sourcePixelStride * sampleSize, Byte.SIZE); - final long[] size = new long[] {sourceScanlineStride, getTileSize(Y_DIMENSION)}; + final long[] size = new long[] {sourceScanlineStride, getTileSize(yDimension)}; /* * If we use an interleaved sample model, each "element" from `HyperRectangleReader` perspective is actually a * group of `sourcePixelStride` values. Note that in such case, we cannot handle subsampling on the first axis. * Such case should be handled by the `CompressedSubset` subclass instead, even if there is no compression. */ - assert sourcePixelStride == 1 || subsampling[X_DIMENSION] == 1; - lower[X_DIMENSION] *= sourcePixelStride; - upper[X_DIMENSION] *= sourcePixelStride; + assert sourcePixelStride == 1 || subsampling[xDimension] == 1; + lower[xDimension] *= sourcePixelStride; + upper[xDimension] *= sourcePixelStride; /* * Read each plane ("banks" in Java2D terminology). Note that a single bank contains all bands * in the interleaved sample model case. This block assumes that each bank element contains diff --git a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledDeferredImage.java b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledDeferredImage.java index 50812101ee..c8936935d1 100644 --- a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledDeferredImage.java +++ b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledDeferredImage.java @@ -61,10 +61,10 @@ final class TiledDeferredImage extends BatchComputedImage { final TiledGridCoverage.TileIterator iterator) { super(iterator.getCoverage().model, properties); - this.width = imageSize[TiledGridCoverage.X_DIMENSION]; - this.height = imageSize[TiledGridCoverage.Y_DIMENSION]; - this.minTileX = tileLower[TiledGridCoverage.X_DIMENSION]; - this.minTileY = tileLower[TiledGridCoverage.Y_DIMENSION]; + this.width = imageSize[iterator.xDimension]; + this.height = imageSize[iterator.yDimension]; + this.minTileX = tileLower[iterator.xDimension]; + this.minTileY = tileLower[iterator.yDimension]; this.iterator = iterator; } @@ -75,12 +75,12 @@ final class TiledDeferredImage extends BatchComputedImage { /** Returns the minimum <var>x</var> coordinate (inclusive) of this image. */ @Override public final int getMinX() { - return iterator.getTileOrigin(TiledGridCoverage.X_DIMENSION); + return iterator.getTileOrigin(iterator.xDimension); } /** Returns the minimum <var>y</var> coordinate (inclusive) of this image. */ @Override public final int getMinY() { - return iterator.getTileOrigin(TiledGridCoverage.Y_DIMENSION); + return iterator.getTileOrigin(iterator.yDimension); } /** Returns the number of pixels along X axis in the whole rendered image. */ diff --git a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverage.java b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverage.java index 06498ac4d7..44f0bae9eb 100644 --- a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverage.java +++ b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverage.java @@ -81,12 +81,6 @@ import org.opengis.coordinate.MismatchedDimensionException; * @since 1.7 */ public abstract class TiledGridCoverage extends GridCoverage { - /** - * The dimensions of <var>x</var> and <var>y</var> axes. - * Static constants for now, may become configurable fields in the future. - */ - protected static final int X_DIMENSION = 0, Y_DIMENSION = 1; - /** * The area to read in unit of the full coverage (without subsampling). * This is the intersection between user-specified domain and the source @@ -209,6 +203,26 @@ public abstract class TiledGridCoverage extends GridCoverage { */ protected final int[] includedBands; + /** + * The dimension of the grid which is mapped to the <var>x</var> axis (column indexes) in rendered images. + * This is the value of the {@code xDimension} argument in the last call to the + * {@link TiledGridResource#setRasterDimension(int, int)} method before this coverage has been constructed. + * This value is usually 0. + * + * @see #readTiles(TileIterator) + */ + protected final int xDimension; + + /** + * The dimension of the grid which is mapped to the <var>y</var> axis (row indexes) in rendered images. + * This is the value of the {@code yDimension} argument in the last call to the + * {@link TiledGridResource#setRasterDimension(int, int)} method before this coverage has been constructed. + * This value is usually 1. + * + * @see #readTiles(TileIterator) + */ + protected final int yDimension; + /** * Cache of rasters read by this {@code TiledGridCoverage}. This cache may be shared with other coverages * created for the same {@link TiledGridResource} resource. For each value, the raster {@code minX} and @@ -262,7 +276,8 @@ public abstract class TiledGridCoverage extends GridCoverage { */ protected TiledGridCoverage(final TiledGridResource.Subset subset) { super(subset.domain, subset.ranges); - final GridExtent extent = subset.domain.getExtent(); + xDimension = subset.xDimension(); + yDimension = subset.yDimension(); deferredTileReading = subset.deferredTileReading(); // May be shorter than other arrays or the grid geometry. readExtent = subset.readExtent; subsampling = subset.subsampling; @@ -274,7 +289,7 @@ public abstract class TiledGridCoverage extends GridCoverage { tmcOfFirstTile = new long[dimension]; tileStrides = new int [dimension]; final int[] subSize = new int [dimension]; - + final GridExtent extent = subset.domain.getExtent(); @SuppressWarnings("LocalVariableHidesMemberVariable") long indexOfFirstTile = 0; int tileStride = 1; @@ -295,8 +310,8 @@ public abstract class TiledGridCoverage extends GridCoverage { */ @SuppressWarnings("LocalVariableHidesMemberVariable") SampleModel model = subset.modelForBandSubset; - if (model.getWidth() != subSize[X_DIMENSION] || model.getHeight() != subSize[Y_DIMENSION]) { - model = model.createCompatibleSampleModel(subSize[X_DIMENSION], subSize[Y_DIMENSION]); + if (model.getWidth() != subSize[xDimension] || model.getHeight() != subSize[yDimension]) { + model = model.createCompatibleSampleModel(subSize[xDimension], subSize[yDimension]); } this.model = model; this.colors = subset.colorsForBandSubset; @@ -484,10 +499,10 @@ public abstract class TiledGridCoverage extends GridCoverage { if (extent == null) { return null; } - return new Rectangle(toIntExact(extent.getLow (X_DIMENSION)), - toIntExact(extent.getLow (Y_DIMENSION)), - toIntExact(extent.getSize(X_DIMENSION)), - toIntExact(extent.getSize(Y_DIMENSION))); + return new Rectangle(toIntExact(extent.getLow (xDimension)), + toIntExact(extent.getLow (yDimension)), + toIntExact(extent.getSize(xDimension)), + toIntExact(extent.getSize(yDimension))); } /** @@ -512,9 +527,9 @@ public abstract class TiledGridCoverage extends GridCoverage { } } final int[] selectedDimensions = sliceExtent.getSubspaceDimensions(BIDIMENSIONAL); - if (selectedDimensions[1] != 1) { + if (selectedDimensions[0] != xDimension || selectedDimensions[1] != yDimension) { // TODO - throw new UnsupportedOperationException("Non-horizontal slices not yet implemented."); + throw new UnsupportedOperationException("Slices in arbitrary dimensions not yet implemented."); } final RenderedImage image; try { @@ -550,7 +565,7 @@ public abstract class TiledGridCoverage extends GridCoverage { * Prepare an iterator over all tiles to read, together with the following properties: * - Two-dimensional conversion from pixel coordinates to "real world" coordinates. */ - final var iterator = new TileIterator(tileLower, tileUpper, offsetAOI, dimension); + final var iterator = new TileIterator(tileLower, tileUpper, offsetAOI, dimension, xDimension, yDimension); final Map<String,Object> properties = DeferredProperty.forGridGeometry(gridGeometry, selectedDimensions); if (deferredTileReading) { image = new TiledDeferredImage(imageSize, tileLower, properties, iterator); @@ -561,8 +576,8 @@ public abstract class TiledGridCoverage extends GridCoverage { */ final Raster[] result = readTiles(iterator); image = new TiledImage(properties, colors, - imageSize[X_DIMENSION], imageSize[Y_DIMENSION], - tileLower[X_DIMENSION], tileLower[Y_DIMENSION], result); + imageSize[xDimension], imageSize[yDimension], + tileLower[xDimension], tileLower[yDimension], result); } } catch (DisjointExtentException | CannotEvaluateException e) { throw e; @@ -582,6 +597,11 @@ public abstract class TiledGridCoverage extends GridCoverage { * of the iterator position as an instant ({@link Snapshot}). */ protected static abstract class AOI { + /** + * The dimension of the <var>x</var> and <var>y</var> axes in rendered images. + */ + final int xDimension, yDimension; + /** * Tile Matrix Coordinates (TMC) relative to the enclosing {@link TiledGridCoverage}. * Tile (0,0) is the tile in the upper-left corner of this {@link TiledGridCoverage}, @@ -628,7 +648,9 @@ public abstract class TiledGridCoverage extends GridCoverage { /** * Creates a new area of interest. */ - AOI(final int[] tmcInSubset, final int[] uncroppedTileLocation) { + AOI(final int xDimension, final int yDimension, final int[] tmcInSubset, final int[] uncroppedTileLocation) { + this.xDimension = xDimension; + this.yDimension = yDimension; this.tmcInSubset = tmcInSubset; this.uncroppedTileLocation = uncroppedTileLocation; } @@ -703,8 +725,8 @@ public abstract class TiledGridCoverage extends GridCoverage { * Found a tile, but the sample model may be different because band order may be different. * In any cases, we need to make sure that the raster starts at the expected coordinates. */ - final int x = getTileOrigin(X_DIMENSION); - final int y = getTileOrigin(Y_DIMENSION); + final int x = getTileOrigin(xDimension); + final int y = getTileOrigin(yDimension); final SampleModel model = coverage.model; if (model.equals(tile.getSampleModel())) { if (tile.getMinX() == x && tile.getMinY() == y) { @@ -763,8 +785,8 @@ public abstract class TiledGridCoverage extends GridCoverage { * @return a newly created, initially empty raster. */ public WritableRaster createRaster() { - final int x = getTileOrigin(X_DIMENSION); - final int y = getTileOrigin(Y_DIMENSION); + final int x = getTileOrigin(xDimension); + final int y = getTileOrigin(yDimension); return Raster.createWritableRaster(getCoverage().model, new Point(x, y)); } @@ -781,8 +803,8 @@ public abstract class TiledGridCoverage extends GridCoverage { * @see Raster#createTranslatedChild(int, int) */ public Raster moveRaster(final Raster raster) { - final int x = getTileOrigin(X_DIMENSION); - final int y = getTileOrigin(Y_DIMENSION); + final int x = getTileOrigin(xDimension); + final int y = getTileOrigin(yDimension); if (raster.getMinX() == x && raster.getMinY() == y) { return raster; } @@ -811,8 +833,8 @@ public abstract class TiledGridCoverage extends GridCoverage { if (uncroppedTileLocation == null) { return Optional.empty(); // Usual case. } - return Optional.of(new Point(uncroppedTileLocation[X_DIMENSION], - uncroppedTileLocation[Y_DIMENSION])); + return Optional.of(new Point(uncroppedTileLocation[xDimension], + uncroppedTileLocation[yDimension])); } /** @@ -861,10 +883,10 @@ public abstract class TiledGridCoverage extends GridCoverage { final long[] upper = new long[BIDIMENSIONAL]; if (getRegionInsideTile(lower, upper, null, subsampled)) { return new Rectangle( - toIntExact(lower[X_DIMENSION]), - toIntExact(lower[Y_DIMENSION]), - toIntExact(subtractExact(upper[X_DIMENSION], lower[X_DIMENSION])), - toIntExact(subtractExact(upper[Y_DIMENSION], lower[Y_DIMENSION]))); + toIntExact(lower[xDimension]), + toIntExact(lower[yDimension]), + toIntExact(subtractExact(upper[xDimension], lower[xDimension])), + toIntExact(subtractExact(upper[yDimension], lower[yDimension]))); } return null; } @@ -1000,8 +1022,14 @@ public abstract class TiledGridCoverage extends GridCoverage { * @param offsetAOI pixel coordinates to assign to the upper-left corner of the subsampled region to render. * @param dimension number of dimension of the {@code TiledGridCoverage} grid extent. */ - TileIterator(final int[] tileLower, final int[] tileUpper, final int[] offsetAOI, final int dimension) { - super(tileLower.clone(), uncroppedTileLocation(tileLower)); + TileIterator(final int[] tileLower, + final int[] tileUpper, + final int[] offsetAOI, + final int dimension, + final int xDimension, + final int yDimension) + { + super(xDimension, yDimension, tileLower.clone(), uncroppedTileLocation(tileLower)); this.tileLower = tileLower; this.tileUpper = tileUpper; this.offsetAOI = offsetAOI; @@ -1060,7 +1088,7 @@ public abstract class TiledGridCoverage extends GridCoverage { for (int i = Math.min(endTile.length, upper.length); --i >= 0;) { upper[i] = Math.max(lower[i], Math.min(upper[i], endTile[i])); } - return new TileIterator(lower, upper, offset, offset.length); + return new TileIterator(lower, upper, offset, offset.length, xDimension, yDimension); } /** @@ -1145,10 +1173,10 @@ public abstract class TiledGridCoverage extends GridCoverage { long x, y; // Convenience for casting `int` to `long`. final long d = tight ? 1 : 0; final var r = new Rectangle(); - r.x = toIntExact(resourceToImage(x = bounds.x, X_DIMENSION, false)); - r.y = toIntExact(resourceToImage(y = bounds.y, Y_DIMENSION, false)); - r.width = toIntExact(resourceToImage(x + bounds.width - d, X_DIMENSION, true) - r.x + d); - r.height = toIntExact(resourceToImage(y + bounds.height - d, Y_DIMENSION, true) - r.y + d); + r.x = toIntExact(resourceToImage(x = bounds.x, xDimension, false)); + r.y = toIntExact(resourceToImage(y = bounds.y, yDimension, false)); + r.width = toIntExact(resourceToImage(x + bounds.width - d, xDimension, true) - r.x + d); + r.height = toIntExact(resourceToImage(y + bounds.height - d, yDimension, true) - r.y + d); return r; } @@ -1173,10 +1201,10 @@ public abstract class TiledGridCoverage extends GridCoverage { long x, y; // Convenience for casting `int` to `long`. final long d = tight ? 1 : 0; final var r = new Rectangle(); - r.x = toIntExact(imageToResource(x = bounds.x, X_DIMENSION)); - r.y = toIntExact(imageToResource(y = bounds.y, Y_DIMENSION)); - r.width = toIntExact(imageToResource(x + bounds.width - d, X_DIMENSION) - r.x + d); - r.height = toIntExact(imageToResource(y + bounds.height - d, Y_DIMENSION) - r.y + d); + r.x = toIntExact(imageToResource(x = bounds.x, xDimension)); + r.y = toIntExact(imageToResource(y = bounds.y, yDimension)); + r.width = toIntExact(imageToResource(x + bounds.width - d, xDimension) - r.x + d); + r.height = toIntExact(imageToResource(y + bounds.height - d, yDimension) - r.y + d); return r; } @@ -1275,12 +1303,12 @@ public abstract class TiledGridCoverage extends GridCoverage { * @param iterator the iterator for which to create a snapshot of its current position. */ public Snapshot(final AOI iterator) { - super(iterator.tmcInSubset.clone(), iterator.uncroppedTileLocation); + super(iterator.xDimension, iterator.yDimension, iterator.tmcInSubset.clone(), iterator.uncroppedTileLocation); coverage = iterator.getCoverage(); indexInResultArray = iterator.indexInResultArray; indexInTileVector = iterator.indexInTileVector; - originX = iterator.getTileOrigin(X_DIMENSION); - originY = iterator.getTileOrigin(Y_DIMENSION); + originX = iterator.getTileOrigin(xDimension); + originY = iterator.getTileOrigin(yDimension); } /** @@ -1299,11 +1327,9 @@ public abstract class TiledGridCoverage extends GridCoverage { */ @Override final int getTileOrigin(final int dimension) { - switch (dimension) { - case X_DIMENSION: return originX; - case Y_DIMENSION: return originY; - default: throw new AssertionError(dimension); - } + if (dimension == xDimension) return originX; + if (dimension == yDimension) return originY; + throw new AssertionError(dimension); } } @@ -1356,10 +1382,14 @@ public abstract class TiledGridCoverage extends GridCoverage { * (0,0) is the tile in the upper-left corner of this {@code TiledGridCoverage} (not necessarily the upper-left * corner of the image in the {@link TiledGridResource}). * - * The {@link Raster#getMinX()} and {@code getMinY()} coordinates of returned rasters + * <p>The {@link Raster#getMinX()} and {@code getMinY()} coordinates of returned rasters * shall start at the values given by {@link TileIterator#getTileOrigin(int)}. * Each tile in the returned array shall be stored at the index given by - * {@link TileIterator#getTileIndexInResultArray()}. + * {@link TileIterator#getTileIndexInResultArray()}.</p> + * + * <p>The <var>x</var> axis of the raster shall be the grid dimension specified by {@link #xDimension}. + * Likewise, the <var>y</var> axis shall be the dimension specified by {@link #yDimension}. + * These dimensions are usually 0 and 1 respectively.</p> * * <p>This method must be thread-safe. It is implementer responsibility to ensure synchronization, * for example using {@link TiledGridResource#getSynchronizationLock()}.</p> @@ -1370,6 +1400,8 @@ public abstract class TiledGridCoverage extends GridCoverage { * but the main ones are {@link java.io.IOException} for I/O errors and various {@link RuntimeException} * subtypes for Java2D errors. * + * @see #xDimension + * @see #yDimension * @see TileIterator#createRaster() * @see TileIterator#getTileIndexInResultArray() */ diff --git a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridResource.java b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridResource.java index 12f595eb6c..245f2fa590 100644 --- a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridResource.java +++ b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridResource.java @@ -47,10 +47,10 @@ import org.apache.sis.storage.DataStoreException; import org.apache.sis.storage.RasterLoadingStrategy; import org.apache.sis.measure.NumberRange; import org.apache.sis.util.ArraysExt; +import org.apache.sis.util.ArgumentChecks; +import org.apache.sis.util.resources.Errors; import org.apache.sis.util.internal.shared.Numerics; import org.apache.sis.util.collection.WeakValueHashMap; -import static org.apache.sis.storage.tiling.TiledGridCoverage.X_DIMENSION; -import static org.apache.sis.storage.tiling.TiledGridCoverage.Y_DIMENSION; // Specific to the geoapi-3.1 and geoapi-4.0 branches: import org.opengis.coverage.CannotEvaluateException; @@ -92,6 +92,9 @@ public abstract class TiledGridResource extends AbstractGridCoverageResource { /** * Number of dimensions in a rendered image. * Used for identifying codes where a two-dimensional slice is assumed. + * + * @see #xDimension + * @see #yDimension */ private static final int BIDIMENSIONAL = 2; @@ -156,6 +159,18 @@ public abstract class TiledGridResource extends AbstractGridCoverageResource { */ private RasterLoadingStrategy loadingStrategy; + /** + * The dimension of the grid which is mapped to the <var>x</var> axis (column indexes) in rendered images. + * The default value is 0. + */ + private int xDimension; + + /** + * The dimension of the grid which is mapped to the <var>y</var> axis (row indexes) in rendered images. + * The default value is 1. + */ + private int yDimension; + /** * Creates a new resource. * @@ -163,6 +178,35 @@ public abstract class TiledGridResource extends AbstractGridCoverageResource { */ protected TiledGridResource(final Resource parent) { super(parent); + yDimension = 1; + } + + /** + * Sets the mapping from grid dimensions to image axes. + * This method specifies the dimensions of the slices obtained + * when {@linkplain TiledGridCoverage#readTiles reading tiles}. + * + * <p>If this method is never invoked, then by default + * the dimension 0 of the grid is mapped to the image <var>x</var> axis and + * the dimension 1 of the grid is mapped to the image <var>y</var> axis.</p> + * + * @param xDimension dimension of the grid which is mapped to the <var>x</var> axis (column indexes) in rendered images. + * @param yDimension dimension of the grid which is mapped to the <var>y</var> axis (row indexes) in rendered images. + * @throws IllegalArgumentException if {@code xDimension} or {@code yDimension} is negative, or the two values are equal. + * @throws DataStoreException if another error occurred while setting the mapping from grid dimensions to image axes. + * + * @see TiledGridCoverage#xDimension + * @see TiledGridCoverage#yDimension + */ + protected void setRasterDimension(final int xDimension, final int yDimension) throws DataStoreException { + final int max = getGridGeometry().getDimension() - 1; + ArgumentChecks.ensureBetween("xDimension", 0, max, xDimension); + ArgumentChecks.ensureBetween("yDimension", 0, max, yDimension); + if (xDimension == yDimension) { + throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalArgumentValue_2, "yDimension", "xDimension")); + } + this.xDimension = xDimension; + this.yDimension = yDimension; } /** @@ -315,8 +359,8 @@ public abstract class TiledGridResource extends AbstractGridCoverageResource { */ protected SampleModel getSampleModel(final int[] bands) throws DataStoreException { final int[] tileSize = getTileSize(); - final int width = tileSize[X_DIMENSION]; - final int height = tileSize[Y_DIMENSION]; + final int width = tileSize[xDimension]; + final int height = tileSize[yDimension]; final ColorModel colors = getColorModel(bands); if (colors != null) { return colors.createCompatibleSampleModel(width, height); @@ -471,7 +515,7 @@ check: if (dataType.isInteger()) { /** * The sample model for the bands to read (not the full set of bands in the resource). - * The width is {@code tileSize[X_DIMENSION]} and the height it {@code tileSize[Y_DIMENSION]}, + * The width is {@code tileSize[xDimension]} and the height it {@code tileSize[yDimension]}, * i.e. subsampling is <strong>not</strong> applied. */ final SampleModel modelForBandSubset; @@ -553,7 +597,7 @@ check: if (dataType.isInteger()) { * ("atome size" of 1) and disable subsampling otherwise for avoiding code complexity. */ maxSubsmp[i] = (atomSize == 1) ? Long.MAX_VALUE : 1; - chunkSize[i] = (i == X_DIMENSION || i == Y_DIMENSION) ? span : 1; + chunkSize[i] = (i == xDimension() || i == yDimension()) ? span : 1; } /* * Build the domain in units of subsampled pixels, and get the same extent (`readExtent`) @@ -673,7 +717,23 @@ check: if (dataType.isInteger()) { * @return whether the values to read on a row are contiguous. */ public boolean isXContiguous() { - return includedBands == null && subsampling[X_DIMENSION] == 1; + return includedBands == null && subsampling[xDimension()] == 1; + } + + /** + * Returns dimension of the grid which is mapped to the <var>x</var> axis (column indexes) in rendered images. + * This is usually 0. + */ + final int xDimension() { + return xDimension; + } + + /** + * Returns dimension of the grid which is mapped to the <var>y</var> axis (row indexes) in rendered images. + * This is usually 1. + */ + final int yDimension() { + return yDimension; } /**
