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 eceea7ffb6eb9e94f2efa14accd05385c03c610e Author: Martin Desruisseaux <[email protected]> AuthorDate: Tue Dec 29 18:18:40 2020 +0100 Make possible to use `BandedIterator` with multi-tiled images. It required to retrofit `LinearIterator` into `PixelIterator`. --- .../java/org/apache/sis/image/BandedIterator.java | 65 +++------ .../java/org/apache/sis/image/LinearIterator.java | 124 ----------------- .../java/org/apache/sis/image/PixelIterator.java | 154 ++++++++++++--------- .../apache/sis/image/WritablePixelIterator.java | 11 +- .../org/apache/sis/image/BandedIteratorTest.java | 8 +- .../org/apache/sis/image/LinearIteratorTest.java | 40 +----- .../org/apache/sis/image/PixelIteratorTest.java | 19 ++- 7 files changed, 135 insertions(+), 286 deletions(-) diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/BandedIterator.java b/core/sis-feature/src/main/java/org/apache/sis/image/BandedIterator.java index 312ac7b..2f9fce8 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/image/BandedIterator.java +++ b/core/sis-feature/src/main/java/org/apache/sis/image/BandedIterator.java @@ -28,6 +28,7 @@ import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.awt.image.WritableRaster; import java.awt.image.WritableRenderedImage; +import org.opengis.coverage.grid.SequenceType; /** @@ -80,7 +81,7 @@ final class BandedIterator extends WritablePixelIterator { * * Then {@code xToBuffer} is above value with <var>x</var> = 0. This value may be negative. * - * @see #updateForRowChange() + * @see #changedRowOrTile() */ private int xToBuffer; @@ -97,15 +98,16 @@ final class BandedIterator extends WritablePixelIterator { * @param output the raster where to write the sample values, or {@code null} for read-only iterator. * @param subArea the raster region where to perform the iteration, or {@code null} for iterating over all the raster domain. * @param window size of the window to use in {@link #createWindow(TransferType)} method, or {@code null} if none. + * @param order {@code null} or {@link SequenceType#LINEAR}. Other values may be added in future versions. * @param scanlineStride value of {@code getScanlineStride(input.getSampleModel()}. Shall be greater than zero. */ BandedIterator(final Raster input, final WritableRaster output, final Rectangle subArea, - final Dimension window, final int scanlineStride) + final Dimension window, final SequenceType order, final int scanlineStride) { - super(input, output, subArea, window); + super(input, output, subArea, window, order); this.scanlineStride = scanlineStride; acquiredTile(input); - updateForRowChange(); + changedRowOrTile(); } /** @@ -115,32 +117,25 @@ final class BandedIterator extends WritablePixelIterator { * @param output the image where to write the sample values, or {@code null} for read-only iterator. * @param subArea the image region where to perform the iteration, or {@code null} for iterating over all the image domain. * @param window size of the window to use in {@link #createWindow(TransferType)} method, or {@code null} if none. + * @param order {@code null} or {@link SequenceType#LINEAR}. Other values may be added in future versions. * @param scanlineStride value of {@code getScanlineStride(input.getSampleModel()}. Shall be greater than zero. */ BandedIterator(final RenderedImage input, final WritableRenderedImage output, final Rectangle subArea, - final Dimension window, final int scanlineStride) + final Dimension window, final SequenceType order, final int scanlineStride) { - super(input, output, subArea, window); + super(input, output, subArea, window, order); this.scanlineStride = scanlineStride; // `acquiredTile(…)` will be invoked later by `fetchTile()`. } /** * Recomputes {@link #xToBuffer} for the new {@link #y} value. This method shall be invoked - * when the iterator moved to new row, or when the iterator fetched a new tile but only after - * the (x,y) coordinates have been updated. - */ - private void updateForRowChange() { - xToBuffer = (y - sampleModelTranslateY) * scanlineStride - sampleModelTranslateX; - } - - /** - * Restores the iterator to the start position. + * when the iterator moved to a new row, or when the iterator fetched a new tile but only + * after the (x,y) coordinates have been updated. */ @Override - public void rewind() { - super.rewind(); - updateForRowChange(); + final void changedRowOrTile() { + xToBuffer = (y - sampleModelTranslateY) * scanlineStride - sampleModelTranslateX; } /** @@ -150,47 +145,19 @@ final class BandedIterator extends WritablePixelIterator { */ @Override public void moveTo(final int px, final int py) { - if (py == y && px >= currentLowerX() && px < currentUpperX()) { + if (isSameRowAndTile(px, py)) { x = px; } else { super.moveTo(px, py); - updateForRowChange(); - } - } - - /** - * Moves the iterator to the next pixel. This implementation is a copy of {@link PixelIterator#next()} - * with only a call to {@link #updateForRowChange()} added when the {@link #y} value changed. - * - * @return {@code true} if the current pixel is valid, or {@code false} if there is no more pixels. - */ - @Override - public boolean next() { - if (++x >= currentUpperX()) { - if (++y >= currentUpperY()) { - releaseTile(); - if (++tileX >= tileUpperX) { - if (++tileY >= tileUpperY) { - endOfIteration(); - return false; - } - tileX = tileLowerX; - } - y = fetchTile(); - updateForRowChange(); - } else { - xToBuffer += scanlineStride; - } - x = currentLowerX(); + changedRowOrTile(); } - return true; } /** * Invoked when the iterator fetched a new tile. This method updates {@code BandedIterator} fields * with raster properties, except {@link #xToBuffer} which is not updated here because {@link #y} * is not yet updated to its new value. {@code BandedIterator} must override all methods invoking - * {@link #fetchTile()} ane ensure that {@link #updateForRowChange()} is invoked after (x,y) have + * {@link #fetchTile()} ane ensure that {@link #changedRowOrTile()} is invoked after (x,y) have * been updated. */ @Override diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/LinearIterator.java b/core/sis-feature/src/main/java/org/apache/sis/image/LinearIterator.java deleted file mode 100644 index e1d4fdd..0000000 --- a/core/sis-feature/src/main/java/org/apache/sis/image/LinearIterator.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.sis.image; - -import java.util.Optional; -import java.awt.Dimension; -import java.awt.Rectangle; -import java.awt.image.Raster; -import java.awt.image.RenderedImage; -import java.awt.image.WritableRaster; -import java.awt.image.WritableRenderedImage; -import java.awt.image.RasterFormatException; -import org.opengis.coverage.grid.SequenceType; -import org.apache.sis.internal.feature.Resources; - - -/** - * Iterator for the {@link SequenceType#LINEAR} traversal order. - * This iterator behaves as is the whole image was a single tile. - * Calls to {@link #next()} move the current position by increasing the following values, in order: - * - * <ol> - * <li>Column index in image (from left to right)</li> - * <li>Row index in image (from top to bottom).</li> - * </ol> - * - * This class uses the {@link Raster} API for traversing the pixels of the image, - * i.e. it does not yet provide optimization for commonly used sample models. - * - * @author Johann Sorel (Geomatys) - * @author Martin Desruisseaux (Geomatys) - * @version 1.1 - * @since 1.0 - * @module - */ -final class LinearIterator extends WritablePixelIterator { - /** - * Creates an iterator for the given region in the given raster. - * - * @param input the raster which contains the sample values to read. - * @param output the raster where to write the sample values, or {@code null} for read-only iterator. - * @param subArea the raster region where to perform the iteration, or {@code null} for iterating over all the raster domain. - * @param window size of the window to use in {@link #createWindow(TransferType)} method, or {@code null} if none. - */ - LinearIterator(final Raster input, final WritableRaster output, final Rectangle subArea, final Dimension window) { - super(input, output, subArea, window); - } - - /** - * Creates an iterator for the given region in the given image. - * - * @param input the image which contains the sample values to read. - * @param output the image where to write the sample values, or {@code null} for read-only iterator. - * @param subArea the image region where to perform the iteration, or {@code null} for iterating over all the image domain. - * @param window size of the window to use in {@link #createWindow(TransferType)} method, or {@code null} if none. - */ - LinearIterator(final RenderedImage input, final WritableRenderedImage output, final Rectangle subArea, final Dimension window) { - super(input, output, subArea, window); - } - - /** - * Returns the order in which pixels are traversed. - */ - @Override - public Optional<SequenceType> getIterationOrder() { - return Optional.of(SequenceType.LINEAR); - } - - /** - * Moves the iterator to the next pixel on the current row, or to the next row. - * This method behaves as if the whole image was a single tile. - * - * @return {@code true} if the current pixel is valid, or {@code false} if there is no more pixels. - * @throws IllegalStateException if this iterator already reached end of iteration in a previous call - * to {@code next()}, and {@link #rewind()} or {@link #moveTo(int,int)} have not been invoked. - */ - @Override - public boolean next() { - if (++x >= currentUpperX()) { // Move to next column, potentially on a different tile. - if (x < upperX) { - releaseTile(); // Must be invoked before `tileX` change. - tileX++; - } else { - x = lowerX; // Beginning of next row. - if (++y >= currentUpperY()) { // Move to next line. - releaseTile(); // Must be invoked before `tileY` change. - if (++tileY >= tileUpperY) { - endOfIteration(); - return false; - } - } else if (tileX == tileLowerX) { - return true; // Beginning of next row is in the same tile. - } - releaseTile(); // Must be invoked before `tileX` change. - tileX = tileLowerX; - } - /* - * At this point the (x,y) pixel coordinates have been updated and are inside the domain of validity. - * We may need to change tile, either because we moved to the tile on the right or because we start a - * new row (in which case we need to move to the leftmost tile). The only case where we can skip tile - * change is when the image has only one tile width (in which case tileX == tileLowerX) and the next - * row is still on the same tile. - */ - if (fetchTile() > y) { - throw new RasterFormatException(Resources.format(Resources.Keys.IncompatibleTile_2, tileX, tileY)); - } - } - return true; - } -} diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/PixelIterator.java b/core/sis-feature/src/main/java/org/apache/sis/image/PixelIterator.java index de88021..7dd9366 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/image/PixelIterator.java +++ b/core/sis-feature/src/main/java/org/apache/sis/image/PixelIterator.java @@ -133,7 +133,7 @@ public class PixelIterator { * The tile index ranges may be smaller than the ranges of valid indices in image, * but not greater. The lower values are inclusive and the upper values exclusive. */ - final int tileLowerX, tileLowerY, tileUpperX, tileUpperY; + private final int tileLowerX, tileLowerY, tileUpperX, tileUpperY; /** * Size of the window to use in {@link #createWindow(TransferType)} method, or {@code 0} if none. @@ -156,9 +156,6 @@ public class PixelIterator { * Bounds of the region traversed by the iterator in {@linkplain #currentRaster current raster}. * When iteration reaches the upper coordinates, the iterator needs to move to next tile. * This the raster bounds clipped to the area of interest. - * - * @see #currentUpperX() - * @see #currentUpperY() */ private int currentLowerX, currentUpperX, currentUpperY; @@ -176,14 +173,21 @@ public class PixelIterator { private int windowLimitX, windowLimitY; /** + * {@code true} for default iteration order, or {@code false} for {@link SequenceType#LINEAR}. + * Note that the order is equivalent to linear order when there is only one tile. + */ + private final boolean isDefaultOrder; + + /** * Creates an iterator for the given region in the given raster. * * @param data the raster which contains the sample values on which to iterate. * @param subArea the raster region where to perform the iteration, or {@code null} * for iterating over all the raster domain. * @param window size of the window to use in {@link #createWindow(TransferType)} method, or {@code null} if none. + * @param order {@code null} or {@link SequenceType#LINEAR}. Other values may be added in future versions. */ - PixelIterator(final Raster data, final Rectangle subArea, final Dimension window) { + PixelIterator(final Raster data, final Rectangle subArea, final Dimension window, final SequenceType order) { final Rectangle bounds; image = null; currentRaster = data; @@ -210,6 +214,7 @@ public class PixelIterator { windowLimitY = Math.addExact(tileGridYOffset, tileHeight); x = Math.decrementExact(lowerX); // Set to the position before first pixel. y = lowerY; + isDefaultOrder = true; } /** @@ -219,8 +224,9 @@ public class PixelIterator { * @param subArea the image region where to perform the iteration, or {@code null} * for iterating over all the image domain. * @param window size of the window to use in {@link #createWindow(TransferType)} method, or {@code null} if none. + * @param order {@code null} or {@link SequenceType#LINEAR}. Other values may be added in future versions. */ - PixelIterator(final RenderedImage data, final Rectangle subArea, final Dimension window) { + PixelIterator(final RenderedImage data, final Rectangle subArea, final Dimension window, final SequenceType order) { final Rectangle bounds; image = data; numBands = data.getSampleModel().getNumBands(); @@ -246,6 +252,7 @@ public class PixelIterator { currentUpperY = lowerY; x = Math.decrementExact(lowerX); // Set to the position before first pixel. y = lowerY; + isDefaultOrder = (order == null) || (tileUpperX - tileLowerX) <= 1; /* * We need to ensure that `tileUpperY+1 > tileUpperY` will alway be true because `tileY` may be equal * to `tileUpperY` when the `if (++tileY >= tileUpperY)` statement is excuted in the `next()` method. @@ -420,18 +427,11 @@ public class PixelIterator { */ public PixelIterator create(final Raster data) { ArgumentChecks.ensureNonNull("data", data); - if (order != null && order != SequenceType.LINEAR) { - throw new IllegalStateException(Errors.format(Errors.Keys.UnsupportedType_1, order)); - } - /* - * No need to instantiate `LinearIterator` because the default iterator - * has the same iteration order when there is only one tile. - */ final int scanlineStride = getScanlineStride(data.getSampleModel()); if (scanlineStride > 0) { - return new BandedIterator(data, null, subArea, window, scanlineStride); + return new BandedIterator(data, null, subArea, window, order, scanlineStride); } else { - return new PixelIterator(data, subArea, window); + return new PixelIterator(data, subArea, window, order); } } @@ -445,7 +445,7 @@ public class PixelIterator { ArgumentChecks.ensureNonNull("data", data); data = unwrap(data); /* - * Note: As of Java 14, `BufferedImage.getTileGridXOffset()` and `getTileGridYOffset()` have a bug. + * Note: Before Java 16, `BufferedImage.getTileGridXOffset()` and `getTileGridYOffset()` had a bug. * They should return `BufferedImage.getMinX()` (which is always 0) because the image contains only * one tile at index (0,0). But they return `raster.getSampleModelTranslateX()` instead, which may * be non-zero if the image is a sub-region of another image. Delegating to `create(Raster)` avoid @@ -456,16 +456,11 @@ public class PixelIterator { if (data instanceof BufferedImage) { return create(((BufferedImage) data).getRaster()); } - if (order == SequenceType.LINEAR) { - return new LinearIterator(data, null, subArea, window); - } else if (order != null) { - throw new IllegalStateException(Errors.format(Errors.Keys.UnsupportedType_1, order)); - } final int scanlineStride = getScanlineStride(data.getSampleModel()); if (scanlineStride > 0) { - return new BandedIterator(data, null, subArea, window, scanlineStride); + return new BandedIterator(data, null, subArea, window, order, scanlineStride); } else { - return new PixelIterator(data, subArea, window); + return new PixelIterator(data, subArea, window, order); } } @@ -505,18 +500,11 @@ public class PixelIterator { public WritablePixelIterator createWritable(final Raster input, final WritableRaster output) { ArgumentChecks.ensureNonNull("input", input); ArgumentChecks.ensureNonNull("output", output); - if (order != null && order != SequenceType.LINEAR) { - throw new IllegalStateException(Errors.format(Errors.Keys.UnsupportedType_1, order)); - } - /* - * No need to instantiate `LinearIterator` because the default iterator - * has the same iteration order when there is only one tile. - */ final int scanlineStride = getScanlineStride(input.getSampleModel()); if (scanlineStride > 0) { - return new BandedIterator(input, output, subArea, window, scanlineStride); + return new BandedIterator(input, output, subArea, window, order, scanlineStride); } else { - return new WritablePixelIterator(input, output, subArea, window); + return new WritablePixelIterator(input, output, subArea, window, order); } } @@ -532,16 +520,11 @@ public class PixelIterator { ArgumentChecks.ensureNonNull("input", input); ArgumentChecks.ensureNonNull("output", output); input = unwrap(input); - if (order == SequenceType.LINEAR) { - return new LinearIterator(input, output, subArea, window); - } else if (order != null) { - throw new IllegalStateException(Errors.format(Errors.Keys.UnsupportedType_1, order)); - } final int scanlineStride = getScanlineStride(input.getSampleModel()); if (scanlineStride > 0) { - return new BandedIterator(input, output, subArea, window, scanlineStride); + return new BandedIterator(input, output, subArea, window, order, scanlineStride); } else { - return new WritablePixelIterator(input, output, subArea, window); + return new WritablePixelIterator(input, output, subArea, window, order); } } } @@ -656,10 +639,10 @@ public class PixelIterator { * @return order in which pixels are traversed. */ public Optional<SequenceType> getIterationOrder() { - if (image == null || (tileUpperX - tileLowerX) <= 1 && (tileUpperY - tileLowerY) <= 1) { - return Optional.of(SequenceType.LINEAR); + if (isDefaultOrder && (tileUpperX - tileLowerX) > 1) { + return Optional.empty(); // Undefined iteration order. } else { - return Optional.empty(); // Undefined order. + return Optional.of(SequenceType.LINEAR); } } @@ -757,44 +740,80 @@ public class PixelIterator { * to {@code next()}, and {@link #rewind()} or {@link #moveTo(int,int)} have not been invoked. */ public boolean next() { + /* + * Current implementation supports two iteration orders: default and SequenceType.LINEAR. + * They are the two most frequent orders and have in common an iteration over x values of + * current tile before to make any decision. It is reasonably cheap to implement them in + * the same method because the cost of checking for iteration order happens only once per + * tile row (instead than at every pixel). Providing the two implementations here makes + * easier for subclasses such as `BandedIterator` to support those two iteration orders. + * + * All other iteration orders (Cantor, Morton, Hilbert, etc.) should have a dedicated + * class overriding this method. We do not intent to support all iteration order here. + */ if (++x >= currentUpperX) { - if (++y >= currentUpperY) { // Strict equality (==) would work, but use >= as a safety. - releaseTile(); // Release current writable raster, if any. - if (++tileX >= tileUpperX) { // Strict equality (==) would work, but use >= as a safety. - if (++tileY >= tileUpperY) { - endOfIteration(); - return false; + if (isDefaultOrder) { + if (++y >= currentUpperY) { // Strict equality (==) would work, but use >= as a safety. + releaseTile(); // Release current writable raster, if any. + if (++tileX >= tileUpperX) { // Strict equality (==) would work, but use >= as a safety. + if (++tileY >= tileUpperY) { + endOfIteration(); + return false; + } + tileX = tileLowerX; + } + y = fetchTile(); + } + x = currentLowerX; + } else { + /* + * SequenceType.LINEAR iteration order: before to move to next row, verify if there is + * more tiles to traverse on the right side. + */ + releaseTile(); // Must be invoked before (tileX, tileY) change. + if (x < upperX) { + tileX++; + } else { + if (++y >= currentUpperY) { // Move to next line only after full image row. + if (++tileY >= tileUpperY) { + endOfIteration(); + return false; + } } tileX = tileLowerX; + x = lowerX; // Beginning of next row. + } + /* + * At this point the (x,y) pixel coordinates have been updated and are inside the domain of validity. + * We need to change tile, either because we moved to the tile on the right or because we started a + * new row (in which case we need to move to the leftmost tile). + */ + if (fetchTile() > y) { + throw new RasterFormatException(Resources.format(Resources.Keys.IncompatibleTile_2, tileX, tileY)); } - y = fetchTile(); } - x = currentLowerX; + changedRowOrTile(); } return true; } /** - * Returns the lower limit of the region traversed by the iterator in current raster. - */ - final int currentLowerX() { - return currentLowerX; - } - - /** - * Returns the upper limit of the region traversed by the iterator in current raster. - * When iteration reaches this limit, the iterator needs to move to next row or next tile. + * Invoked by the default {@link #next()} implementation when the iterator moved to a new row or a new tile. + * Subclasses can override for updating some <var>y</var>-dependent cached values. + * + * <p>Note that this method is not invoked by {@link #moveTo(int, int)} for performance reason. + * Subclasses can get equivalent functionality by overriding {@code moveTo(…)} and checking + * {@code isSameRowAndTile(px, py)}.</p> */ - final int currentUpperX() { - return currentUpperX; + void changedRowOrTile() { } /** - * Returns the upper limit of the region traversed by the iterator in current raster. - * When iteration reaches this limit, the iterator needs to move to next tile. + * Returns whether given position is on the same row and same tile than current (x,y) position. + * This method is provided as a complement to {@link #changedRowOrTile()}. */ - final int currentUpperY() { - return currentUpperY; + final boolean isSameRowAndTile(final int px, final int py) { + return (py == y) && px >= currentLowerX && px < currentUpperX; } /** @@ -810,7 +829,7 @@ public class PixelIterator { * * @return the {@link #y} value of the first row of new tile. */ - final int fetchTile() { + private int fetchTile() { Raster tile = fetchWritableTile(); if (tile == null) { tile = image.getTile(tileX, tileY); @@ -870,7 +889,7 @@ public class PixelIterator { * <p>Note: {@link #releaseTile()} is always invoked before this method. * Consequently {@link #currentRaster} is already {@code null}.</p> */ - final void endOfIteration() { + private void endOfIteration() { /* * The `tileY` value is used for checking if next() is invoked again, in order to avoid a * common misuse pattern. In principle `tileY` needs to be compared only to `tileUpperY`, @@ -1430,5 +1449,6 @@ public class PixelIterator { } x = lowerX - 1; // Set to the position before first pixel. y = lowerY; + changedRowOrTile(); } } diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/WritablePixelIterator.java b/core/sis-feature/src/main/java/org/apache/sis/image/WritablePixelIterator.java index 6ee7598..986c354 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/image/WritablePixelIterator.java +++ b/core/sis-feature/src/main/java/org/apache/sis/image/WritablePixelIterator.java @@ -23,6 +23,7 @@ import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.awt.image.WritableRaster; import java.awt.image.WritableRenderedImage; +import org.opengis.coverage.grid.SequenceType; import org.apache.sis.internal.feature.Resources; @@ -80,11 +81,12 @@ public class WritablePixelIterator extends PixelIterator implements Closeable { * @param subArea the raster region where to perform the iteration, or {@code null} * for iterating over all the raster domain. * @param window size of the window to use in {@link #createWindow(TransferType)} method, or {@code null} if none. + * @param order {@code null} or {@link SequenceType#LINEAR}. Other values may be added in future versions. */ WritablePixelIterator(final Raster input, final WritableRaster output, - final Rectangle subArea, final Dimension window) + final Rectangle subArea, final Dimension window, final SequenceType order) { - super(input, subArea, window); + super(input, subArea, window, order); destRaster = output; destination = null; if (output != null) { @@ -104,11 +106,12 @@ public class WritablePixelIterator extends PixelIterator implements Closeable { * @param subArea the image region where to perform the iteration, or {@code null} * for iterating over all the image domain. * @param window size of the window to use in {@link #createWindow(TransferType)} method, or {@code null} if none. + * @param order {@code null} or {@link SequenceType#LINEAR}. Other values may be added in future versions. */ WritablePixelIterator(final RenderedImage input, final WritableRenderedImage output, - final Rectangle subArea, final Dimension window) + final Rectangle subArea, final Dimension window, final SequenceType order) { - super(input, subArea, window); + super(input, subArea, window, order); destRaster = null; destination = output; if (output != null) { diff --git a/core/sis-feature/src/test/java/org/apache/sis/image/BandedIteratorTest.java b/core/sis-feature/src/test/java/org/apache/sis/image/BandedIteratorTest.java index 3221552..4d70f46 100644 --- a/core/sis-feature/src/test/java/org/apache/sis/image/BandedIteratorTest.java +++ b/core/sis-feature/src/test/java/org/apache/sis/image/BandedIteratorTest.java @@ -38,7 +38,7 @@ public final strictfp class BandedIteratorTest extends PixelIteratorTest { * Creates a new test case. */ public BandedIteratorTest() { - super(DataBuffer.TYPE_FLOAT); + super(DataBuffer.TYPE_FLOAT, null); useBandedSampleModel = true; } @@ -49,7 +49,7 @@ public final strictfp class BandedIteratorTest extends PixelIteratorTest { void createPixelIterator(final WritableRaster raster, final Rectangle subArea) { final int scanlineStride = PixelIterator.Builder.getScanlineStride(raster.getSampleModel()); assertTrue(scanlineStride >= raster.getWidth()); - iterator = new BandedIterator(raster, isWritable ? raster : null, subArea, null, scanlineStride); + iterator = new BandedIterator(raster, isWritable ? raster : null, subArea, null, null, scanlineStride); assertEquals("getIterationOrder()", SequenceType.LINEAR, iterator.getIterationOrder().get()); assertEquals("isWritable", isWritable, iterator.isWritable()); } @@ -61,7 +61,7 @@ public final strictfp class BandedIteratorTest extends PixelIteratorTest { void createPixelIterator(final WritableRenderedImage image, final Rectangle subArea) { final int scanlineStride = PixelIterator.Builder.getScanlineStride(image.getSampleModel()); assertTrue(scanlineStride >= image.getTileWidth()); - iterator = new BandedIterator(image, isWritable ? image : null, subArea, null, scanlineStride); + iterator = new BandedIterator(image, isWritable ? image : null, subArea, null, null, scanlineStride); assertEquals("isWritable", isWritable, iterator.isWritable()); } @@ -73,7 +73,7 @@ public final strictfp class BandedIteratorTest extends PixelIteratorTest { void createWindowIterator(final WritableRenderedImage image, final Dimension window) { final int scanlineStride = PixelIterator.Builder.getScanlineStride(image.getSampleModel()); assertTrue(scanlineStride >= image.getTileWidth()); - iterator = new BandedIterator(image, isWritable ? image : null, null, window, scanlineStride); + iterator = new BandedIterator(image, isWritable ? image : null, null, window, null, scanlineStride); assertEquals("isWritable", isWritable, iterator.isWritable()); } } diff --git a/core/sis-feature/src/test/java/org/apache/sis/image/LinearIteratorTest.java b/core/sis-feature/src/test/java/org/apache/sis/image/LinearIteratorTest.java index 35ff72c..f7e0e92 100644 --- a/core/sis-feature/src/test/java/org/apache/sis/image/LinearIteratorTest.java +++ b/core/sis-feature/src/test/java/org/apache/sis/image/LinearIteratorTest.java @@ -19,8 +19,6 @@ package org.apache.sis.image; import java.awt.Dimension; import java.awt.Rectangle; import java.awt.image.DataBuffer; -import java.awt.image.WritableRaster; -import java.awt.image.WritableRenderedImage; import org.opengis.coverage.grid.SequenceType; import static org.junit.Assert.*; @@ -29,9 +27,14 @@ import static org.junit.Assert.*; /** * Tests the linear read-write iterator on signed short integer values. * + * <p>Historical note: in a previous version, this iteration order was implemented in a separated class + * named {@code LinearIterator}. Linear order has been retrofitted in {@link PixelIterator} but we keep + * that test class separated as an easy way to execute the same set tests with the two iteration orders + * (default and linear).</p> + * * @author Johann Sorel (Geomatys) * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 1.1 * @since 1.0 */ public final strictfp class LinearIteratorTest extends PixelIteratorTest { @@ -39,7 +42,7 @@ public final strictfp class LinearIteratorTest extends PixelIteratorTest { * Creates a new test case. */ public LinearIteratorTest() { - super(DataBuffer.TYPE_SHORT); + super(DataBuffer.TYPE_SHORT, SequenceType.LINEAR); } /** @@ -93,35 +96,6 @@ public final strictfp class LinearIteratorTest extends PixelIteratorTest { } /** - * Creates a {@code PixelIterator} for a sub-area of given raster. - */ - @Override - void createPixelIterator(WritableRaster raster, Rectangle subArea) { - iterator = new LinearIterator(raster, isWritable ? raster : null, subArea, null); - assertEquals("getIterationOrder()", SequenceType.LINEAR, iterator.getIterationOrder().get()); - assertEquals("isWritable", isWritable, iterator.isWritable()); - } - - /** - * Creates a {@code PixelIterator} for a sub-area of given image. - */ - @Override - void createPixelIterator(WritableRenderedImage image, Rectangle subArea) { - iterator = new LinearIterator(image, isWritable ? image : null, subArea, null); - assertEquals("isWritable", isWritable, iterator.isWritable()); - } - - /** - * Creates a {@code PixelIterator} for a window in the given image. - * The iterator shall be assigned to the {@link #iterator} field. - */ - @Override - void createWindowIterator(WritableRenderedImage image, Dimension window) { - iterator = new LinearIterator(image, isWritable ? image : null, null, window); - assertEquals("isWritable", isWritable, iterator.isWritable()); - } - - /** * Returns the values of the given sub-region, organized in a {@link SequenceType#LINEAR} fashion. * This method is invoked for {@link #verifyWindow(Dimension)} purpose. * diff --git a/core/sis-feature/src/test/java/org/apache/sis/image/PixelIteratorTest.java b/core/sis-feature/src/test/java/org/apache/sis/image/PixelIteratorTest.java index bf67736..9f8c71e 100644 --- a/core/sis-feature/src/test/java/org/apache/sis/image/PixelIteratorTest.java +++ b/core/sis-feature/src/test/java/org/apache/sis/image/PixelIteratorTest.java @@ -111,6 +111,13 @@ public strictfp class PixelIteratorTest extends TestCase { private float[] expected; /** + * Iteration order to request at construction time. This is not necessarily the same + * than the actual iteration order chosen by the iterator because the iterator may + * replace default order by a more specific one. + */ + private final SequenceType requestedOrder; + + /** * {@code true} for testing write operations in addition of read operations. */ boolean isWritable; @@ -125,15 +132,17 @@ public strictfp class PixelIteratorTest extends TestCase { * * @param dataType the raster or image data type as one of the {@link DataBuffer} constants. */ - PixelIteratorTest(final int dataType) { + PixelIteratorTest(final int dataType, final SequenceType requestedOrder) { this.dataType = dataType; + this.requestedOrder = requestedOrder; } /** * Creates a new test case. */ public PixelIteratorTest() { - this(DataBuffer.TYPE_SHORT); + dataType = DataBuffer.TYPE_SHORT; + requestedOrder = null; } /** @@ -341,7 +350,7 @@ public strictfp class PixelIteratorTest extends TestCase { * @param subArea the boundary of the raster sub-area where to perform iteration. */ void createPixelIterator(WritableRaster raster, Rectangle subArea) { - iterator = new WritablePixelIterator(raster, isWritable ? raster : null, subArea, null); + iterator = new WritablePixelIterator(raster, isWritable ? raster : null, subArea, null, requestedOrder); assertEquals("getIterationOrder()", SequenceType.LINEAR, iterator.getIterationOrder().get()); assertEquals("isWritable", isWritable, iterator.isWritable()); } @@ -357,7 +366,7 @@ public strictfp class PixelIteratorTest extends TestCase { * @param subArea the boundary of the image sub-area where to perform iteration. */ void createPixelIterator(WritableRenderedImage image, Rectangle subArea) { - iterator = new WritablePixelIterator(image, isWritable ? image : null, subArea, null); + iterator = new WritablePixelIterator(image, isWritable ? image : null, subArea, null, requestedOrder); assertEquals("isWritable", isWritable, iterator.isWritable()); } @@ -372,7 +381,7 @@ public strictfp class PixelIteratorTest extends TestCase { * @param window size of the window to use in {@link PixelIterator#createWindow(TransferType)} method. */ void createWindowIterator(WritableRenderedImage image, Dimension window) { - iterator = new WritablePixelIterator(image, isWritable ? image : null, null, window); + iterator = new WritablePixelIterator(image, isWritable ? image : null, null, window, requestedOrder); assertEquals("isWritable", isWritable, iterator.isWritable()); }
