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 2022/08/18 16:46:10 UTC
[sis] branch geoapi-4.0 updated (696dfafa87 -> 99a1d79f15)
This is an automated email from the ASF dual-hosted git repository.
desruisseaux pushed a change to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git
from 696dfafa87 Allow `ChannelImageInputStream` to wrap an array of `byte[]` containing all data.
new 4da5559c3a Fix an EOF exception when reading a GeoTIFF image using LZW compression but without EOI (End Of Information) code.
new 6680d98683 Add an annotation for methods which may return `java.util.Optional` in a future SIS version. This is for documentation purpose only and a reminder for future development. We do not annotate all possible methods yet; annotations will be added progressively.
new 99a1d79f15 Add a `MatrixSIS.getInteger(j,i)` method returning a `long`. This method can be more accurate than `double` type when using `GeneralMatrix`.
The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../apache/sis/metadata/iso/extent/Extents.java | 9 +++++-
.../main/java/org/apache/sis/util/iso/Types.java | 5 ++++
.../main/java/org/apache/sis/referencing/CRS.java | 10 +++++++
.../operation/matrix/GeneralMatrix.java | 28 ++++++++++++++++++-
.../referencing/operation/matrix/MatrixSIS.java | 17 +++++++++++-
.../referencing/operation/matrix/package-info.java | 2 +-
.../operation/transform/MathTransforms.java | 2 ++
.../operation/matrix/GeneralMatrixTest.java | 19 ++++++++++++-
.../org/apache/sis/internal/util/DoubleDouble.java | 14 +++++++---
.../main/java/org/apache/sis/measure/Units.java | 3 ++
.../org/apache/sis/util/OptionalCandidate.java} | 20 +++++++-------
.../sis/internal/storage/inflater/CCITTRLE.java | 8 ++++--
.../storage/inflater/CompressionChannel.java | 19 +++++++++----
.../sis/internal/storage/inflater/Inflater.java | 26 +++++++++---------
.../apache/sis/internal/storage/inflater/LZW.java | 32 ++++++++++++++++++----
.../sis/internal/storage/inflater/PackBits.java | 10 ++++---
.../apache/sis/internal/storage/inflater/ZIP.java | 8 ++++--
.../sis/storage/geotiff/CompressedSubset.java | 2 +-
.../org/apache/sis/storage/geotiff/DataCube.java | 16 +++++------
.../org/apache/sis/storage/geotiff/DataSubset.java | 4 +--
.../internal/storage/inflater/CCITTRLETest.java | 2 +-
21 files changed, 191 insertions(+), 65 deletions(-)
copy core/sis-utility/src/{test/java/org/apache/sis/test/TestStep.java => main/java/org/apache/sis/util/OptionalCandidate.java} (62%)
[sis] 01/03: Fix an EOF exception when reading a GeoTIFF image using LZW compression but without EOI (End Of Information) code.
Posted by de...@apache.org.
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 4da5559c3af058d88b04c8e84f07380a184f48f2
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Thu Aug 18 18:39:16 2022 +0200
Fix an EOF exception when reading a GeoTIFF image using LZW compression but without EOI (End Of Information) code.
---
.../sis/internal/storage/inflater/CCITTRLE.java | 8 ++++--
.../storage/inflater/CompressionChannel.java | 19 +++++++++----
.../sis/internal/storage/inflater/Inflater.java | 26 +++++++++---------
.../apache/sis/internal/storage/inflater/LZW.java | 32 ++++++++++++++++++----
.../sis/internal/storage/inflater/PackBits.java | 10 ++++---
.../apache/sis/internal/storage/inflater/ZIP.java | 8 ++++--
.../sis/storage/geotiff/CompressedSubset.java | 2 +-
.../org/apache/sis/storage/geotiff/DataCube.java | 16 +++++------
.../org/apache/sis/storage/geotiff/DataSubset.java | 4 +--
.../internal/storage/inflater/CCITTRLETest.java | 2 +-
10 files changed, 81 insertions(+), 46 deletions(-)
diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/CCITTRLE.java b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/CCITTRLE.java
index cf44863623..b89e2c2dd4 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/CCITTRLE.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/CCITTRLE.java
@@ -18,6 +18,7 @@ package org.apache.sis.internal.storage.inflater;
import java.io.IOException;
import java.nio.ByteBuffer;
+import org.apache.sis.storage.event.StoreListeners;
import org.apache.sis.internal.storage.io.ChannelDataInput;
@@ -41,7 +42,7 @@ import org.apache.sis.internal.storage.io.ChannelDataInput;
* which is not equivalent to "0011" neither. Consequently we can not parse directly the bits as integer values.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 1.1
* @module
*/
@@ -120,10 +121,11 @@ final class CCITTRLE extends CompressionChannel {
* before a reading process can start.
*
* @param input the source of data to decompress.
+ * @param listeners object where to report warnings.
* @param sourceWidth number of pixels in a row of the source image.
*/
- CCITTRLE(final ChannelDataInput input, final int sourceWidth) {
- super(input);
+ CCITTRLE(final ChannelDataInput input, final StoreListeners listeners, final int sourceWidth) {
+ super(input, listeners);
bitsPerRow = sourceWidth;
}
diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/CompressionChannel.java b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/CompressionChannel.java
index ab41f72001..4fe15fc575 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/CompressionChannel.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/CompressionChannel.java
@@ -23,6 +23,7 @@ import org.apache.sis.math.MathFunctions;
import org.apache.sis.internal.util.Numerics;
import org.apache.sis.internal.geotiff.Resources;
import org.apache.sis.internal.storage.io.ChannelDataInput;
+import org.apache.sis.storage.event.StoreListeners;
/**
@@ -53,15 +54,22 @@ abstract class CompressionChannel extends PixelChannel {
*/
private long endPosition;
+ /**
+ * Objects where to report warnings.
+ */
+ protected final StoreListeners listeners;
+
/**
* Creates a new channel which will decompress data from the given input.
* The {@link #setInputRegion(long, long)} method must be invoked after construction
* before a reading process can start.
*
- * @param input the source of data to decompress.
+ * @param input the source of data to decompress.
+ * @param listeners object where to report warnings.
*/
- protected CompressionChannel(final ChannelDataInput input) {
- this.input = input;
+ protected CompressionChannel(final ChannelDataInput input, final StoreListeners listeners) {
+ this.input = input;
+ this.listeners = listeners;
}
/**
@@ -140,10 +148,9 @@ abstract class CompressionChannel extends PixelChannel {
}
/**
- * Returns the resources for error messages. Current implementation does not know the locale.
- * But if this information become known in a future version, this is the code to update.
+ * Returns the resources for error messages.
*/
final Resources resources() {
- return Resources.forLocale(null);
+ return Resources.forLocale(listeners.getLocale());
}
}
diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/Inflater.java b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/Inflater.java
index cb6137895b..14a101a32b 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/Inflater.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/Inflater.java
@@ -28,8 +28,8 @@ import org.apache.sis.internal.geotiff.Predictor;
import org.apache.sis.internal.geotiff.Resources;
import org.apache.sis.internal.storage.io.ChannelDataInput;
import org.apache.sis.storage.UnsupportedEncodingException;
+import org.apache.sis.storage.event.StoreListeners;
import org.apache.sis.util.ArgumentChecks;
-import org.apache.sis.util.Localized;
import static org.apache.sis.internal.util.Numerics.ceilDiv;
@@ -46,7 +46,7 @@ import static org.apache.sis.internal.util.Numerics.ceilDiv;
* and band subset.</p>
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 1.1
* @module
*/
@@ -167,7 +167,7 @@ public abstract class Inflater implements Closeable {
* (e.g. 1 bit) if {@code pixelsPerElement} is greater than 1. If that case, the {@link #elementsPerChunk}
* and {@link #skipAfterChunks} values will be divided by {@code pixelsPerElement}.
*
- * @param caller object calling this method (used in case an error message most be produced).
+ * @param listeners object where to report warnings.
* @param input the source of data to decompress.
* @param compression the compression method.
* @param predictor the mathematical operator to apply after decompression.
@@ -188,7 +188,7 @@ public abstract class Inflater implements Closeable {
* in a way that make them usable with other tiled formats than TIFF.
*/
@SuppressWarnings("fallthrough")
- public static Inflater create(final Localized caller,
+ public static Inflater create(final StoreListeners listeners,
final ChannelDataInput input,
final Compression compression,
final Predictor predictor,
@@ -204,18 +204,18 @@ public abstract class Inflater implements Closeable {
ArgumentChecks.ensureNonNull("input", input);
final CompressionChannel inflater;
switch (compression) {
- case LZW: inflater = new LZW (input); break;
- case DEFLATE: inflater = new ZIP (input); break;
- case PACKBITS: inflater = new PackBits(input); break;
- case CCITTRLE: inflater = new CCITTRLE(input, sourceWidth); break;
+ case LZW: inflater = new LZW (input, listeners); break;
+ case DEFLATE: inflater = new ZIP (input, listeners); break;
+ case PACKBITS: inflater = new PackBits(input, listeners); break;
+ case CCITTRLE: inflater = new CCITTRLE(input, listeners, sourceWidth); break;
case NONE: {
if (predictor == Predictor.NONE) {
return CopyFromBytes.create(input, dataType, chunksPerRow, samplesPerChunk, skipAfterChunks, pixelsPerElement);
}
- throw unsupportedEncoding(caller, Resources.Keys.UnsupportedPredictor_1, predictor);
+ throw unsupportedEncoding(listeners, Resources.Keys.UnsupportedPredictor_1, predictor);
}
default: {
- throw unsupportedEncoding(caller, Resources.Keys.UnsupportedCompressionMethod_1, compression);
+ throw unsupportedEncoding(listeners, Resources.Keys.UnsupportedCompressionMethod_1, compression);
}
}
final PixelChannel channel;
@@ -236,7 +236,7 @@ public abstract class Inflater implements Closeable {
// Fallthrough.
}
default: {
- throw unsupportedEncoding(caller, Resources.Keys.UnsupportedPredictor_1, predictor);
+ throw unsupportedEncoding(listeners, Resources.Keys.UnsupportedPredictor_1, predictor);
}
}
final int scanlineStride = Math.multiplyExact(sourceWidth, sourcePixelStride * dataType.bytes());
@@ -247,8 +247,8 @@ public abstract class Inflater implements Closeable {
/**
* Returns the exception to throw for an unsupported compression or predictor.
*/
- private static UnsupportedEncodingException unsupportedEncoding(final Localized caller, final short key, final Enum<?> value) {
- return new UnsupportedEncodingException(Resources.forLocale(caller.getLocale()).getString(key, value));
+ private static UnsupportedEncodingException unsupportedEncoding(StoreListeners listeners, short key, Enum<?> value) {
+ return new UnsupportedEncodingException(Resources.forLocale(listeners.getLocale()).getString(key, value));
}
/**
diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/LZW.java b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/LZW.java
index 30de03fb9c..89d35d20dd 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/LZW.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/LZW.java
@@ -18,9 +18,11 @@ package org.apache.sis.internal.storage.inflater;
import java.util.Arrays;
import java.io.IOException;
+import java.io.EOFException;
import java.nio.ByteBuffer;
import org.apache.sis.internal.geotiff.Resources;
import org.apache.sis.internal.storage.io.ChannelDataInput;
+import org.apache.sis.storage.event.StoreListeners;
/**
@@ -234,10 +236,11 @@ final class LZW extends CompressionChannel {
* The {@link #setInputRegion(long, long)} method must be invoked after construction
* before a reading process can start.
*
- * @param input the source of data to decompress.
+ * @param input the source of data to decompress.
+ * @param listeners object where to report warnings.
*/
- public LZW(final ChannelDataInput input) {
- super(input);
+ public LZW(final ChannelDataInput input, final StoreListeners listeners) {
+ super(input, listeners);
indexOfFreeEntry = FIRST_ADAPTATIVE_CODE;
entriesForCodes = new int[(1 << MAX_CODE_SIZE) - OFFSET_TO_MAXIMUM];
stringsFromCode = new byte[3 << (MAX_CODE_SIZE + STRING_ALIGNMENT)]; // Dynamically expanded if needed.
@@ -275,6 +278,25 @@ final class LZW extends CompressionChannel {
codeSize = MIN_CODE_SIZE;
}
+ /**
+ * Reads {@link #codeSize} bits from the stream.
+ *
+ * @return the value of the next bits from the stream.
+ * @throws IOException if an error occurred while reading.
+ */
+ public final int readNextCode() throws IOException {
+ try {
+ return (int) input.readBits(codeSize);
+ } catch (EOFException e) {
+ if (finished()) {
+ listeners.warning(null, e);
+ return EOI_CODE;
+ } else {
+ throw e;
+ }
+ }
+ }
+
/**
* Decompresses some bytes from the {@linkplain #input input} into the given destination buffer.
*
@@ -310,7 +332,7 @@ final class LZW extends CompressionChannel {
int stringLength = length(entryForCode);
int maximumIndex = (1 << codeSize) - OFFSET_TO_MAXIMUM;
int code;
- while ((code = (int) input.readBits(codeSize)) != EOI_CODE) { // GetNextCode()
+ while ((code = readNextCode()) != EOI_CODE) { // GetNextCode()
if (code == CLEAR_CODE) {
clearTable(); // InitializeTable()
maximumIndex = (1 << MIN_CODE_SIZE) - OFFSET_TO_MAXIMUM;
@@ -319,7 +341,7 @@ final class LZW extends CompressionChannel {
* The first valid code after `CLEAR_CODE` shall be a byte. If we reached the end
* of strip, the EOI code should be mandatory but appears to be sometime missing.
*/
- do code = finished() ? EOI_CODE : (int) input.readBits(MIN_CODE_SIZE); // GetNextCode()
+ do code = readNextCode(); // GetNextCode()
while (code == CLEAR_CODE);
if ((code & ~0xFF) != 0) {
if (code == EOI_CODE) break;
diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/PackBits.java b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/PackBits.java
index 650633f930..c4b6fbc431 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/PackBits.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/PackBits.java
@@ -18,6 +18,7 @@ package org.apache.sis.internal.storage.inflater;
import java.io.IOException;
import java.nio.ByteBuffer;
+import org.apache.sis.storage.event.StoreListeners;
import org.apache.sis.internal.storage.io.ChannelDataInput;
@@ -26,7 +27,7 @@ import org.apache.sis.internal.storage.io.ChannelDataInput;
* This compression is described in section 9 of TIFF 6 specification.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 1.1
* @module
*/
@@ -53,10 +54,11 @@ final class PackBits extends CompressionChannel {
* The {@link #setInputRegion(long, long)} method must be invoked after construction
* before a reading process can start.
*
- * @param input the source of data to decompress.
+ * @param input the source of data to decompress.
+ * @param listeners object where to report warnings.
*/
- public PackBits(final ChannelDataInput input) {
- super(input);
+ public PackBits(final ChannelDataInput input, final StoreListeners listeners) {
+ super(input, listeners);
}
/**
diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/ZIP.java b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/ZIP.java
index a4f5c1fb35..4e4ccc4ec5 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/ZIP.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/ZIP.java
@@ -21,6 +21,7 @@ import java.nio.ByteBuffer;
import java.nio.BufferOverflowException;
import java.util.zip.Inflater;
import java.util.zip.DataFormatException;
+import org.apache.sis.storage.event.StoreListeners;
import org.apache.sis.internal.storage.io.ChannelDataInput;
@@ -29,7 +30,7 @@ import org.apache.sis.internal.storage.io.ChannelDataInput;
*
* @author Rémi Marechal (Geomatys)
* @author Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 1.1
* @module
*/
@@ -46,12 +47,13 @@ final class ZIP extends CompressionChannel {
* before a reading process can start.
*
* @param input the source of data to decompress.
+ * @param listeners object where to report warnings.
* @param start stream position where to start reading.
* @param byteCount number of bytes to read from the input.
* @throws IOException if the stream can not be seek to the given start position.
*/
- public ZIP(final ChannelDataInput input) {
- super(input);
+ public ZIP(final ChannelDataInput input, final StoreListeners listeners) {
+ super(input, listeners);
inflater = new Inflater();
}
diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CompressedSubset.java b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CompressedSubset.java
index 3151824b39..2566aac94e 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CompressedSubset.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CompressedSubset.java
@@ -216,7 +216,7 @@ final class CompressedSubset extends DataSubset {
final int pixelsPerElement = getPixelsPerElement(); // Always ≥ 1 and usually = 1.
assert (head % pixelsPerElement) == 0 : head;
if (inflater == null) {
- inflater = Inflater.create(this, input(), source.getCompression(), source.getPredictor(),
+ inflater = Inflater.create(source.listeners(), input(), source.getCompression(), source.getPredictor(),
sourcePixelStride, getTileSize(X_DIMENSION), chunksPerRow, samplesPerChunk, skipAfterChunks,
pixelsPerElement, dataType);
}
diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/DataCube.java b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/DataCube.java
index 664ca72231..99b7a22a70 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/DataCube.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/DataCube.java
@@ -16,7 +16,6 @@
*/
package org.apache.sis.storage.geotiff;
-import java.util.Locale;
import java.util.Optional;
import java.nio.file.Path;
import java.awt.image.DataBuffer;
@@ -26,6 +25,7 @@ import org.opengis.util.GenericName;
import org.apache.sis.storage.DataStore;
import org.apache.sis.storage.DataStoreException;
import org.apache.sis.storage.DataStoreContentException;
+import org.apache.sis.storage.event.StoreListeners;
import org.apache.sis.coverage.grid.GridCoverage;
import org.apache.sis.coverage.grid.GridGeometry;
import org.apache.sis.internal.geotiff.Resources;
@@ -43,8 +43,11 @@ import org.apache.sis.math.Vector;
* But it can also be a stack of images organized in a <var>n</var>-dimensional data cube,
* or a pyramid of images with their overviews used when low resolution images is requested.
*
+ * <p><b>Warning:</b> do not implement {@link org.apache.sis.util.Localized},
+ * as it may cause an infinite loop in {@code listeners.getLocale()} call.</p>
+ *
* @author Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 1.1
* @module
*/
@@ -82,13 +85,10 @@ abstract class DataCube extends TiledGridResource implements ResourceOnFileSyste
}
/**
- * Returns the locale for warnings and error messages.
- *
- * <p><b>Warning:</b> do not implement {@link org.apache.sis.util.Localized},
- * as it may cause an infinite loop in {@code listeners.getLocale()} call.</p>
+ * Access to the protected {@link #listeners} field.
*/
- final Locale getLocale() {
- return listeners.getLocale();
+ final StoreListeners listeners() {
+ return listeners;
}
/**
diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/DataSubset.java b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/DataSubset.java
index e003987e00..03af798ecd 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/DataSubset.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/DataSubset.java
@@ -66,7 +66,7 @@ import static java.lang.Math.toIntExact;
* the same tile indices than {@link DataCube} in order to avoid integer overflow.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 1.1
* @module
*/
@@ -181,7 +181,7 @@ class DataSubset extends TiledGridCoverage implements Localized {
*/
@Override
public final Locale getLocale() {
- return source.getLocale();
+ return source.listeners().getLocale();
}
/**
diff --git a/storage/sis-geotiff/src/test/java/org/apache/sis/internal/storage/inflater/CCITTRLETest.java b/storage/sis-geotiff/src/test/java/org/apache/sis/internal/storage/inflater/CCITTRLETest.java
index ad0903138d..18339f1546 100644
--- a/storage/sis-geotiff/src/test/java/org/apache/sis/internal/storage/inflater/CCITTRLETest.java
+++ b/storage/sis-geotiff/src/test/java/org/apache/sis/internal/storage/inflater/CCITTRLETest.java
@@ -500,7 +500,7 @@ public final strictfp class CCITTRLETest extends TestCase {
private void verifyReading() throws IOException {
final CCITTRLE decoder = new CCITTRLE(
new ChannelDataInput("sequenceOfAllWords", null, sequenceOfAllWords, true),
- sequenceOfAllWords.limit());
+ null, sequenceOfAllWords.limit());
decoder.setInputRegion(0, sequenceOfAllWords.limit());
int runLength = 0;
do {
[sis] 03/03: Add a `MatrixSIS.getInteger(j,i)` method returning a `long`. This method can be more accurate than `double` type when using `GeneralMatrix`.
Posted by de...@apache.org.
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 99a1d79f15ba5e8df85264ded7282a3040a4a650
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Thu Aug 18 17:06:46 2022 +0200
Add a `MatrixSIS.getInteger(j,i)` method returning a `long`.
This method can be more accurate than `double` type when using `GeneralMatrix`.
---
.../operation/matrix/GeneralMatrix.java | 28 +++++++++++++++++++++-
.../referencing/operation/matrix/MatrixSIS.java | 17 ++++++++++++-
.../referencing/operation/matrix/package-info.java | 2 +-
.../operation/matrix/GeneralMatrixTest.java | 19 ++++++++++++++-
.../org/apache/sis/internal/util/DoubleDouble.java | 14 +++++++----
5 files changed, 72 insertions(+), 8 deletions(-)
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/GeneralMatrix.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/GeneralMatrix.java
index ae2ae27bb4..01ed4330df 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/GeneralMatrix.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/GeneralMatrix.java
@@ -36,7 +36,7 @@ import org.apache.sis.internal.referencing.ExtendedPrecisionMatrix;
* the {@link DoubleDouble#error}.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.8
+ * @version 1.3
*
* @see Matrices#createDiagonal(int, int)
*
@@ -262,6 +262,32 @@ class GeneralMatrix extends MatrixSIS implements ExtendedPrecisionMatrix {
}
}
+ /**
+ * Retrieves the value at the specified row and column of this matrix, rounded to nearest integer.
+ *
+ * @param row the row index, from 0 inclusive to {@link #getNumRow()} exclusive.
+ * @param column the column index, from 0 inclusive to {@link #getNumCol()} exclusive.
+ * @return the current value at the given row and column, rounded to nearest integer.
+ *
+ * @see DoubleDouble#longValue()
+ *
+ * @since 1.3
+ */
+ @Override
+ public long getInteger(int row, int column) {
+ if (row >= 0 && row < numRow && column >= 0 && column < numCol) {
+ int i = row * numCol + column;
+ long value = Math.round(elements[i]);
+ i += numRow * numCol;
+ if (i < elements.length) {
+ value += (long) elements[i]; // Really want rounding toward zero.
+ }
+ return value;
+ } else {
+ throw indexOutOfBounds(row, column);
+ }
+ }
+
/**
* Retrieves the value at the specified row and column of this matrix, wrapped in a {@code Number}
* or a {@link DoubleDouble} depending on available precision.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java
index 316ac2f5e9..cee43acaa2 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java
@@ -55,7 +55,7 @@ import org.apache.sis.util.resources.Errors;
* </ul>
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 1.1
+ * @version 1.3
*
* @see Matrices
*
@@ -163,6 +163,21 @@ public abstract class MatrixSIS implements Matrix, LenientComparable, Cloneable,
setElement(row, column, dd.doubleValue());
}
+ /**
+ * Retrieves the value at the specified row and column of this matrix, rounded to nearest integer.
+ * This method may be more accurate than {@link #getElement(int, int)} in some implementations
+ * when the value is expected to be an integer (for example in conversions of pixel coordinates).
+ *
+ * @param row the row index, from 0 inclusive to {@link #getNumRow()} exclusive.
+ * @param column the column index, from 0 inclusive to {@link #getNumCol()} exclusive.
+ * @return the current value at the given row and column, rounded to nearest integer.
+ *
+ * @since 1.3
+ */
+ public long getInteger(int row, int column) {
+ return Math.round(getElement(row, column));
+ }
+
/**
* Retrieves the value at the specified row and column of this matrix, wrapped in a {@code Number}.
* The {@code Number} type depends on the matrix accuracy.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/package-info.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/package-info.java
index 23ced6d69d..1cbd737608 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/package-info.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/package-info.java
@@ -69,7 +69,7 @@
* Like SIS, Vecmath is optimized for small matrices of interest for 2D and 3D graphics.</p>
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 1.1
+ * @version 1.3
* @since 0.4
* @module
*/
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java
index 8d3d883649..b65a2ed69f 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java
@@ -17,6 +17,7 @@
package org.apache.sis.referencing.operation.matrix;
import java.util.Random;
+import org.apache.sis.internal.util.DoubleDouble;
import org.junit.Test;
import static org.junit.Assert.*;
@@ -27,7 +28,7 @@ import static org.junit.Assert.*;
* This class inherits all tests defined in {@link MatrixTestCase}.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.3
* @since 0.4
* @module
*/
@@ -59,6 +60,22 @@ public final strictfp class GeneralMatrixTest extends MatrixTestCase {
assertEquals(GeneralMatrix.class, matrix.getClass());
}
+ /**
+ * Tests {@link GeneralMatrix#getNumber(int, int)} and {@link GeneralMatrix#getInteger(int, int)}
+ * using a value which can not be stored accurately in a {@code double} type.
+ */
+ @Test
+ public void testExtendedPrecision() {
+ final long value = 1000000000000010000L;
+ assertNotEquals(value, Math.round((double) value));
+ final GeneralMatrix m = new GeneralMatrix(1, 1, false, 2);
+ final DoubleDouble ddval = new DoubleDouble((Long) value);
+ m.setNumber(0, 0, ddval);
+ assertEquals(Long.toString(value), ddval.toString());
+ assertEquals(ddval, m.getNumber (0, 0));
+ assertEquals(value, m.getInteger(0, 0));
+ }
+
/**
* Tests {@link GeneralMatrix#getExtendedElements(Matrix, int, int, boolean)}.
* This test verifies that {@code getExtendedElements} can infer default error
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/util/DoubleDouble.java b/core/sis-utility/src/main/java/org/apache/sis/internal/util/DoubleDouble.java
index 4b483d600a..b8a5ad407b 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/util/DoubleDouble.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/util/DoubleDouble.java
@@ -56,7 +56,7 @@ import org.apache.sis.math.DecimalFunctions;
* </ul>
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.3
*
* @see <a href="https://en.wikipedia.org/wiki/Double-double_%28arithmetic%29#Double-double_arithmetic">Wikipedia: Double-double arithmetic</a>
*
@@ -220,6 +220,8 @@ public final class DoubleDouble extends Number {
value = otherValue.doubleValue();
if (otherValue instanceof DoubleDouble) {
error = ((DoubleDouble) otherValue).error;
+ } else if (otherValue instanceof Long) {
+ error = otherValue.longValue() - (long) value;
} else if (otherValue instanceof BigDecimal) {
// Really need new BigDecimal(value) below, not BigDecimal.valueOf(value).
error = ((BigDecimal) otherValue).subtract(new BigDecimal(value), MathContext.DECIMAL64).doubleValue();
@@ -231,8 +233,11 @@ public final class DoubleDouble extends Number {
/**
* Returns {@code true} if the given value is one of the special cases recognized by the
- * {@link DoubleDouble(Number)} constructor. Those special cases should rarely occur, so
- * we do not complicate the code with optimized code paths.
+ * {@link #DoubleDouble(Number)} constructor. Those special cases should rarely occur,
+ * so we do not complicate the code with optimized code paths.
+ *
+ * <p>This method does not test if the given value is already an instance of {@code DoubleDouble}.
+ * That verification should be done by the caller.</p>
*
* @param value the value to test.
* @return {@code true} if it is worth to convert the given value to a {@code DoubleDouble}.
@@ -240,7 +245,8 @@ public final class DoubleDouble extends Number {
* @since 0.8
*/
public static boolean shouldConvert(final Number value) {
- return (value instanceof Fraction) || (value instanceof BigInteger) || (value instanceof BigDecimal);
+ return (value instanceof Fraction) || (value instanceof Long) ||
+ (value instanceof BigInteger) || (value instanceof BigDecimal);
}
/**
[sis] 02/03: Add an annotation for methods which may return `java.util.Optional` in a future SIS version. This is for documentation purpose only and a reminder for future development. We do not annotate all possible methods yet; annotations will be added progressively.
Posted by de...@apache.org.
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 6680d98683cdb3bcac1967601d22af095c2ec1b8
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Thu Aug 18 16:28:41 2022 +0200
Add an annotation for methods which may return `java.util.Optional` in a future SIS version.
This is for documentation purpose only and a reminder for future development.
We do not annotate all possible methods yet; annotations will be added progressively.
---
.../apache/sis/metadata/iso/extent/Extents.java | 9 ++++-
.../main/java/org/apache/sis/util/iso/Types.java | 5 +++
.../main/java/org/apache/sis/referencing/CRS.java | 10 +++++
.../operation/transform/MathTransforms.java | 2 +
.../main/java/org/apache/sis/measure/Units.java | 3 ++
.../org/apache/sis/util/OptionalCandidate.java | 44 ++++++++++++++++++++++
6 files changed, 72 insertions(+), 1 deletion(-)
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/Extents.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/Extents.java
index 4ab70007e1..ae145b88cc 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/Extents.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/Extents.java
@@ -51,6 +51,7 @@ import org.apache.sis.measure.Longitude;
import org.apache.sis.measure.MeasurementRange;
import org.apache.sis.measure.Range;
import org.apache.sis.util.iso.Types;
+import org.apache.sis.util.OptionalCandidate;
import org.apache.sis.util.resources.Vocabulary;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.ArgumentChecks;
@@ -130,10 +131,11 @@ public final class Extents extends Static {
* using {@link #getGeographicBoundingBox(Extent)}.</div>
*
* @param metadata the metadata from which to get a global bounding box, or {@code null} if none.
- * @return a global bounding box for all extents found in the given metadata.
+ * @return a global bounding box for all extents found in the given metadata, or {@code null} if none.
*
* @since 1.1
*/
+ @OptionalCandidate
public static GeographicBoundingBox getGeographicBoundingBox(final Metadata metadata) {
if (metadata == null) {
return null;
@@ -179,6 +181,7 @@ public final class Extents extends Static {
*
* @see org.apache.sis.referencing.CRS#getDomainOfValidity(CoordinateReferenceSystem)
*/
+ @OptionalCandidate
public static GeographicBoundingBox getGeographicBoundingBox(final Extent extent) {
if (extent == null) {
return null;
@@ -328,6 +331,7 @@ public final class Extents extends Static {
*
* @since 0.4
*/
+ @OptionalCandidate
public static MeasurementRange<Double> getVerticalRange(final Extent extent) {
MeasurementRange<Double> range = null;
VerticalDatumType selectedType = null;
@@ -402,6 +406,7 @@ public final class Extents extends Static {
*
* @since 0.4
*/
+ @OptionalCandidate
public static Range<Date> getTimeRange(final Extent extent) {
Date min = null;
Date max = null;
@@ -451,6 +456,7 @@ public final class Extents extends Static {
*
* @since 0.4
*/
+ @OptionalCandidate
public static Date getDate(final Extent extent, final double location) {
ArgumentChecks.ensureFinite("location", location);
Date min = null;
@@ -487,6 +493,7 @@ public final class Extents extends Static {
*
* @since 1.1
*/
+ @OptionalCandidate
public static String getDescription(final Extent extent, final Locale locale) {
return (extent != null) ? Types.toString(extent.getDescription(), locale) : null;
}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/util/iso/Types.java b/core/sis-metadata/src/main/java/org/apache/sis/util/iso/Types.java
index 7fa0879c9f..b88c3f3adb 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/util/iso/Types.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/util/iso/Types.java
@@ -39,6 +39,7 @@ import org.apache.sis.util.Static;
import org.apache.sis.util.Locales;
import org.apache.sis.util.CharSequences;
import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.OptionalCandidate;
import org.apache.sis.util.logging.Logging;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.resources.Messages;
@@ -149,6 +150,7 @@ public final class Types extends Static {
*
* @see #forStandardName(String)
*/
+ @OptionalCandidate
public static String getStandardName(final Class<?> type) {
if (type != null) {
final UML uml = type.getAnnotation(UML.class);
@@ -294,6 +296,7 @@ public final class Types extends Static {
* @see #getCodeTitle(ControlledVocabulary)
* @see #getDescription(Class)
*/
+ @OptionalCandidate
public static InternationalString getDescription(final ControlledVocabulary code) {
if (code != null) {
final String resources = getResources(code.getClass().getName());
@@ -313,6 +316,7 @@ public final class Types extends Static {
*
* @see #getDescription(ControlledVocabulary)
*/
+ @OptionalCandidate
public static InternationalString getDescription(final Class<?> type) {
final String name = getStandardName(type);
if (name != null) {
@@ -690,6 +694,7 @@ public final class Types extends Static {
*
* @since 0.4
*/
+ @OptionalCandidate
public static InternationalString toInternationalString(Map<String,?> properties, final String prefix)
throws IllegalArgumentException
{
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
index 18e19dad8a..265f31a557 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
@@ -86,6 +86,7 @@ import org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox;
import org.apache.sis.metadata.iso.extent.Extents;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.logging.Logging;
+import org.apache.sis.util.OptionalCandidate;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.Utilities;
import org.apache.sis.util.Static;
@@ -461,6 +462,7 @@ public final class CRS extends Static {
*
* @since 0.8
*/
+ @OptionalCandidate
public static CoordinateReferenceSystem suggestCommonTarget(GeographicBoundingBox regionOfInterest,
CoordinateReferenceSystem... sourceCRS)
{
@@ -728,6 +730,7 @@ public final class CRS extends Static {
*
* @since 0.7
*/
+ @OptionalCandidate
public static double getLinearAccuracy(final CoordinateOperation operation) {
if (operation == null) {
return Double.NaN;
@@ -758,6 +761,7 @@ public final class CRS extends Static {
*
* @since 0.7
*/
+ @OptionalCandidate
public static GeographicBoundingBox getGeographicBoundingBox(final CoordinateOperation operation) {
if (operation == null) {
return null;
@@ -785,6 +789,7 @@ public final class CRS extends Static {
*
* @category information
*/
+ @OptionalCandidate
public static GeographicBoundingBox getGeographicBoundingBox(final CoordinateReferenceSystem crs) {
return (crs != null) ? Extents.getGeographicBoundingBox(crs.getDomainOfValidity()) : null;
}
@@ -812,6 +817,7 @@ public final class CRS extends Static {
* @category information
* @since 0.8
*/
+ @OptionalCandidate
public static Envelope getDomainOfValidity(final CoordinateReferenceSystem crs) {
Envelope envelope = null;
GeneralEnvelope merged = null;
@@ -1096,6 +1102,7 @@ public final class CRS extends Static {
*
* @see org.apache.sis.geometry.GeneralEnvelope#horizontal()
*/
+ @OptionalCandidate
public static SingleCRS getHorizontalComponent(final CoordinateReferenceSystem crs) {
switch (horizontalCode(crs)) {
/*
@@ -1190,6 +1197,7 @@ public final class CRS extends Static {
*
* @category information
*/
+ @OptionalCandidate
public static VerticalCRS getVerticalComponent(final CoordinateReferenceSystem crs, final boolean allowCreateEllipsoidal) {
if (crs instanceof VerticalCRS) {
return (VerticalCRS) crs;
@@ -1233,6 +1241,7 @@ public final class CRS extends Static {
*
* @category information
*/
+ @OptionalCandidate
public static TemporalCRS getTemporalComponent(final CoordinateReferenceSystem crs) {
if (crs instanceof TemporalCRS) {
return (TemporalCRS) crs;
@@ -1348,6 +1357,7 @@ public final class CRS extends Static {
*
* @since 0.5
*/
+ @OptionalCandidate
public static CoordinateReferenceSystem getComponentAt(CoordinateReferenceSystem crs, int lower, int upper) {
if (crs == null) return null; // Skip bounds check.
int dimension = ReferencingUtilities.getDimension(crs);
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java
index 73e125f7a9..13452be39c 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java
@@ -37,6 +37,7 @@ import org.apache.sis.internal.referencing.j2d.AffineTransform2D;
import org.apache.sis.referencing.operation.matrix.AffineTransforms2D;
import org.apache.sis.referencing.operation.matrix.MatrixSIS;
import org.apache.sis.referencing.operation.matrix.Matrices;
+import org.apache.sis.util.OptionalCandidate;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.ArraysExt;
import org.apache.sis.util.Static;
@@ -614,6 +615,7 @@ public final class MathTransforms extends Static {
* @see #linear(Matrix)
* @see LinearTransform#getMatrix()
*/
+ @OptionalCandidate
public static Matrix getMatrix(final MathTransform transform) {
if (transform instanceof LinearTransform) {
return ((LinearTransform) transform).getMatrix();
diff --git a/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java b/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java
index 090d7a8007..0bd4832301 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java
@@ -27,6 +27,7 @@ import org.opengis.geometry.DirectPosition; // For javadoc
import org.opengis.referencing.cs.AxisDirection; // For javadoc
import org.apache.sis.util.Static;
+import org.apache.sis.util.OptionalCandidate;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.internal.util.Constants;
@@ -1793,6 +1794,7 @@ public final class Units extends Static {
*
* @see org.apache.sis.referencing.factory.GeodeticAuthorityFactory#createUnit(String)
*/
+ @OptionalCandidate
public static Unit<?> valueOfEPSG(final int code) {
/*
* The switch for the SexagesimalConverter cases are needed since we did not put those units
@@ -1838,6 +1840,7 @@ public final class Units extends Static {
*
* @since 0.4
*/
+ @OptionalCandidate
public static Integer getEpsgCode(Unit<?> unit, final boolean inAxis) {
if (unit != null) {
if (!(unit instanceof AbstractUnit<?>)) {
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/OptionalCandidate.java b/core/sis-utility/src/main/java/org/apache/sis/util/OptionalCandidate.java
new file mode 100644
index 0000000000..1eb9949eda
--- /dev/null
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/OptionalCandidate.java
@@ -0,0 +1,44 @@
+/*
+ * 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.util;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+
+/**
+ * Marker annotation for methods which may return {@code java.util.Optional} in a future version.
+ * This is applied on some methods introduced at a time when Apache SIS was targeting Java 6 or 7.
+ * Replacing the return value by an {@link java.util.Optional} would be an incompatible change,
+ * so this change will not be applied in SIS 1.x. But it may be applied in SIS 2.0.
+ *
+ * <p><b>Note:</b> the use of this annotation is not a guarantee that the annotated method will return
+ * {@link java.util.Optional} in SIS 2. It only means that this possibility is under consideration.</p>
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.3
+ * @since 1.3
+ * @module
+ */
+@Documented
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.SOURCE)
+public @interface OptionalCandidate {
+}