sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] branch geoapi-4.0 updated: When rounding from Envelope to GridExtent result in lower == upper, must ensure than [lower … upper] contains the coordinate.
Date Fri, 13 Mar 2020 13:19:21 GMT
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


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new 112f191  When rounding from Envelope to GridExtent result in lower == upper, must
ensure than [lower … upper] contains the coordinate.
112f191 is described below

commit 112f191a53db4563c52955d5d14f2d7aaf64a3a2
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Fri Mar 13 14:17:53 2020 +0100

    When rounding from Envelope to GridExtent result in lower == upper, must ensure than [lower
… upper] contains the coordinate.
---
 .../org/apache/sis/coverage/grid/GridExtent.java   | 52 ++++++++++++----------
 .../apache/sis/coverage/grid/GridExtentTest.java   | 24 ++++++++--
 2 files changed, 50 insertions(+), 26 deletions(-)

diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridExtent.java b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridExtent.java
index 9ce3ad2..559b8ad 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridExtent.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridExtent.java
@@ -379,8 +379,8 @@ public class GridExtent implements GridEnvelope, Serializable {
          * Now computes the grid extent coordinates.
          */
         for (int i=0; i<dimension; i++) {
-            double min = envelope.getLower(i);
-            double max = envelope.getUpper(i);
+            double min = envelope.getLower(i);                      // Inclusive
+            double max = envelope.getUpper(i);                      // Exclusive
             final boolean isMinValid = (min >= Long.MIN_VALUE);
             final boolean isMaxValid = (max <= Long.MAX_VALUE);
             if (min > max || (enclosing == null && !(isMinValid & isMaxValid)))
{
@@ -411,27 +411,33 @@ public class GridExtent implements GridEnvelope, Serializable {
                 case NEAREST: {
                     lower = Math.round(min);
                     upper = Math.round(max);
-                    if (lower != upper) upper--;                                // For making
the coordinate inclusive.
-                    /*
-                     * The [lower … upper] range may be slightly larger than desired in
some rounding error situations.
-                     * For example if `min` was 1.49999 and 'max' was 2.50001,  the rounding
will create a [1…3] range
-                     * while there is actually only 2 pixels. We detect those rounding problems
by comparing the spans
-                     * before and after rounding.  We attempt an adjustment only if the span
mismatch is ±1, otherwise
-                     * the difference is assumed to be caused by overflow. On the three values
that can be affected by
-                     * the adjustment (min, max and span), we change only the number which
is farthest from an integer
-                     * value.
-                     */
-                    long error = (upper - lower) + 1;                           // Negative
number if overflow.
-                    if (error >= 0) {
-                        final double span = envelope.getSpan(i);
-                        final long extent = Math.round(span);
-                        if (extent != 0 && Math.abs(error -= extent) == 1) {
-                            final double dmin = Math.abs(min - Math.rint(min));
-                            final double dmax = Math.abs(max - Math.rint(max));
-                            final boolean adjustMax = (dmax >= dmin);
-                            if (Math.abs(span - extent) < (adjustMax ? dmax : dmin)) {
-                                if (adjustMax) upper = Math.subtractExact(upper, error);
-                                else lower = Math.addExact(lower, error);
+                    if (lower == upper) {                                       // Equality
implies (max - min) < 1.
+                        if (min - Math.floor(min) > Math.ceil(max) - max) {
+                            upper = --lower;
+                        }
+                    } else {
+                        upper--;                                                // For making
the coordinate inclusive.
+                        /*
+                         * The [lower … upper] range may be slightly larger than desired
in some rounding error situations.
+                         * For example if `min` was 1.49999 and `max` was 2.50001,  the rounding
will create a [1…3] range
+                         * while there is actually only 2 pixels. We detect those rounding
problems by comparing the spans
+                         * before and after rounding.  We attempt an adjustment only if the
span mismatch is ±1, otherwise
+                         * the difference is assumed to be caused by overflow. On the three
values that can be affected by
+                         * the adjustment (min, max and span), we change only the number
which is farthest from an integer
+                         * value.
+                         */
+                        long delta = (upper - lower) + 1;                       // Negative
number if overflow.
+                        if (delta >= 0) {
+                            final double span = envelope.getSpan(i);
+                            final long extent = Math.round(span);
+                            if (extent != 0 && Math.abs(delta -= extent) == 1) {
+                                final double dmin = Math.abs(min - Math.rint(min));
+                                final double dmax = Math.abs(max - Math.rint(max));
+                                final boolean adjustMax = (dmax >= dmin);
+                                if (Math.abs(span - extent) < (adjustMax ? dmax : dmin))
{
+                                    if (adjustMax) upper = Math.subtractExact(upper, delta);
+                                    else lower = Math.addExact(lower, delta);
+                                }
                             }
                         }
                     }
diff --git a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridExtentTest.java
b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridExtentTest.java
index 22ee513..88fd556 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridExtentTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridExtentTest.java
@@ -39,7 +39,7 @@ import static org.apache.sis.test.Assert.*;
  * Tests {@link GridExtent}.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 1.0
+ * @version 1.1
  * @since   1.0
  * @module
  */
@@ -74,7 +74,8 @@ public final strictfp class GridExtentTest extends TestCase {
     }
 
     /**
-     * Tests the {@link GridExtent#GridExtent(AbstractEnvelope, GridRoundingMode, int[],
GridExtent, int[])} constructor.
+     * Tests the {@link GridExtent#GridExtent(AbstractEnvelope,
+     * GridRoundingMode, int[], GridExtent, int[])} constructor.
      */
     @Test
     public void testCreateFromEnvelope() {
@@ -89,7 +90,24 @@ public final strictfp class GridExtentTest extends TestCase {
     }
 
     /**
-     * Tests the rounding performed by the {@link GridExtent#GridExtent(AbstractEnvelope,
GridRoundingMode, int[], GridExtent, int[])} constructor.
+     * Tests the {@link GridExtent#GridExtent(AbstractEnvelope, GridRoundingMode, int[],
+     * GridExtent, int[])} constructor when an envelope has a span close to zero.
+     */
+    @Test
+    public void testCreateFromThinEnvelope() {
+        final GeneralEnvelope env = new GeneralEnvelope(3);
+        env.setRange(0,  11.22,  11.23);
+        env.setRange(1, -23.02, -23.01);
+        env.setRange(2,  34.91,  34.92);
+        GridExtent extent = new GridExtent(env, GridRoundingMode.NEAREST, null, null, null);
+        assertExtentEquals(extent, 0,  11,  11);
+        assertExtentEquals(extent, 1, -24, -24);
+        assertExtentEquals(extent, 2,  34,  34);
+    }
+
+    /**
+     * Tests the rounding performed by the {@link GridExtent#GridExtent(AbstractEnvelope,
+     * GridRoundingMode, int[], GridExtent, int[])} constructor.
      */
     @Test
     public void testRoundings() {


Mime
View raw message