You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2019/12/29 22:40:38 UTC

[sis] 02/03: Add more tests for ReshapedImage and fix a few bugs in this process.

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 a32a606dbf8f96f54f619a0abeae43c0b946d789
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Sun Dec 29 22:55:45 2019 +0100

    Add more tests for ReshapedImage and fix a few bugs in this process.
---
 .../apache/sis/coverage/grid/ReshapedImage.java    |  31 +++-
 .../sis/coverage/grid/ReshapedImageTest.java       | 171 +++++++++++++++++++--
 .../sis/internal/coverage/j2d/PlanarImageTest.java |   2 +-
 .../apache/sis/test/suite/FeatureTestSuite.java    |   6 +-
 4 files changed, 183 insertions(+), 27 deletions(-)

diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ReshapedImage.java b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ReshapedImage.java
index 7fd6ab3..bb4fe6c 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ReshapedImage.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ReshapedImage.java
@@ -24,6 +24,7 @@ import java.awt.image.SampleModel;
 import java.awt.image.ColorModel;
 import java.awt.image.WritableRaster;
 import org.apache.sis.internal.coverage.j2d.PlanarImage;
+import org.apache.sis.util.ArgumentChecks;
 
 import static java.lang.Math.min;
 import static java.lang.Math.max;
@@ -131,8 +132,8 @@ final class ReshapedImage extends PlanarImage {
         minY     = toIntExact(y);
         width    = toIntExact(min(upperX, (maxTX + 1) * tw + xo) - sx);
         height   = toIntExact(min(upperY, (maxTY + 1) * th + yo) - sy);
-        offsetX  = toIntExact(x - lowerX);
-        offsetY  = toIntExact(y - lowerY);
+        offsetX  = toIntExact(x - sx);
+        offsetY  = toIntExact(y - sy);
         minTileX = toIntExact(minTX);
         minTileY = toIntExact(minTY);
     }
