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 <[email protected]> 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); } /**
