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 7476cb39e4a20d79ab98a2e15137613831bd8d5a Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Sun Apr 24 16:27:45 2022 +0200 Add test cases for BIL/BIL/BSQ formats and fixes a few bugs identified by those tests. --- .../org/apache/sis/internal/util/Numerics.java | 2 +- ide-project/NetBeans/build.xml | 2 + .../sis/internal/storage/esri/RawRasterReader.java | 51 ++++++++++++++------- .../BILConsistencyTest.java} | 26 +++++------ .../BIPConsistencyTest.java} | 26 +++++------ .../BSQConsistencyTest.java} | 26 +++++------ .../storage/image/SelfConsistencyTest.java | 4 +- .../apache/sis/test/suite/StorageTestSuite.java | 3 ++ .../org/apache/sis/internal/storage/esri/BIL.hdr | 9 ++++ .../org/apache/sis/internal/storage/esri/BIL.raw | Bin 0 -> 243 bytes .../org/apache/sis/internal/storage/esri/BIP.hdr | 12 +++++ .../org/apache/sis/internal/storage/esri/BIP.raw | Bin 0 -> 243 bytes .../org/apache/sis/internal/storage/esri/BSQ.hdr | 13 ++++++ .../org/apache/sis/internal/storage/esri/BSQ.raw | Bin 0 -> 243 bytes .../org/apache/sis/internal/storage/esri/grid.prj | 4 ++ 15 files changed, 114 insertions(+), 64 deletions(-) diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java b/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java index 6f7bea5f17..f5700385be 100644 --- a/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java +++ b/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java @@ -233,7 +233,7 @@ public final class Numerics extends Static { * @throws ArithmeticException if y is zero of if the result of x/y is not an integer. */ public static int wholeDiv(final int x, final int y) { - if ((x % y) != 0) throw new ArithmeticException(); + if ((x % y) != 0) throw new ArithmeticException(x + " % " + y + " ≠ 0"); return x / y; // TODO: use Math.divideExact with JDK18. } diff --git a/ide-project/NetBeans/build.xml b/ide-project/NetBeans/build.xml index 7e9bc0715d..557ef9f261 100644 --- a/ide-project/NetBeans/build.xml +++ b/ide-project/NetBeans/build.xml @@ -303,6 +303,8 @@ <fileset dir="${project.root}/storage/sis-storage/src/test/resources"> <include name="**/*.txt"/> <include name="**/*.asc"/> + <include name="**/*.hdr"/> + <include name="**/*.raw"/> <include name="**/*.png"/> <include name="**/*.pgw"/> <include name="**/*.prj"/> diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/esri/RawRasterReader.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/esri/RawRasterReader.java index 449c09aded..22c93e9a23 100644 --- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/esri/RawRasterReader.java +++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/esri/RawRasterReader.java @@ -43,6 +43,7 @@ import static java.lang.Math.addExact; import static java.lang.Math.multiplyExact; import static java.lang.Math.incrementExact; import static org.apache.sis.internal.util.Numerics.ceilDiv; +import static org.apache.sis.internal.util.Numerics.wholeDiv; import static org.apache.sis.internal.jdk9.JDK9.multiplyFull; @@ -63,6 +64,13 @@ final class RawRasterReader extends HyperRectangleReader { */ private static final int BIDIMENSIONAL = 2; + /** + * Index of a two-dimensional dimension selected by this reader. + * Note that the (<var>x</var>,<var>y</var>) axis order also appears implicitly in some method calls; + * modifying the values of those constants is not sufficient if different axis indices were wanted. + */ + private static final int X_DIMENSION = 0, Y_DIMENSION = 1; + /** * The full image size together with the "grid to CRS" transform. */ @@ -144,12 +152,10 @@ final class RawRasterReader extends HyperRectangleReader { } fullSize = new long[] {scanlineStride, height}; regionLower = new long[BIDIMENSIONAL]; - regionUpper = new long[BIDIMENSIONAL]; + regionUpper = fullSize.clone(); if (domain == null) { - domain = gridGeometry; - regionUpper[0] = ceilDiv(multiplyFull(width, pixelStrideNumerator), pixelStrideDivisor); - regionUpper[1] = height; - subsampling = new int[] {1, 1}; + domain = gridGeometry; + subsampling = new int[] {1, 1}; } else { /* * Take in account the requested domain with the following restrictions: @@ -158,23 +164,37 @@ final class RawRasterReader extends HyperRectangleReader { * to be aligned on an integer amount of sample values. * (2) If there is more than one band and those bands are stored in pixel * interleaved fashion, we can not apply subsampling on the X axis. + * (3) If the layout is BIL, we do not support sub-region and subsampling + * on the X axis in current version. */ + int firstModifiableDimension = X_DIMENSION; final GridDerivation gd = gridGeometry.derive(); - if (pixelStrideDivisor > 1) { - gd.chunkSize(pixelStrideDivisor / pixelStrideNumerator); // Restriction #1 + if (pixelStrideDivisor > 1) { // Restriction #1 + gd.chunkSize(pixelStrideDivisor / pixelStrideNumerator); } - if (pixelStrideNumerator != pixelStrideDivisor) { - gd.maximumSubsampling(1); // Restriction #2 + if (pixelStrideNumerator != pixelStrideDivisor) { // Restriction #2 + gd.maximumSubsampling(1); + } + if (layout.getClass() == ComponentSampleModel.class) { // Restriction #3 + firstModifiableDimension = Y_DIMENSION; + gd.chunkSize(scanlineStride); + gd.maximumSubsampling(1); } final GridExtent ex = gd.subgrid(domain).getIntersection(); - for (int i=0; i<BIDIMENSIONAL; i++) { - regionLower[i] = floorDiv(multiplyExact(ex.getLow(i), pixelStrideNumerator), pixelStrideDivisor); - regionUpper[i] = incrementExact(ceilDiv(multiplyExact(ex.getHigh(i), pixelStrideNumerator), pixelStrideDivisor)); + for (int i=firstModifiableDimension; i<BIDIMENSIONAL; i++) { + regionLower[i] = ex.getLow(i); + regionUpper[i] = incrementExact(ex.getHigh(i)); + } + if (X_DIMENSION >= firstModifiableDimension) { + regionLower[X_DIMENSION] = floorDiv(multiplyExact(regionLower[X_DIMENSION], pixelStrideNumerator), pixelStrideDivisor); + regionUpper[X_DIMENSION] = ceilDiv(multiplyExact(regionUpper[X_DIMENSION], pixelStrideNumerator), pixelStrideDivisor); } subsampling = gd.getSubsampling(); domain = gd.build(); } final Region region = new Region(fullSize, regionLower, regionUpper, subsampling); + int regionWidth = region.getTargetSize(X_DIMENSION); + int regionHeight = region.getTargetSize(Y_DIMENSION); /* * Now perform the actual reading of sample values. In the BSQ (Band sequential) case, * bands are read in the order they appear in the file (not necessarily the order requested by the caller). @@ -214,15 +234,14 @@ final class RawRasterReader extends HyperRectangleReader { buffer = new Buffer[] { readAsBuffer(region, 0) }; + regionWidth = wholeDiv(regionWidth, sm.getNumBands()); } /* * AT this point the data have been read. Adjust the sample model to the new data size (if different), * build the raster then apply band subseting if it was not done at reading time. */ - final int tw = region.getTargetSize(0); - final int th = region.getTargetSize(1); - if (tw != width || th != height) { - sm = sm.createCompatibleSampleModel(tw, th); + if (regionWidth != width || regionHeight != height) { + sm = sm.createCompatibleSampleModel(regionWidth, regionHeight); } final DataBuffer data = RasterFactory.wrap(DataType.forDataBufferType(sm.getDataType()), buffer); WritableRaster raster = WritableRaster.createWritableRaster(sm, data, null); diff --git a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/image/SelfConsistencyTest.java b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/esri/BILConsistencyTest.java similarity index 69% copy from storage/sis-storage/src/test/java/org/apache/sis/internal/storage/image/SelfConsistencyTest.java copy to storage/sis-storage/src/test/java/org/apache/sis/internal/storage/esri/BILConsistencyTest.java index a2858cfadc..da2396d199 100644 --- a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/image/SelfConsistencyTest.java +++ b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/esri/BILConsistencyTest.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.internal.storage.image; +package org.apache.sis.internal.storage.esri; import java.net.URL; import java.io.IOException; @@ -24,26 +24,22 @@ import org.apache.sis.test.storage.CoverageReadConsistency; import org.junit.AfterClass; import org.junit.BeforeClass; -import static org.junit.Assume.assumeNotNull; +import static org.junit.Assert.assertNotNull; /** - * Test consistency of read operations in random domains. - * Assuming that the code reading the full extent is correct, this class can detect some bugs - * in the code reading sub-regions or applying sub-sampling. This assumption is reasonable if - * we consider that the code reading the full extent is usually simpler than the code reading - * a subset of data. + * Test consistency of read operations in random domains of a BIP (Band Interleaved by Line) file. * * @author Martin Desruisseaux (Geomatys) * @version 1.2 * @since 1.2 * @module */ -public final strictfp class SelfConsistencyTest extends CoverageReadConsistency { +public final strictfp class BILConsistencyTest extends CoverageReadConsistency { /** * The store used for the test, opened only once. */ - private static WorldFileStore store; + private static RawRasterStore store; /** * Opens the test file to be used for all tests. @@ -53,9 +49,9 @@ public final strictfp class SelfConsistencyTest extends CoverageReadConsistency */ @BeforeClass public static void openFile() throws IOException, DataStoreException { - final URL url = WorldFileStoreTest.class.getResource("gradient.png"); - assumeNotNull(url); - store = new WorldFileStore(null, new StorageConnector(url), true); + final URL url = BIPConsistencyTest.class.getResource("BIL.raw"); + assertNotNull("Test file not found.", url); + store = new RawRasterStore(null, new StorageConnector(url)); } /** @@ -65,7 +61,7 @@ public final strictfp class SelfConsistencyTest extends CoverageReadConsistency */ @AfterClass public static void closeFile() throws DataStoreException { - final WorldFileStore s = store; + final RawRasterStore s = store; if (s != null) { store = null; // Clear first in case of failure. s.close(); @@ -77,7 +73,7 @@ public final strictfp class SelfConsistencyTest extends CoverageReadConsistency * * @throws DataStoreException if an error occurred while fetching the first image. */ - public SelfConsistencyTest() throws DataStoreException { - super(store.components().iterator().next()); + public BILConsistencyTest() throws DataStoreException { + super(store); } } diff --git a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/image/SelfConsistencyTest.java b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/esri/BIPConsistencyTest.java similarity index 69% copy from storage/sis-storage/src/test/java/org/apache/sis/internal/storage/image/SelfConsistencyTest.java copy to storage/sis-storage/src/test/java/org/apache/sis/internal/storage/esri/BIPConsistencyTest.java index a2858cfadc..4112d84eb9 100644 --- a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/image/SelfConsistencyTest.java +++ b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/esri/BIPConsistencyTest.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.internal.storage.image; +package org.apache.sis.internal.storage.esri; import java.net.URL; import java.io.IOException; @@ -24,26 +24,22 @@ import org.apache.sis.test.storage.CoverageReadConsistency; import org.junit.AfterClass; import org.junit.BeforeClass; -import static org.junit.Assume.assumeNotNull; +import static org.junit.Assert.assertNotNull; /** - * Test consistency of read operations in random domains. - * Assuming that the code reading the full extent is correct, this class can detect some bugs - * in the code reading sub-regions or applying sub-sampling. This assumption is reasonable if - * we consider that the code reading the full extent is usually simpler than the code reading - * a subset of data. + * Test consistency of read operations in random domains of a BIP (Band Interleaved by Pixel) file. * * @author Martin Desruisseaux (Geomatys) * @version 1.2 * @since 1.2 * @module */ -public final strictfp class SelfConsistencyTest extends CoverageReadConsistency { +public final strictfp class BIPConsistencyTest extends CoverageReadConsistency { /** * The store used for the test, opened only once. */ - private static WorldFileStore store; + private static RawRasterStore store; /** * Opens the test file to be used for all tests. @@ -53,9 +49,9 @@ public final strictfp class SelfConsistencyTest extends CoverageReadConsistency */ @BeforeClass public static void openFile() throws IOException, DataStoreException { - final URL url = WorldFileStoreTest.class.getResource("gradient.png"); - assumeNotNull(url); - store = new WorldFileStore(null, new StorageConnector(url), true); + final URL url = BIPConsistencyTest.class.getResource("BIP.raw"); + assertNotNull("Test file not found.", url); + store = new RawRasterStore(null, new StorageConnector(url)); } /** @@ -65,7 +61,7 @@ public final strictfp class SelfConsistencyTest extends CoverageReadConsistency */ @AfterClass public static void closeFile() throws DataStoreException { - final WorldFileStore s = store; + final RawRasterStore s = store; if (s != null) { store = null; // Clear first in case of failure. s.close(); @@ -77,7 +73,7 @@ public final strictfp class SelfConsistencyTest extends CoverageReadConsistency * * @throws DataStoreException if an error occurred while fetching the first image. */ - public SelfConsistencyTest() throws DataStoreException { - super(store.components().iterator().next()); + public BIPConsistencyTest() throws DataStoreException { + super(store); } } diff --git a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/image/SelfConsistencyTest.java b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/esri/BSQConsistencyTest.java similarity index 69% copy from storage/sis-storage/src/test/java/org/apache/sis/internal/storage/image/SelfConsistencyTest.java copy to storage/sis-storage/src/test/java/org/apache/sis/internal/storage/esri/BSQConsistencyTest.java index a2858cfadc..2d2adccbe8 100644 --- a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/image/SelfConsistencyTest.java +++ b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/esri/BSQConsistencyTest.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.internal.storage.image; +package org.apache.sis.internal.storage.esri; import java.net.URL; import java.io.IOException; @@ -24,26 +24,22 @@ import org.apache.sis.test.storage.CoverageReadConsistency; import org.junit.AfterClass; import org.junit.BeforeClass; -import static org.junit.Assume.assumeNotNull; +import static org.junit.Assert.assertNotNull; /** - * Test consistency of read operations in random domains. - * Assuming that the code reading the full extent is correct, this class can detect some bugs - * in the code reading sub-regions or applying sub-sampling. This assumption is reasonable if - * we consider that the code reading the full extent is usually simpler than the code reading - * a subset of data. + * Test consistency of read operations in random domains of a BSQ (Band Sequential) file. * * @author Martin Desruisseaux (Geomatys) * @version 1.2 * @since 1.2 * @module */ -public final strictfp class SelfConsistencyTest extends CoverageReadConsistency { +public final strictfp class BSQConsistencyTest extends CoverageReadConsistency { /** * The store used for the test, opened only once. */ - private static WorldFileStore store; + private static RawRasterStore store; /** * Opens the test file to be used for all tests. @@ -53,9 +49,9 @@ public final strictfp class SelfConsistencyTest extends CoverageReadConsistency */ @BeforeClass public static void openFile() throws IOException, DataStoreException { - final URL url = WorldFileStoreTest.class.getResource("gradient.png"); - assumeNotNull(url); - store = new WorldFileStore(null, new StorageConnector(url), true); + final URL url = BSQConsistencyTest.class.getResource("BSQ.raw"); + assertNotNull("Test file not found.", url); + store = new RawRasterStore(null, new StorageConnector(url)); } /** @@ -65,7 +61,7 @@ public final strictfp class SelfConsistencyTest extends CoverageReadConsistency */ @AfterClass public static void closeFile() throws DataStoreException { - final WorldFileStore s = store; + final RawRasterStore s = store; if (s != null) { store = null; // Clear first in case of failure. s.close(); @@ -77,7 +73,7 @@ public final strictfp class SelfConsistencyTest extends CoverageReadConsistency * * @throws DataStoreException if an error occurred while fetching the first image. */ - public SelfConsistencyTest() throws DataStoreException { - super(store.components().iterator().next()); + public BSQConsistencyTest() throws DataStoreException { + super(store); } } diff --git a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/image/SelfConsistencyTest.java b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/image/SelfConsistencyTest.java index a2858cfadc..62778d2c60 100644 --- a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/image/SelfConsistencyTest.java +++ b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/image/SelfConsistencyTest.java @@ -24,7 +24,7 @@ import org.apache.sis.test.storage.CoverageReadConsistency; import org.junit.AfterClass; import org.junit.BeforeClass; -import static org.junit.Assume.assumeNotNull; +import static org.junit.Assert.assertNotNull; /** @@ -54,7 +54,7 @@ public final strictfp class SelfConsistencyTest extends CoverageReadConsistency @BeforeClass public static void openFile() throws IOException, DataStoreException { final URL url = WorldFileStoreTest.class.getResource("gradient.png"); - assumeNotNull(url); + assertNotNull("Test file not found.", url); store = new WorldFileStore(null, new StorageConnector(url), true); } diff --git a/storage/sis-storage/src/test/java/org/apache/sis/test/suite/StorageTestSuite.java b/storage/sis-storage/src/test/java/org/apache/sis/test/suite/StorageTestSuite.java index 2a5e64104e..2392c0f1de 100644 --- a/storage/sis-storage/src/test/java/org/apache/sis/test/suite/StorageTestSuite.java +++ b/storage/sis-storage/src/test/java/org/apache/sis/test/suite/StorageTestSuite.java @@ -61,6 +61,9 @@ import org.junit.BeforeClass; org.apache.sis.internal.storage.image.SelfConsistencyTest.class, org.apache.sis.internal.storage.esri.AsciiGridStoreTest.class, org.apache.sis.internal.storage.esri.WritableStoreTest.class, + org.apache.sis.internal.storage.esri.BSQConsistencyTest.class, + org.apache.sis.internal.storage.esri.BIPConsistencyTest.class, + org.apache.sis.internal.storage.esri.BILConsistencyTest.class, org.apache.sis.internal.storage.folder.StoreTest.class, org.apache.sis.internal.storage.JoinFeatureSetTest.class, org.apache.sis.internal.storage.ConcatenatedFeatureSetTest.class, diff --git a/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/esri/BIL.hdr b/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/esri/BIL.hdr new file mode 100644 index 0000000000..eda7882b97 --- /dev/null +++ b/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/esri/BIL.hdr @@ -0,0 +1,9 @@ +Header file for the `BIL.raw` test raster. + +NROWS 9 +NCOLS 9 +NBANDS 3 +LAYOUT BIL Band Interleaved by Line + +Note: ULXMAP, ULYMAP, XDIM and YDIM entries +are omitted for testing their default value. diff --git a/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/esri/BIL.raw b/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/esri/BIL.raw new file mode 100644 index 0000000000..f49e651f85 Binary files /dev/null and b/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/esri/BIL.raw differ diff --git a/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/esri/BIP.hdr b/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/esri/BIP.hdr new file mode 100644 index 0000000000..197bf27453 --- /dev/null +++ b/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/esri/BIP.hdr @@ -0,0 +1,12 @@ +Header file for the `BIP.raw` test raster. + +NROWS 9 +NCOLS 9 +NBANDS 3 +LAYOUT BIP Band Interleaved by Pixel + +ULXMAP -10 Dummy values +ULYMAP -15 + +Note: XDIM and YDIM entries are omitted for +testing their default value, which is 1. diff --git a/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/esri/BIP.raw b/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/esri/BIP.raw new file mode 100644 index 0000000000..38c2dbc967 Binary files /dev/null and b/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/esri/BIP.raw differ diff --git a/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/esri/BSQ.hdr b/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/esri/BSQ.hdr new file mode 100644 index 0000000000..02078150ef --- /dev/null +++ b/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/esri/BSQ.hdr @@ -0,0 +1,13 @@ +Header file for the `BSQ.raw` test raster. +Lines that do not begin with a keyword shall be ignored as comments. + +NROWS 9 Text after value shall be ignored as well +NCOLS 9 +NBANDS 3 +NBITS 8 Default value, omission tested in other tests +LAYOUT BSQ Band Sequential + +ULXMAP -10 Dummy values +ULYMAP -15 +XDIM 0.2 +YDIM 0.1 diff --git a/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/esri/BSQ.raw b/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/esri/BSQ.raw new file mode 100644 index 0000000000..9baaa23dae Binary files /dev/null and b/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/esri/BSQ.raw differ diff --git a/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/esri/grid.prj b/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/esri/grid.prj index 61f8cc4918..bd389eb6a0 100644 --- a/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/esri/grid.prj +++ b/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/esri/grid.prj @@ -3,3 +3,7 @@ PROJCS["WGS 84 / World Mercator", DATUM["World Geodetic System 1984", SPHEROID["WGS 84", 6378137.0, 298.257223563]], PRIMEM["Greenwich", 0.0], UNIT["degree", 0.017453292519943295]], PROJECTION["Mercator_1SP"], UNIT["km", 1000.0]] + +Lines after the CRS definitions shall be ignored. +PRJ files usually contains WKT-1 on a single line, +but this test uses multi-line for readability.