sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1803853 - in /sis/branches/JDK8/core/sis-raster/src: main/java/org/apache/sis/image/ test/java/org/apache/sis/image/
Date Wed, 02 Aug 2017 16:16:53 GMT
Author: desruisseaux
Date: Wed Aug  2 16:16:53 2017
New Revision: 1803853

URL: http://svn.apache.org/viewvc?rev=1803853&view=rev
Log:
First implementation of PixelIterator.window().

Modified:
    sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/DefaultIterator.java
    sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/PixelIterator.java
    sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/PixelIteratorFactory.java
    sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/WritablePixelIterator.java
    sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/PixelIteratorTest.java

Modified: sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/DefaultIterator.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/DefaultIterator.java?rev=1803853&r1=1803852&r2=1803853&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/DefaultIterator.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/DefaultIterator.java
[UTF-8] Wed Aug  2 16:16:53 2017
@@ -17,6 +17,7 @@
 package org.apache.sis.image;
 
 import java.awt.Point;
+import java.awt.Dimension;
 import java.awt.Rectangle;
 import java.awt.image.Raster;
 import java.awt.image.RenderedImage;
@@ -68,14 +69,20 @@ final class DefaultIterator extends Pixe
     private int currentLowerX, currentUpperX, currentUpperY;
 
     /**
+     * A temporary array used by {@link #window} for transferring data.
+     */
+    private transient double[] transfer;
+
+    /**
      * 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 #window()} method, or {@code
null} if none.
      */
