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 38b9d8fc69bcede94dca2a7d19dc2b7621a79333 Author: Martin Desruisseaux <[email protected]> AuthorDate: Wed Oct 17 18:29:37 2018 +0200 Fix rounding error when converting 46°57'8.66" to decimal degrees. The slight rounding error become a 4 cm error in some map projections. --- .../java/org/apache/sis/internal/util/Numerics.java | 2 +- .../org/apache/sis/measure/SexagesimalConverter.java | 20 +++++++++++++++++++- .../apache/sis/measure/SexagesimalConverterTest.java | 13 ++++++++++++- 3 files changed, 32 insertions(+), 3 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 5e50833..a231706 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 @@ -71,7 +71,7 @@ public final class Numerics extends Static { * {@link org.apache.sis.util.ComparisonMode#APPROXIMATIVE}. * * <p>Historically, this was the relative tolerance threshold for considering two - * matrixes as equal. This value has been determined empirically in order to allow + * matrices as equal. This value has been determined empirically in order to allow * {@code org.apache.sis.referencing.operation.transform.ConcatenatedTransform} to * detect the cases where two {@link org.apache.sis.referencing.operation.transform.LinearTransform} * are equal for practical purpose. This threshold can be used as below:</p> diff --git a/core/sis-utility/src/main/java/org/apache/sis/measure/SexagesimalConverter.java b/core/sis-utility/src/main/java/org/apache/sis/measure/SexagesimalConverter.java index 494de7d..dc1dbaf 100644 --- a/core/sis-utility/src/main/java/org/apache/sis/measure/SexagesimalConverter.java +++ b/core/sis-utility/src/main/java/org/apache/sis/measure/SexagesimalConverter.java @@ -41,7 +41,7 @@ import static org.apache.sis.math.MathFunctions.truncate; * This class and all inner classes are immutable, and thus inherently thread-safe. * * @author Martin Desruisseaux (IRD, Geomatys) - * @version 0.8 + * @version 1.0 * @since 0.3 * @module */ @@ -272,6 +272,22 @@ class SexagesimalConverter extends AbstractConverter { } /** + * After calculation of the remaining seconds or minutes, trims the rounding errors presumably + * caused by rounding errors in floating point arithmetic. This is required for avoiding the + * following conversion issue: + * + * <ol> + * <li>Sexagesimal value: 46.570866 (from 46°57'8.66"N in EPSG:2056 projected CRS)</li> + * <li>value * 10000 = 465708.66000000003</li> + * <li>deg = 46, min = 57, deg = 8.660000000032596</li> + * </ol> + */ + private static double fixRoundingError(final double remainder) { + final double c = Math.rint(remainder * 1E+6) / 1E+6; + return (Math.abs(remainder - c) < 1E-9) ? c : remainder; + } + + /** * Performs a conversion from sexagesimal degrees to fractional degrees. * * @throws IllegalArgumentException If the given angle can not be converted. @@ -283,11 +299,13 @@ class SexagesimalConverter extends AbstractConverter { sec = angle * divider; deg = truncate(sec/10000); sec -= 10000*deg; min = truncate(sec/ 100); sec -= 100*min; + sec = fixRoundingError(sec); } else { sec = 0; min = angle * divider; deg = truncate(min / 100); min -= deg * 100; + min = fixRoundingError(min); } if (min <= -60 || min >= 60) { // Do not enter for NaN if (Math.abs(Math.abs(min) - 100) <= (EPS * 100)) { diff --git a/core/sis-utility/src/test/java/org/apache/sis/measure/SexagesimalConverterTest.java b/core/sis-utility/src/test/java/org/apache/sis/measure/SexagesimalConverterTest.java index d7187e8..f6c385e 100644 --- a/core/sis-utility/src/test/java/org/apache/sis/measure/SexagesimalConverterTest.java +++ b/core/sis-utility/src/test/java/org/apache/sis/measure/SexagesimalConverterTest.java @@ -30,7 +30,7 @@ import static org.apache.sis.test.Assert.*; * Test the {@link SexagesimalConverter} class. * * @author Martin Desruisseaux (Geomatys) - * @version 0.8 + * @version 1.0 * @since 0.3 * @module */ @@ -93,6 +93,17 @@ public final strictfp class SexagesimalConverterTest extends TestCase { } /** + * Tests the fix for rounding error in conversion of 46°57'8.66". + * This fix is necessary for avoiding a 4 cm error with Apache SIS + * construction of EPSG:2056 projected CRS. + */ + @Test + public void testRoundingErrorFix() { + final UnitConverter c = DMS.getConverterTo(Units.DEGREE); + assertEquals(46.95240555555556, c.convert(46.570866), STRICT); + } + + /** * Verifies the unit symbols. */ @Test
