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 65c2a49846fd3aafb3d23415c923ed5f66a6b1f7 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Sat Apr 8 15:27:44 2023 +0200 Make `getTileWidth()` and `getTileHeight()` methods final in `ComputedImage`. Add design notes in Javadoc for explaining some rational. --- .../java/org/apache/sis/image/ComputedImage.java | 36 ++++++++++++---------- .../org/apache/sis/image/SourceAlignedImage.java | 8 ++--- .../sis/internal/coverage/j2d/ImageUtilities.java | 30 ++++++++++++++++++ 3 files changed, 53 insertions(+), 21 deletions(-) diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/ComputedImage.java b/core/sis-feature/src/main/java/org/apache/sis/image/ComputedImage.java index 126fe58caf..c991a18cb4 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/image/ComputedImage.java +++ b/core/sis-feature/src/main/java/org/apache/sis/image/ComputedImage.java @@ -43,6 +43,7 @@ import org.apache.sis.util.Exceptions; import org.apache.sis.util.resources.Errors; import org.apache.sis.coverage.grid.GridExtent; // For javadoc import org.apache.sis.internal.feature.Resources; +import org.apache.sis.internal.coverage.j2d.ImageUtilities; /** @@ -401,37 +402,41 @@ public abstract class ComputedImage extends PlanarImage implements Disposable { * @return the sample model of this image. */ @Override - public SampleModel getSampleModel() { + public final SampleModel getSampleModel() { return sampleModel; } /** - * Returns the width of tiles in this image. The default implementation returns {@link SampleModel#getWidth()}. + * Returns the width of tiles in this image. + * In {@code ComputedImage} implementation, this is fixed to {@link SampleModel#getWidth()}. * - * <h4>Note</h4> - * A raster can have a smaller width than its sample model, for example when a raster is a view over a subregion - * of another raster. But this is not recommended in the particular case of this {@code ComputedImage} class, - * because it would cause {@link #createTile(int, int)} to consume more memory than necessary. + * <h4>Design note</h4> + * In theory it is legal to have a tile width smaller than the sample model width, + * for example when a raster is a view over a subregion of another raster. + * But this is not allowed in {@code ComputedImage} class, because it would + * cause {@link #createTile(int, int)} to consume more memory than necessary. * * @return the width of this image in pixels. */ @Override - public int getTileWidth() { + public final int getTileWidth() { return sampleModel.getWidth(); } /** - * Returns the height of tiles in this image. The default implementation returns {@link SampleModel#getHeight()}. + * Returns the height of tiles in this image. + * In {@code ComputedImage} implementation, this is fixed to {@link SampleModel#getHeight()}. * - * <h4>Note</h4> - * A raster can have a smaller height than its sample model, for example when a raster is a view over a subregion - * of another raster. But this is not recommended in the particular case of this {@code ComputedImage} class, - * because it would cause {@link #createTile(int, int)} to consume more memory than necessary. + * <h4>Design note</h4> + * In theory it is legal to have a tile height smaller than the sample model height, + * for example when a raster is a view over a subregion of another raster. + * But this is not allowed in {@code ComputedImage} class, because it would + * cause {@link #createTile(int, int)} to consume more memory than necessary. * * @return the height of this image in pixels. */ @Override - public int getTileHeight() { + public final int getTileHeight() { return sampleModel.getHeight(); } @@ -588,9 +593,8 @@ public abstract class ComputedImage extends PlanarImage implements Disposable { * @return initially empty tile for the given indices (cannot be null). */ protected WritableRaster createTile(final int tileX, final int tileY) { - // A temporary `int` overflow may occur before the final addition. - final int x = Math.toIntExact((((long) tileX) - getMinTileX()) * getTileWidth() + getMinX()); - final int y = Math.toIntExact((((long) tileY) - getMinTileY()) * getTileHeight() + getMinY()); + final int x = ImageUtilities.tileToPixelX(this, tileX); + final int y = ImageUtilities.tileToPixelY(this, tileY); return WritableRaster.createWritableRaster(sampleModel, new Point(x,y)); } diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/SourceAlignedImage.java b/core/sis-feature/src/main/java/org/apache/sis/image/SourceAlignedImage.java index 608c3a3c7e..35df3ce8c6 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/image/SourceAlignedImage.java +++ b/core/sis-feature/src/main/java/org/apache/sis/image/SourceAlignedImage.java @@ -33,10 +33,10 @@ import org.apache.sis.util.Workaround; * Tiles in this image have the same size than tiles in the source image. * See {@link ComputedImage} javadoc for more information about tile computation. * - * <div class="note"><b>Relationship with other classes</b><br> + * <h2>Relationship with other classes</h2> * This class is similar to {@link ImageAdapter} except that it extends {@link ComputedImage} * and does not forward {@link #getTile(int, int)}, {@link #getData()} and other data methods - * to the source image.</div> + * to the source image. * * <h2>Sub-classing</h2> * Subclasses need to implement at least the {@link #computeTile(int, int, WritableRaster)} method. @@ -46,7 +46,7 @@ import org.apache.sis.util.Workaround; * The {@link #equals(Object)} and {@link #hashCode()} methods should also be overridden. * * @author Martin Desruisseaux (Geomatys) - * @version 1.3 + * @version 1.4 * @since 1.1 */ abstract class SourceAlignedImage extends ComputedImage { @@ -182,8 +182,6 @@ abstract class SourceAlignedImage extends ComputedImage { @Override public final int getMinTileY() {return getSource().getMinTileY();} @Override public final int getNumXTiles() {return getSource().getNumXTiles();} @Override public final int getNumYTiles() {return getSource().getNumYTiles();} - @Override public final int getTileWidth() {return getSource().getTileWidth();} - @Override public final int getTileHeight() {return getSource().getTileHeight();} @Override public final int getTileGridXOffset() {return getSource().getTileGridXOffset();} @Override public final int getTileGridYOffset() {return getSource().getTileGridYOffset();} diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ImageUtilities.java b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ImageUtilities.java index 8b6bdbb63c..9c0280ba60 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ImageUtilities.java +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ImageUtilities.java @@ -486,9 +486,16 @@ public final class ImageUtilities extends Static { /** * Converts a <var>x</var> pixel coordinates to a tile index. * + * <h4>Implementation note</h4> + * This method performs its calculation using <cite>tile grid offset</cite> instead of minimum coordinate + * values because the former does not assume that image coordinates start at the beginning of first tile. + * In practice it would be risky to have image {@code minX} different than first tile {@code minX}, + * but Apache SIS tries to handle the most general cases when possible. + * * @param image the image containing tiles. * @param x the pixel coordinate for which to get tile index. * @return tile index for the given pixel coordinate. + * @throws ArithmeticException if the result overflows 32 bits integer. */ public static int pixelToTileX(final RenderedImage image, final int x) { return toIntExact(floorDiv((x - (long) image.getTileGridXOffset()), image.getTileWidth())); @@ -496,10 +503,12 @@ public final class ImageUtilities extends Static { /** * Converts a <var>y</var> pixel coordinates to a tile index. + * See {@link #pixelToTileX(RenderedImage, int)} for an implementation note. * * @param image the image containing tiles. * @param y the pixel coordinate for which to get tile index. * @return tile index for the given pixel coordinate. + * @throws ArithmeticException if the result overflows 32 bits integer. */ public static int pixelToTileY(final RenderedImage image, final int y) { return toIntExact(floorDiv((y - (long) image.getTileGridYOffset()), image.getTileHeight())); @@ -509,9 +518,16 @@ public final class ImageUtilities extends Static { * Converts a tile column index to smallest <var>x</var> pixel coordinate inside the tile. * The returned value is a coordinate of the pixel in upper-left corner. * + * <h4>Implementation note</h4> + * This method performs its calculation using <cite>tile grid offset</cite> instead of minimum coordinate + * values because the former does not assume that image coordinates start at the beginning of first tile. + * In practice it would be risky to have image {@code minX} different than first tile {@code minX}, + * but Apache SIS tries to handle the most general cases when possible. + * * @param image the image containing tiles. * @param tileX the tile index for which to get pixel coordinate. * @return smallest <var>x</var> pixel coordinate inside the tile. + * @throws ArithmeticException if the result overflows 32 bits integer. */ public static int tileToPixelX(final RenderedImage image, final int tileX) { // Following `long` arithmetic never overflows even if all values are `Integer.MAX_VALUE`. @@ -521,10 +537,12 @@ public final class ImageUtilities extends Static { /** * Converts a tile row index to smallest <var>y</var> pixel coordinate inside the tile. * The returned value is a coordinate of the pixel in upper-left corner. + * See {@link #tileToPixelX(RenderedImage, int)} for an implementation note. * * @param image the image containing tiles. * @param tileY the tile index for which to get pixel coordinate. * @return smallest <var>y</var> pixel coordinate inside the tile. + * @throws ArithmeticException if the result overflows 32 bits integer. */ public static int tileToPixelY(final RenderedImage image, final int tileY) { return toIntExact(multiplyFull(tileY, image.getTileHeight()) + image.getTileGridYOffset()); @@ -534,9 +552,15 @@ public final class ImageUtilities extends Static { * Converts pixel coordinates to pixel indices. * This method does <strong>not</strong> clip the rectangle to image bounds. * + * <h4>Implementation note</h4> + * This method performs its calculation using <cite>tile grid offset</cite> instead of minimum coordinate + * values because the former does not assume that image coordinates start at the beginning of first tile. + * The intend is to be consistent with {@link #pixelToTileX(RenderedImage, int)}. + * * @param image the image containing tiles. * @param pixels the pixel coordinates for which to get tile indices. * @return tile indices that fully contain the pixel coordinates. + * @throws ArithmeticException if the result overflows 32 bits integer. */ public static Rectangle pixelsToTiles(final RenderedImage image, final Rectangle pixels) { final Rectangle r = new Rectangle(); @@ -562,9 +586,15 @@ public final class ImageUtilities extends Static { * Tiles will be fully included in the returned range of pixel indices. * This method does <strong>not</strong> clip the rectangle to image bounds. * + * <h4>Implementation note</h4> + * This method performs its calculation using <cite>tile grid offset</cite> instead of minimum coordinate + * values because the former does not assume that image coordinates start at the beginning of first tile. + * The intend is to be consistent with {@link #tileToPixelX(RenderedImage, int)}. + * * @param image the image containing tiles. * @param tiles the tile indices for which to get pixel coordinates. * @return pixel coordinates that fully contain the tiles. + * @throws ArithmeticException if the result overflows 32 bits integer. */ public static Rectangle tilesToPixels(final RenderedImage image, final Rectangle tiles) { final Rectangle r = new Rectangle();