-    DefaultIterator(final Raster data, final Rectangle subArea) {
-        super(data, subArea);
+    DefaultIterator(final Raster data, final Rectangle subArea, final Dimension window) {
+        super(data, subArea, window);
         currentLowerX = lowerX;
         currentUpperX = upperX;
         currentUpperY = upperY;
@@ -89,9 +96,10 @@ final class DefaultIterator extends Pixe
      * @param  data     the image which contains the sample values on which to iterate.
      * @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 #window()} method, or {@code
null} if none.
      */
-    DefaultIterator(final RenderedImage data, final Rectangle subArea) {
-        super(data, subArea);
+    DefaultIterator(final RenderedImage data, final Rectangle subArea, final Dimension window)
{
+        super(data, subArea, window);
         tileX = Math.decrementExact(tileLowerX);
         tileY = tileLowerY;
         currentLowerX = lowerX;
@@ -237,6 +245,7 @@ final class DefaultIterator extends Pixe
 
     /**
      * Returns the sample value in the specified band of current pixel, rounded toward zero.
+     * This method assumes that {@link #next()} or {@link #moveTo(int,int)} has been invoked.
      */
     @Override
     public int getSample(final int band) {
@@ -245,6 +254,7 @@ final class DefaultIterator extends Pixe
 
     /**
      * Returns the sample value in the specified band of current pixel as a single-precision
floating point number.
+     * This method assumes that {@link #next()} or {@link #moveTo(int,int)} has been invoked.
      */
     @Override
     public float getSampleFloat(final int band) {
@@ -253,6 +263,7 @@ final class DefaultIterator extends Pixe
 
     /**
      * Returns the sample value in the specified band of current pixel, without precision
lost.
+     * This method assumes that {@link #next()} or {@link #moveTo(int,int)} has been invoked.
      */
     @Override
     public double getSampleDouble(final int band) {
@@ -261,6 +272,7 @@ final class DefaultIterator extends Pixe
 
     /**
      * Returns the sample values of current pixel for all bands.
+     * This method assumes that {@link #next()} or {@link #moveTo(int,int)} has been invoked.
      */
     @Override
     public double[] getPixel​(double[] dest) {
@@ -269,6 +281,7 @@ final class DefaultIterator extends Pixe
 
     /**
      * Returns the sample values of current pixel for all bands.
+     * This method assumes that {@link #next()} or {@link #moveTo(int,int)} has been invoked.
      */
     @Override
     public float[] getPixel​(float[] dest) {
@@ -277,6 +290,7 @@ final class DefaultIterator extends Pixe
 
     /**
      * Returns the sample values of current pixel for all bands.
+     * This method assumes that {@link #next()} or {@link #moveTo(int,int)} has been invoked.
      */
     @Override
     public int[] getPixel​(int[] dest) {
@@ -284,10 +298,67 @@ final class DefaultIterator extends Pixe
     }
 
     /**
-     * Returns the sample values in a region of the given size starting at the current pixel
position.
+     * Returns the sample values in a region of the window size starting at the current pixel
position.
+     * This method assumes that {@link #next()} or {@link #moveTo(int,int)} has been invoked.
      */
     @Override
-    public Region region(final int width, final int height) {
-        throw new UnsupportedOperationException();              // TODO
+    public double[] window() {
+        if (window == null) {
+            window   = new double[numBands * windowWidth * windowHeight];
+            transfer = new double[window.length /*- numBands * Math.min(windowWidth, windowHeight)*/];
+            // 'transfer' will always have at least one row or one column less than 'window'.
+        }
+        int subX         = x;                       // Upper-left corner of a sub-window
inside the window.
+        int subY         = y;
+        int tileSubX     = tileX;                   // The tile where is located the (subX,
subY) coordinate.
+        int tileSubY     = tileY;
+        final int endX   = subX + windowWidth;      // Upper limit of the full window. May
be located in another tile.
+        final int endY   = subY + windowHeight;
+        final int stride = windowWidth * numBands;  // Number of samples between two rows
in the 'windows' array.
+        Raster raster    = currentRaster;
+        int subEndX      = raster.getMinX() + raster.getWidth();
+        int subEndY      = raster.getMinY() + raster.getHeight();
+        final int rewind = subEndX;
+        int destOffset   = 0;                       // Index in 'window' array where to copy
the sample values.
+        for (;;) {
+            final int subWidth  = Math.min(endX, subEndX) - subX;
+            final int subHeight = Math.min(endY, subEndY) - subY;
+            if (subWidth > 0 && subHeight > 0) {
+                final boolean fullWidth = (subWidth == windowWidth);
+                if (fullWidth && subHeight == windowHeight) {
+//                    return raster.getPixels(subX, subY, subWidth, subHeight, window);
+                }
+                transfer = raster.getPixels(subX, subY, subWidth, subHeight, transfer);
+                final int  rowLength = numBands  * subWidth;
+                final int fullLength = rowLength * subHeight;
+                for (int srcOffset=0; srcOffset < fullLength; srcOffset += rowLength)
{
+                    System.arraycopy(transfer, srcOffset, window, destOffset, rowLength);
+                    destOffset += stride;
+                }
+            }
+            /*
+             * At this point, we copied all sample values that we could obtain from the current
tile.
+             * In most cases we will be done, since the window size should be much smaller
than the tile size.
+             * However in a few cases the window overlaps more than one tile, in which case
we need to move to
+             * next tile.
+             */
+            if (subEndX < endX) {
+                subX     = subEndX;
+                subEndX += tileWidth;                       // Next tile on the same row.
+                tileSubX++;
+            } else {
+                if (subEndY >= endY) {
+                    return window;                          // Completed last row of tiles.
+                }
+                subY     = subEndY;
+                subEndY += tileHeight;                      // Tile on the next row.
+                tileSubY++;
+                tileSubX = tileX;
+                subEndX  = rewind;
+                subX     = x;                               // Move x position back to the
window left border.
+            }
+            raster = image.getTile(tileSubX, tileSubY);
+            destOffset = ((subY - y) * windowWidth + (subX - x)) * numBands;
+        }
     }
 }

Modified: sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/PixelIterator.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/PixelIterator.java?rev=1803853&r1=1803852&r2=1803853&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/PixelIterator.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/PixelIterator.java
[UTF-8] Wed Aug  2 16:16:53 2017
@@ -17,6 +17,7 @@
 package org.apache.sis.image;
 
 import java.awt.Point;
+import java.awt.Dimension;
 import java.awt.Rectangle;
 import java.awt.image.Raster;
 import java.awt.image.RenderedImage;
@@ -98,13 +99,25 @@ public abstract class PixelIterator {
     final int tileLowerX, tileLowerY, tileUpperX, tileUpperY;
 
     /**
+     * Size of the window to use in {@link #window()} method, or {@code 0} if none.
+     */
+    final int windowWidth, windowHeight;
+
+    /**
+     * Sample values in the window, or {@code null} if not yet extracted.
+     * Current sample values. This array is overwritten when {@link #window()} is invoked.
+     */
+    transient double[] window;
+
+    /**
      * 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 #window()} method, or {@code
null} if none.
      */
-    PixelIterator(final Raster data, final Rectangle subArea) {
+    PixelIterator(final Raster data, final Rectangle subArea, final Dimension window) {
         ArgumentChecks.ensureNonNull("data", data);
         final Rectangle bounds;
         image           = null;
@@ -118,11 +131,13 @@ public abstract class PixelIterator {
         tileLowerY      = 0;
         tileUpperX      = 1;
         tileUpperY      = 1;
-        bounds          = intersection(tileGridXOffset, tileGridYOffset, tileWidth, tileHeight,
subArea);
+        bounds          = intersection(tileGridXOffset, tileGridYOffset, tileWidth, tileHeight,
subArea, window);
         lowerX          = bounds.x;
         lowerY          = bounds.y;
         upperX          = Math.addExact(lowerX, bounds.width);
         upperY          = Math.addExact(lowerY, bounds.height);
+        windowWidth     = (window != null) ? window.width  : 0;
+        windowHeight    = (window != null) ? window.height : 0;
     }
 
     /**
@@ -131,8 +146,9 @@ public abstract class PixelIterator {
      * @param  data     the image which contains the sample values on which to iterate.
      * @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 #window()} method, or {@code
null} if none.
      */
-    PixelIterator(final RenderedImage data, final Rectangle subArea) {
+    PixelIterator(final RenderedImage data, final Rectangle subArea, final Dimension window)
{
         ArgumentChecks.ensureNonNull("data", data);
         final Rectangle bounds;
         image           = data;
@@ -141,7 +157,7 @@ public abstract class PixelIterator {
         tileHeight      = data.getTileHeight();
         tileGridXOffset = data.getTileGridXOffset();
         tileGridYOffset = data.getTileGridYOffset();
-        bounds          = intersection(data.getMinX(), data.getMinY(), data.getWidth(), data.getHeight(),
subArea);
+        bounds          = intersection(data.getMinX(), data.getMinY(), data.getWidth(), data.getHeight(),
subArea, window);
         lowerX          = bounds.x;
         lowerY          = bounds.y;
         upperX          = Math.addExact(lowerX, bounds.width);
@@ -150,6 +166,8 @@ public abstract class PixelIterator {
         tileLowerY      = floorDiv(Math.subtractExact(lowerY, tileGridYOffset), tileHeight);
         tileUpperX      =  ceilDiv(Math.subtractExact(upperX, tileGridXOffset), tileWidth);
         tileUpperY      =  ceilDiv(Math.subtractExact(upperY, tileGridYOffset), tileHeight);
+        windowWidth     = (window != null) ? window.width  : 0;
+        windowHeight    = (window != null) ? window.height : 0;
     }
 
     /**
@@ -163,7 +181,13 @@ public abstract class PixelIterator {
      * Computes the intersection between the given bounds and and {@code subArea} if {@code
subArea} is non-null.
      * If the result is empty, then the width and/or height are set to zero (not negative).
      */
-    private static Rectangle intersection(int x, int y, int width, int height, Rectangle
subArea) {
+    private static Rectangle intersection(int x, int y, int width, int height, Rectangle
subArea, Dimension window) {
+        if (window != null) {
+            ArgumentChecks.ensureBetween("window.width",  1, width,  window.width);
+            ArgumentChecks.ensureBetween("window.height", 1, height, window.height);
+            width  -= (window.width  - 1);
+            height -= (window.height - 1);
+        }
         Rectangle bounds = new Rectangle(x, y, width, height);
         if (subArea != null) {
             bounds = bounds.intersection(subArea);
@@ -326,88 +350,40 @@ public abstract class PixelIterator {
     public abstract int[] getPixel​(int[] dest);
 
     /**
-     * Returns the sample values in a region of the given size starting at the current pixel
position.
-     * The returned region will be live: calls to {@link #next()} followed by {@link Region#values()}
-     * returns an updated array with values starting at the new iterator position.
-     * This method is designed for use like below:
-     *
-     * {@preformat java
-     *     Region r = iterator.getRegion(width, height);
-     *     while (iterator.next()) {
-     *         double[] samples = r.values();
-     *         // Do some computation here...
-     *     }
-     * }
-     *
-     * Arrays returned by {@code Region.values()} shall be considered read-only. This constraint
exists
-     * for performance reasons because {@code Region} will recycle the same array in a way
that avoid
-     * fetching existing values.
-     *
-     * @param  width   number of pixel columns to store in the region.
-     * @param  height  number of pixel rows to store in the region.
-     * @return an accessor for sample values in a region of the given size.
-     *
-     * @see Raster#getPixels(int, int, int, int, double[])
-     */
-    public abstract Region region(final int width, final int height);
-
-    /**
-     * Holds sample values in a rectangular region of the image traversed by the iterator.
+     * Returns the sample values in a rectangular region starting at the current pixel position.
+     * The region size is the <cite>window size</cite> specified at {@code PixelIterator} construction
time.
+     * The length of the returned array will be
+     * <var>(number of bands)</var> × <var>(window width)</var>
× <var>(window height)</var>.
      * Values are always stored with band index varying fastest, then column index, then
row index.
      * Columns are traversed from left to right and rows are traversed from top to bottom
      * ({@link SequenceType#LINEAR} iteration order).
-     * This order is the same regardless iteration order of the enclosing pixel iterator.
+     * That order is the same regardless the {@linkplain #getIterationOrder() iteration order}
of this iterator.
      *
      * <div class="note"><b>Example:</b>
-     * for an RGB image, the 3 first values are the red, green and blue components of the
first pixel
-     * (first column of first row). The 3 next values are the red, green and blue components
of the pixel
-     * in the second column of the first row, <i>etc.</i></div>
-     *
-     * Regions are created by call to {@link PixelIterator#region(int, int)}.
-     * Once created, the same instance can be used for all regions of the given size traversed
during iteration.
-     */
-    public abstract static class Region {
-        /**
-         * Number of pixel columns stored in this region.
-         */
-        private final int width;
-
-        /**
-         * Number of pixel rows stored in this region.
-         */
-        private final int height;
-
-        /**
-         * Current sample values. This array is overwritten when {@link #values()} is invoked.
-         */
-        private final double[] values;
-
-        /**
-         * Creates a new region of the specified size.
-         *
-         * @param  width   number of pixel columns to store in the region.
-         * @param  height  number of pixel rows to store in the region.
-         */
-        protected Region(final int width, final int height) {
-            ArgumentChecks.ensureStrictlyPositive("width",  width);
-            ArgumentChecks.ensureStrictlyPositive("height", height);
-            this.width  = width;
-            this.height = height;
-            this.values = new double[width * height];
-        }
-
-        /**
-         * Returns sample values in the region starting at current iterator position.
-         * Values in the returned array are stored with band index varying fastest,
-         * then column index (from left to right), then row index (from top to bottom).
-         * The returned array is valid only until the next call to {@code values()}.
-         * The array shall only be read; behavior of this method become unspecified
-         * if caller modifies any values in the array.
-         *
-         * @return the sample values in the region starting at current iterator position.
-         */
-        public abstract double[] values();
-    }
+     * for an RGB image, the 3 first values are the red, green and blue components of the
pixel at
+     * {@linkplain #getPosition() current iterator position}. The 3 next values are the red,
green
+     * and blue components of the pixel at the right of current iterator position, <i>etc.</i></div>
+     *
+     * The returned region will be live: calls to {@link #next()} followed by {@code window()}
returns an array
+     * (potentially the same array instance than previous call) updated with values starting
at the new iterator
+     * position. The returned array is valid only until the next call to {@code window()}.
The array shall only
+     * be read; behavior of this method become unspecified if caller modifies any values
in the array.
+     *
+     * <div class="note"><b>Rational:</b>
+     * the read-only constraint on the returned array exists for performance reasons.
+     * This method may recycle the same array in a way that avoid fetching existing values.
+     * </div>
+     *
+     * The {@link #next()} method must have returned {@code true}, or the {@link #moveTo(int,int)}
method must have
+     * been invoked successfully, before this {@code window()} method is invoked. If above
condition is not met,
+     * then this method behavior is undefined: it may throw any runtime exception or return
meaningless values
+     * (there is no explicit bounds check for performance reasons).
+     *
+     * @return the sample values in the region starting at current iterator position.
+     *
+     * @see Raster#getPixels(int, int, int, int, double[])
+     */
+    public abstract double[] window();
 
     /**
      * Restores the iterator to the start position. After this method has been invoked,

Modified: sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/PixelIteratorFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/PixelIteratorFactory.java?rev=1803853&r1=1803852&r2=1803853&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/PixelIteratorFactory.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/PixelIteratorFactory.java
[UTF-8] Wed Aug  2 16:16:53 2017
@@ -58,7 +58,7 @@ final class PixelIteratorFactory {
 //                }
 //            }
 //        }
-        return new DefaultIterator(raster, subReadArea);
+        return new DefaultIterator(raster, subReadArea, null);
     }
 
     /**
@@ -93,7 +93,7 @@ final class PixelIteratorFactory {
 //                }
 //            }
 //        }
-        return new DefaultIterator(renderedImage, subReadArea);
+        return new DefaultIterator(renderedImage, subReadArea, null);
     }
 
     //-- NOT IMPLEMENTED YET

Modified: sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/WritablePixelIterator.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/WritablePixelIterator.java?rev=1803853&r1=1803852&r2=1803853&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/WritablePixelIterator.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-raster/src/main/java/org/apache/sis/image/WritablePixelIterator.java
[UTF-8] Wed Aug  2 16:16:53 2017
@@ -43,13 +43,13 @@ abstract class WritablePixelIterator ext
     private final WritableRenderedImage wRenderedImage;
 
     public WritablePixelIterator(WritableRaster raster, Rectangle subArea) {
-        super(raster, subArea);
+        super(raster, subArea, null);
         wRaster        = raster;
         wRenderedImage = null;
     }
 
     public WritablePixelIterator(WritableRenderedImage renderedImage, Rectangle subArea)
{
-        super(renderedImage, subArea);
+        super(renderedImage, subArea, null);
         wRaster        = null;
         wRenderedImage = renderedImage;
     }

Modified: sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/PixelIteratorTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/PixelIteratorTest.java?rev=1803853&r1=1803852&r2=1803853&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/PixelIteratorTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-raster/src/test/java/org/apache/sis/image/PixelIteratorTest.java
[UTF-8] Wed Aug  2 16:16:53 2017
@@ -16,8 +16,8 @@
  */
 package org.apache.sis.image;
 
-import java.util.Arrays;
 import java.awt.Point;
+import java.awt.Dimension;
 import java.awt.Rectangle;
 import java.awt.image.DataBuffer;
 import java.awt.image.PixelInterleavedSampleModel;
@@ -236,20 +236,6 @@ public strictfp class PixelIteratorTest
     }
 
     /**
-     * Creates a {@code PixelIterator} for the full area of given raster.
-     * The iterator shall be assigned to the {@link #iterator} field.
-     *
-     * <p>The default implementation creates read-only iterators.
-     * Tests for read-write iterators need to override.</p>
-     *
-     * @param  raster  the data on which to perform iteration.
-     */
-    void createPixelIterator(WritableRaster raster) {
-        iterator = new DefaultIterator(raster, null);
-        assertEquals("getIterationOrder()", SequenceType.LINEAR, iterator.getIterationOrder());
-    }
-
-    /**
      * Creates a {@code PixelIterator} for a sub-area of given raster.
      * The iterator shall be assigned to the {@link #iterator} field.
      *
@@ -260,35 +246,50 @@ public strictfp class PixelIteratorTest
      * @param  subArea  the boundary of the raster sub-area where to perform iteration.
      */
     void createPixelIterator(WritableRaster raster, Rectangle subArea) {
-        iterator = new DefaultIterator(raster, subArea);
+        iterator = new DefaultIterator(raster, subArea, null);
         assertEquals("getIterationOrder()", SequenceType.LINEAR, iterator.getIterationOrder());
     }
 
     /**
-     * Creates a {@code PixelIterator} for the full area of given image.
+     * Creates a {@code PixelIterator} for a sub-area of given image.
      * The iterator shall be assigned to the {@link #iterator} field.
      *
      * <p>The default implementation creates read-only iterators.
      * Tests for read-write iterators need to override.</p>
      *
-     * @param  image  the data on which to perform iteration.
+     * @param  image    the data on which to perform iteration.
+     * @param  subArea  the boundary of the image sub-area where to perform iteration.
      */
-    void createPixelIterator(WritableRenderedImage image) {
-        iterator = new DefaultIterator(image, null);
+    void createPixelIterator(WritableRenderedImage image, Rectangle subArea) {
+        iterator = new DefaultIterator(image, subArea, null);
     }
 
     /**
-     * Creates a {@code PixelIterator} for the full area of given image.
+     * Creates a {@code PixelIterator} for a window in the given image.
      * The iterator shall be assigned to the {@link #iterator} field.
      *
      * <p>The default implementation creates read-only iterators.
      * Tests for read-write iterators need to override.</p>
      *
      * @param  image    the data on which to perform iteration.
-     * @param  subArea  the boundary of the image sub-area where to perform iteration.
+     * @param  window   size of the window to use in {@link PixelIterator#window()} method.
      */
-    void createPixelIterator(WritableRenderedImage image, Rectangle subArea) {
-        iterator = new DefaultIterator(image, subArea);
+    void createWindowIterator(WritableRenderedImage image, Dimension window) {
+        iterator = new DefaultIterator(image, null, window);
+    }
+
+    /**
+     * Verifies the sample value at current iterator position.
+     *
+     * @param i  index in {@link #expected} array.
+     * @param b  band number at current iterator position.
+     */
+    private void verifySample(final int i, final int b) {
+        final float e = expected[i];
+        final float a = iterator.getSampleFloat(b);
+        if (Float.floatToRawIntBits(a) != Float.floatToRawIntBits(e)) {
+            fail("Pixel iteration at index " + i + ": expected " + e + " but got " + a);
+        }
     }
 
     /**
@@ -296,16 +297,15 @@ public strictfp class PixelIteratorTest
      *
      * @param verifyIndices  whether to verify also iterator {@code getPosition()} return
values.
      *                       This is usually {@code true} if an only if the iterator cover
the full raster area.
+     *
+     * @see #verifyIterationAfterMove(int, int)
+     * @see #verifyWindow(Dimension)
      */
     private void verifyIteration(final boolean verifyIndices) {
         int i = 0;
         while (iterator.next()) {
             for (int b=0; b<numBands; b++) {
-                final float e = expected[i];
-                final float a = iterator.getSampleFloat(b);
-                if (Float.floatToRawIntBits(a) != Float.floatToRawIntBits(e)) {
-                    fail("Pixel iteration at index " + i + ": expected " + e + " but got
" + a);
-                }
+                verifySample(i, b);
                 if (verifyIndices) {
                     final int p = i / numBands;
                     final Point position = iterator.getPosition();
@@ -327,7 +327,7 @@ public strictfp class PixelIteratorTest
         width    =  7;
         height   = 10;
         numBands =  3;
-        createPixelIterator(createRaster(null));
+        createPixelIterator(createRaster(null), null);
         verifyIteration(true);
     }
 
@@ -343,7 +343,7 @@ public strictfp class PixelIteratorTest
         width    =  8;
         height   =  7;
         numBands =  2;
-        createPixelIterator(createRaster(null));
+        createPixelIterator(createRaster(null), null);
         verifyIteration(true);
 
         iterator.rewind();
@@ -503,7 +503,7 @@ public strictfp class PixelIteratorTest
         width    =  5;
         height   =  4;
         numBands =  1;
-        createPixelIterator(createRaster(null));
+        createPixelIterator(createRaster(null), null);
         assertTrue("Expected a non-empty set of values.", expected.length != 0);
         try {
             iterator.moveTo(2, 3);
@@ -538,7 +538,7 @@ public strictfp class PixelIteratorTest
         tileWidth  =   8;
         tileHeight =   5;
         numBands   =   3;
-        createPixelIterator(createImage(null));
+        createPixelIterator(createImage(null), null);
         assertNull("getIterationOrder()", iterator.getIterationOrder());
         verifyIteration(false);
     }
@@ -558,7 +558,7 @@ public strictfp class PixelIteratorTest
         tileWidth  =   8;
         tileHeight =   5;
         numBands   =   2;
-        createPixelIterator(createImage(null));
+        createPixelIterator(createImage(null), null);
         assertNull("getIterationOrder()", iterator.getIterationOrder());
         verifyIteration(false);
 
@@ -861,7 +861,7 @@ public strictfp class PixelIteratorTest
         tileWidth  =  4;
         tileHeight =  3;
         numBands   =  1;
-        createPixelIterator(createImage(null));
+        createPixelIterator(createImage(null), null);
         assertTrue("Expected a non-empty set of values.", expected.length != 0);
         try {
             iterator.moveTo(102, 53);
@@ -884,7 +884,7 @@ public strictfp class PixelIteratorTest
         tileWidth  =  4;
         tileHeight =  3;
         numBands   =  1;
-        createPixelIterator(createImage(null));
+        createPixelIterator(createImage(null), null);
         assertTrue("Expected a non-empty set of values.", expected.length != 0);
         verifyIteration(false);
         try {
@@ -909,7 +909,7 @@ public strictfp class PixelIteratorTest
         numBands   =   2;
         minTileX   =  10;
         minTileY   = 100;
-        createPixelIterator(createImage(null));
+        createPixelIterator(createImage(null), null);
         assertTrue("Expected a non-empty set of values.", expected.length != 0);
         int i = 0;
         for (int ty = 0; ty < height/tileHeight; ty++) {
@@ -931,39 +931,44 @@ public strictfp class PixelIteratorTest
     }
 
     /**
-     * Moves the iterator to the given position and discards the {@link #expected} values
prior that position.
-     * Then, verifies the iteration. This method is used for implementation of {@code testMoveXXX()}
methods.
+     * Moves the iterator to the given position and verifies the iteration.
+     * This method is used for implementation of {@code testMoveXXX()} methods.
+     *
+     * @see #verifyIteration(boolean)
+     * @see #verifyWindow(Dimension)
      */
     private void verifyIterationAfterMove(int x, int y) {
+        /*
+         * Move the iterator and verify location after the move.
+         */
         iterator.moveTo(x, y);
         final Point p = iterator.getPosition();
         assertEquals("x", x, p.x);
         assertEquals("y", y, p.y);
+        /*
+         * Compute index of the (x,y) position in the array of expected values.
+         * Iteration verification will need to begin at that value.
+         */
         x -= xmin;
         y -= ymin;
-        final int pixelIndex;
+        int i;
         if (tileWidth == 0 && tileHeight == 0) {
-            pixelIndex = y*width + x;
+            i = y * width + x;
         } else {
             final int tx = x / tileWidth;
             final int ty = y / tileHeight;
             final int numTileX = (width + tileWidth - 1) / tileWidth;
-            pixelIndex = ((ty * (numTileX - 1) + tx) * tileHeight + y - tx) * tileWidth +
x;
+            i = ((ty * (numTileX - 1) + tx) * tileHeight + y - tx) * tileWidth + x;
         }
-        expected = Arrays.copyOfRange(expected, pixelIndex * numBands, expected.length);
+        i *= numBands;
         /*
-         * Following is a copy of 'verifyIteration(boolean)' except that we use a do …
while loop
-         * instead than a while loop. See PixelIterator.moveTo(int,int) documentation.
+         * Iteration verification happens here. Note that contrarily to 'verifyIteration(boolean)'
method,
+         * we use a do … while loop instead than a while loop because the call to 'moveTo(x,
y)' should be
+         * understood as an implicit 'next()' method call.
          */
-        int i = 0;
         do {
             for (int b=0; b<numBands; b++) {
-                final float e = expected[i];
-                final float a = iterator.getSampleFloat(b);
-                if (Float.floatToRawIntBits(a) != Float.floatToRawIntBits(e)) {
-                    fail("Pixel iteration at index " + i + ": expected " + e + " but got
" + a);
-                }
-                i++;
+                verifySample(i++, b);
             }
         } while (iterator.next());
         assertEquals("Too few elements in iteration.", expected.length, i);
@@ -980,7 +985,7 @@ public strictfp class PixelIteratorTest
         width    =  8;
         height   =  9;
         numBands =  2;
-        createPixelIterator(createRaster(null));
+        createPixelIterator(createRaster(null), null);
         verifyIterationAfterMove(8, 10);
     }
 
@@ -999,7 +1004,90 @@ public strictfp class PixelIteratorTest
         numBands   =   1;
         minTileX   = 120;
         minTileY   = 200;
-        createPixelIterator(createImage(null));
+        createPixelIterator(createImage(null), null);
         verifyIterationAfterMove(7, 5);
     }
+
+    /**
+     * Verifies {@link PixelIterator#window()}.
+     * This method assumes that the iterator traverses the full image (no sub-area).
+     *
+     * @see #verifyIteration(boolean)
+     * @see #verifyIterationAfterMove(int, int)
+     */
+    private void verifyWindow(final Dimension window) {
+        final int tileSize   = tileWidth * tileHeight;
+        final int tileStride = tileSize * (width / tileWidth);
+        while (iterator.next()) {
+            final Point pos = iterator.getPosition();
+            pos.translate(-xmin, -ymin);
+            final double[] values = iterator.window();
+            int i = 0;
+            for (int y=0; y<window.height; y++) {
+                int p,t;
+                p  = pos.y + y;
+                t  = p / tileHeight;
+                p %=     tileHeight;
+                final int start = t * tileStride + p * tileWidth;
+                for (int x=0; x<window.width; x++) {
+                    p  = pos.x + x;
+                    t  = p / tileWidth;
+                    p %=     tileWidth;
+                    int offset = (start + t * tileSize + p) * numBands;
+                    for (int b=0; b<numBands; b++) {
+                        final double e = expected[offset++];
+                        final double a = values[i++];
+                        if (Double.doubleToRawLongBits(a) != Double.doubleToRawLongBits(e))
{
+                            fail("Index (" + x + ", " + y + ") in window starting at index
("
+                                    + pos.x + ", " + pos.y + "), band " + b + ": expected
" + e + " but got " + a);
+                        }
+                    }
+                }
+            }
+            assertEquals("window().length", i, values.length);
+            java.util.Arrays.fill(iterator.window, Double.NaN);
+        }
+    }
+
+    /**
+     * Tests {@link PixelIterator#window()} on a single tile.
+     */
+    @Test
+    @DependsOnMethod("testMoveIntoImage")
+    public void testWindowOnTile() {
+        xmin       =   1;
+        ymin       =  -2;
+        width      =   8;
+        height     =  10;
+        numBands   =   2;
+        tileWidth  = width;
+        tileHeight = height;
+        final Dimension window = new Dimension(3, 4);
+        createWindowIterator(createImage(null), window);
+        assertTrue("Expected a non-empty set of values.", expected.length != 0);
+        assertEquals("getIterationOrder()", SequenceType.LINEAR, iterator.getIterationOrder());
+        verifyWindow(window);
+    }
+
+    /**
+     * Tests {@link PixelIterator#window()} on a tiled image.
+     */
+    @Test
+    @DependsOnMethod("testWindowOnTile")
+    public void testWindowOnImage() {
+        xmin       =   1;
+        ymin       =  -2;
+        width      =   9;
+        height     =  12;
+        tileWidth  =   3;
+        tileHeight =   4;
+        numBands   =   2;
+        minTileX   = 100;
+        minTileY   = 200;
+        final Dimension window = new Dimension(2, 3);
+        createWindowIterator(createImage(null), window);
+        assertTrue("Expected a non-empty set of values.", expected.length != 0);
+        assertNull("getIterationOrder()", iterator.getIterationOrder());
+        verifyWindow(window);
+    }
 }



Mime
View raw message