@@ -224,7 +225,15 @@ final class ReshapedImage extends PlanarImage {
      */
     @Override
     public Raster getData() {
-        return offset(image.getData());
+        /*
+         * If this image contains all data, delegate to RenderedImage.getData()
+         * in case some implementations provide an optimized method. Otherwise
+         * ask only the sub-region covered by this image.
+         */
+        if (width >= image.getWidth() && height >= image.getHeight()) {
+            return offset(image.getData());
+        }
+        return copyData(new Rectangle(minX, minY, width, height));
     }
 
     /**
@@ -235,8 +244,16 @@ final class ReshapedImage extends PlanarImage {
      * @return a copy of this image in the given area of interest.
      */
     @Override
-    public Raster getData(Rectangle aoi) {
-        aoi = new Rectangle(aoi);
+    public Raster getData(final Rectangle aoi) {
+        ArgumentChecks.ensureNonNull("aoi", aoi);
+        return copyData(new Rectangle(aoi));
+    }
+
+    /**
+     * Implementation of {@link #getData(Rectangle)}. This implementation will modify the given {@code aoi}
+     * argument. If that argument was supplied by user, then it should first be copied by the caller.
+     */
+    private Raster copyData(final Rectangle aoi) {
         aoi.x = subtractExact(aoi.x, offsetX);      // Convert coordinate from this image to wrapped image.
         aoi.y = subtractExact(aoi.y, offsetY);
         final Raster data = image.getData(aoi);
@@ -276,8 +293,8 @@ final class ReshapedImage extends PlanarImage {
     public String verify() {
         final String error = super.verify();
         if (error == null) {
-            if (getMinX() != image.getMinX() + offsetX) return "minX";
-            if (getMinY() != image.getMinY() + offsetY) return "minY";
+            if (getMinX() != image.getMinX() + (minTileX - image.getMinTileX()) * getTileWidth()  + offsetX) return "minX";
+            if (getMinY() != image.getMinY() + (minTileY - image.getMinTileY()) * getTileHeight() + offsetY) return "minY";
             if (getTileGridXOffset() != super.getTileGridXOffset()) return "tileGridXOffset";
             if (getTileGridYOffset() != super.getTileGridYOffset()) return "tileGridYOffset";
         }
diff --git a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/ReshapedImageTest.java b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/ReshapedImageTest.java
index de15b71..6155bf9 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/ReshapedImageTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/ReshapedImageTest.java
@@ -16,8 +16,12 @@
  */
 package org.apache.sis.coverage.grid;
 
+import java.util.Random;
+import java.awt.image.DataBuffer;
 import java.awt.image.BufferedImage;
-import java.awt.image.WritableRaster;
+import org.apache.sis.image.TiledImageMock;
+import org.apache.sis.test.DependsOn;
+import org.apache.sis.test.TestUtilities;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
@@ -34,25 +38,160 @@ import static org.apache.sis.test.FeatureAssert.assertValuesEqual;
  * @since   1.1
  * @module
  */
+@DependsOn(org.apache.sis.internal.coverage.j2d.PlanarImageTest.class)
 public final strictfp class ReshapedImageTest extends TestCase {
     /**
-     * Tests with a request starting on the left and on top of data.
+     * Size of tiles used in this test.
+     */
+    private static final int TILE_WIDTH = 3, TILE_HEIGHT = 2;
+
+    /**
+     * Expected coordinates of image upper-left corner. Default value is (0,0).
+     */
+    private int minX, minY;
+
+    /**
+     * Expected index of first tile. Default value is (0,0).
+     */
+    private int minTileX, minTileY;
+
+    /**
+     * Expected number of tiles. Shall be initialized by test method
+     * before to invoke {@link #verifyLayout(ReshapedImage)}.
+     */
+    private int numXTiles, numYTiles;
+
+    /**
+     * Expected values of image size. Shall be initialized by test
+     * method before to invoke {@link #verifyLayout(ReshapedImage)}.
+     */
+    private int width, height;
+
+    /**
+     * Expected values of tile grid offset. Shall be initialized by test
+     * method before to invoke {@link #verifyLayout(ReshapedImage)}.
+     */
+    private int tileXOffset, tileYOffset;
+
+    /**
+     * Tests wrapping a {@link BufferedImage}. This single case has only one tile
+     * with pixel coordinates starting at (0,0).
      */
     @Test
-    public void testRequestBefore() {
-        final BufferedImage image = new BufferedImage(2, 2, BufferedImage.TYPE_BYTE_GRAY);
-        final WritableRaster raster = image.getRaster();
-        raster.setSample(0, 0, 0, 1);
-        raster.setSample(1, 0, 0, 2);
-        raster.setSample(0, 1, 0, 3);
-        raster.setSample(1, 1, 0, 4);
-
-        final ReshapedImage trs = new ReshapedImage(image, -1, -2, 4, 4);
-        assertEquals(1, trs.getMinX());
-        assertEquals(2, trs.getMinY());
-        assertValuesEqual(trs.getData(), 0, new int[][] {
-            {1, 2},
-            {3, 4}
+    public void testSingleTile() {
+        numXTiles = 1;
+        numYTiles = 1;
+        width     = TILE_WIDTH;
+        height    = TILE_HEIGHT;
+        final BufferedImage data = new BufferedImage(TILE_WIDTH, TILE_HEIGHT, BufferedImage.TYPE_BYTE_GRAY);
+        data.getRaster().setSamples(0, 0, TILE_WIDTH, TILE_HEIGHT, 0, new int[] {
+            1, 2, 3,
+            4, 7, 6
+        });
+        /*
+         * Tests with a request starting on the left and on top of data.
+         * The requested size is larger than image size; constructor shall clamp.
+         */
+        tileXOffset = minX = 1;
+        tileYOffset = minY = 2;
+        verifySingleTile(new ReshapedImage(data, -1, -2, 4, 4));
+        /*
+         * Tests with a request inside the image. Constructor should expand to
+         * an integer number of tiles, which is the whole image for this test.
+         */
+        tileXOffset = minX = -2;
+        tileYOffset = minY = -1;
+        verifySingleTile(new ReshapedImage(data, 2, 1, 1, 1));
+    }
+
+    /**
+     * Verify an image created by {@link #testSingleTile()}.
+     *
+     * @param  image   the reshaped image.
+     */
+    private void verifySingleTile(final ReshapedImage image) {
+        verifyLayout(image);
+        assertValuesEqual(image.getData(), 0, new int[][] {
+            {1, 2, 3},
+            {4, 7, 6}
+        });
+    }
+
+    /**
+     * Verifies the image properties (size, number of tiles).
+     *
+     * @param  image  the image to verify.
+     */
+    private void verifyLayout(final ReshapedImage image) {
+        assertNull(               image.verify());
+        assertEquals(minX,        image.getMinX());
+        assertEquals(minY,        image.getMinY());
+        assertEquals(width,       image.getWidth());
+        assertEquals(height,      image.getHeight());
+        assertEquals(TILE_WIDTH,  image.getTileWidth());
+        assertEquals(TILE_HEIGHT, image.getTileHeight());
+        assertEquals(minTileX,    image.getMinTileX());
+        assertEquals(minTileY,    image.getMinTileY());
+        assertEquals(numXTiles,   image.getNumXTiles());
+        assertEquals(numYTiles,   image.getNumYTiles());
+        assertEquals(tileXOffset, image.getTileGridXOffset());
+        assertEquals(tileYOffset, image.getTileGridYOffset());
+    }
+
+    /**
+     * Tests wrapping a {@link TiledImageMock}.
+     */
+    @Test
+    public void testMultiTiles() {
+        final Random random = TestUtilities.createRandomNumberGenerator(219970242558564L);
+        final int dataMinX, dataMinY;
+        dataMinX  = random.nextInt(20) - 10;
+        dataMinY  = random.nextInt(20) - 10;
+        minTileX  = random.nextInt(20) - 10;
+        minTileY  = random.nextInt(20) - 10;
+        numXTiles = 5;
+        numYTiles = 4;
+        width     = numXTiles * TILE_WIDTH;
+        height    = numYTiles * TILE_HEIGHT;
+        final TiledImageMock data = new TiledImageMock(DataBuffer.TYPE_USHORT, 1, dataMinX, dataMinY,
+                                        width, height, TILE_WIDTH, TILE_HEIGHT, minTileX, minTileY);
+        data.validate();
+        data.initializeAllTiles(0);
+        /*
+         * Apply only a translation, keep all tiles.
+         */
+        tileXOffset = (minX =  7) - minTileX * TILE_WIDTH;
+        tileYOffset = (minY = 13) - minTileY * TILE_HEIGHT;
+        ReshapedImage image = new ReshapedImage(data, dataMinX - 7, dataMinY - 13, 100, 100);
+        verifyLayout(image);
+        assertValuesEqual(image.getData(), 0, new int[][] {
+            { 100,  101,  102  ,   200,  201,  202  ,   300,  301,  302  ,   400,  401,  402  ,   500,  501,  502},
+            { 110,  111,  112  ,   210,  211,  212  ,   310,  311,  312  ,   410,  411,  412  ,   510,  511,  512},
+            { 600,  601,  602  ,   700,  701,  702  ,   800,  801,  802  ,   900,  901,  902  ,  1000, 1001, 1002},
+            { 610,  611,  612  ,   710,  711,  712  ,   810,  811,  812  ,   910,  911,  912  ,  1010, 1011, 1012},
+            {1100, 1101, 1102  ,  1200, 1201, 1202  ,  1300, 1301, 1302  ,  1400, 1401, 1402  ,  1500, 1501, 1502},
+            {1110, 1111, 1112  ,  1210, 1211, 1212  ,  1310, 1311, 1312  ,  1410, 1411, 1412  ,  1510, 1511, 1512},
+            {1600, 1601, 1602  ,  1700, 1701, 1702  ,  1800, 1801, 1802  ,  1900, 1901, 1902  ,  2000, 2001, 2002},
+            {1610, 1611, 1612  ,  1710, 1711, 1712  ,  1810, 1811, 1812  ,  1910, 1911, 1912  ,  2010, 2011, 2012}
+        });
+        /*
+         * Ask for a subregion of the image. The subregion starts at (5,3) and ends at (9,5) inclusive.
+         * ReshapedImageTest shall expand to an integer number of tiles, which result in (3,2) - (11,5).
+         * This is 3×2 tiles.
+         */
+        minTileX++;         // Skip one tile on the left.
+        minTileY++;         // Skip one tile on the bottom.
+        width       = (numXTiles = 3) * TILE_WIDTH;
+        height      = (numYTiles = 2) * TILE_HEIGHT;
+        tileXOffset = (minX = -2) - minTileX * TILE_WIDTH;
+        tileYOffset = (minY = -1) - minTileY * TILE_HEIGHT;
+        image = new ReshapedImage(data, dataMinX + 5, dataMinY + 3, dataMinX + 9, dataMinY + 5);
+        verifyLayout(image);
+        assertValuesEqual(image.getData(), 0, new int[][] {
+            { 700,  701,  702  ,   800,  801,  802  ,   900,  901,  902},
+            { 710,  711,  712  ,   810,  811,  812  ,   910,  911,  912},
+            {1200, 1201, 1202  ,  1300, 1301, 1302  ,  1400, 1401, 1402},
+            {1210, 1211, 1212  ,  1310, 1311, 1312  ,  1410, 1411, 1412}
         });
     }
 }
diff --git a/core/sis-feature/src/test/java/org/apache/sis/internal/coverage/j2d/PlanarImageTest.java b/core/sis-feature/src/test/java/org/apache/sis/internal/coverage/j2d/PlanarImageTest.java
index e25f534..c983c3e 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/internal/coverage/j2d/PlanarImageTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/internal/coverage/j2d/PlanarImageTest.java
@@ -66,7 +66,7 @@ public final strictfp class PlanarImageTest extends TestCase {
                 TILE_HEIGHT * 3,                // height
                 TILE_WIDTH,
                 TILE_HEIGHT,
-                random.nextInt(20) - 10,        // minTileX,
+                random.nextInt(20) - 10,        // minTileX
                 random.nextInt(20) - 10);       // minTileY
         image.validate();
         image.initializeAllTiles(0);
diff --git a/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java b/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
index e9a6f4c..73940c8 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
@@ -74,6 +74,9 @@ import org.junit.runners.Suite;
     org.apache.sis.feature.builder.FeatureTypeBuilderTest.class,
 
     // Rasters
+    org.apache.sis.internal.coverage.j2d.ImageUtilitiesTest.class,
+    org.apache.sis.internal.coverage.j2d.ScaledColorSpaceTest.class,
+    org.apache.sis.internal.coverage.j2d.PlanarImageTest.class,
     org.apache.sis.image.DefaultIteratorTest.class,
     org.apache.sis.image.LinearIteratorTest.class,
     org.apache.sis.coverage.CategoryTest.class,
@@ -87,9 +90,6 @@ import org.junit.runners.Suite;
     org.apache.sis.coverage.grid.FractionalGridCoordinatesTest.class,
     org.apache.sis.coverage.grid.ReshapedImageTest.class,
     org.apache.sis.coverage.grid.GridCoverage2DTest.class,
-    org.apache.sis.internal.coverage.j2d.ImageUtilitiesTest.class,
-    org.apache.sis.internal.coverage.j2d.ScaledColorSpaceTest.class,
-    org.apache.sis.internal.coverage.j2d.PlanarImageTest.class,
     org.apache.sis.internal.coverage.j2d.BufferedGridCoverageTest.class
 })
 public final strictfp class FeatureTestSuite extends TestSuite {