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 a6bfe6ed64fea1d1dffe7e5b299ee84a3d2d1b5e
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Wed Dec 29 04:49:52 2021 +0100

    Fix a bug in the application of longitude wraparound when the objective CRS 
is different than the source CRS.
    The bug caused the image to disapear at some zoom levels.
---
 .../sis/internal/map/coverage/RenderingData.java   | 13 ++++-
 .../internal/referencing/WraparoundApplicator.java | 57 +++++++++++++---------
 .../sis/internal/referencing/package-info.java     |  2 +-
 3 files changed, 46 insertions(+), 26 deletions(-)

diff --git 
a/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/coverage/RenderingData.java
 
b/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/coverage/RenderingData.java
index 42fd292..bff4c87 100644
--- 
a/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/coverage/RenderingData.java
+++ 
b/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/coverage/RenderingData.java
@@ -418,6 +418,7 @@ public class RenderingData implements Cloneable {
 
     /**
      * Returns the position at the center of source data, or {@code null} if 
none.
+     * The coordinates are expressed in the CRS of the source coverage.
      */
     private DirectPosition getSourceMedian() {
         if (dataGeometry.isDefined(GridGeometry.ENVELOPE)) {
@@ -585,13 +586,23 @@ public class RenderingData implements Cloneable {
     /**
      * Conversion or transformation from {@linkplain 
PlanarCanvas#getObjectiveCRS() objective CRS} to
      * {@linkplain #data} CRS. This transform will include {@code 
WraparoundTransform} steps if needed.
+     *
+     * @param  transform     the transform to concatenate with a "wraparound" 
operation.
+     * @param  sourceMedian  point of interest in the <em>source</em> CRS of 
given transform.
+     * @param  targetMedian  point of interest after wraparound.
+     * @param  targetCRS     the target CRS of the given transform.
      */
-    private static MathTransform applyWraparound(final MathTransform 
transform, final DirectPosition sourceMedian,
+    private static MathTransform applyWraparound(final MathTransform 
transform, DirectPosition sourceMedian,
             final DirectPosition targetMedian, final CoordinateReferenceSystem 
targetCRS) throws TransformException
     {
         if (targetMedian == null) {
             return transform;
         }
+        /*
+         * This method is invoked with `sourceMedian` expressed in the 
transform source CRS.
+         * But by contract, `WraparoundApplicator` needs that point in the 
transform target CRS.
+         */
+        sourceMedian = transform.transform(sourceMedian, null);
         return new WraparoundApplicator(sourceMedian, targetMedian, 
targetCRS.getCoordinateSystem()).forDomainOfUse(transform);
     }
 
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WraparoundApplicator.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WraparoundApplicator.java
index e7ce027..411f3bb 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WraparoundApplicator.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WraparoundApplicator.java
@@ -38,13 +38,15 @@ import org.apache.sis.measure.Units;
  * Each {@code WraparoundTransform} instance should be used only once.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.2
  * @since   1.1
  * @module
  */
 public final class WraparoundApplicator {
     /**
      * Coordinates at the center of source envelope, or {@code null} if none.
+     * This coordinate shall be expressed in the source CRS of the {@link 
WraparoundTransform},
+     * not in the source CRS of the concatenated transform to be created by 
this applicator.
      */
     private final DirectPosition sourceMedian;
 
@@ -60,7 +62,9 @@ public final class WraparoundApplicator {
     private final CoordinateSystem targetCS;
 
     /**
-     * Creates a new applicator.
+     * Creates a new applicator. The median coordinates are optional and can 
be null.
+     * Coordinates shall be in the source and target CRS of the {@link 
WraparoundTransform},
+     * not in the source CRS of the concatenated transform to be created by 
this applicator.
      *
      * @param  sourceMedian  the coordinates at the center of source envelope, 
or {@code null} if none.
      * @param  targetMedian  the coordinates to put at the center of new 
range, or {@code null} for standard axis center.
@@ -97,7 +101,7 @@ public final class WraparoundApplicator {
     /**
      * Returns the given transform augmented with a "wrap around" behavior if 
applicable.
      * The wraparound is applied on target coordinates and aims to clamp 
coordinate values
-     * in a range centered on the given median.
+     * in a range centered on the target median given at construction time.
      *
      * <p>The centered ranges may be different than the range declared by the 
coordinate system axes.
      * In such case, the wraparound range applied by this method will have a 
translation compared to
@@ -105,6 +109,9 @@ public final class WraparoundApplicator {
      * (e.g. when transforming a raster) and we want that output coordinates 
to be continuous
      * in that domain, independently of axis ranges.</p>
      *
+     * <p>If a non-null {@code sourceMedian} position has been specified at 
construction time,
+     * those coordinates shall be expressed in the <em>target</em> CRS of 
given transform.</p>
+     *
      * @param  tr  the transform to augment with "wrap around" behavior.
      * @return the math transform with wraparound if needed.
      * @throws TransformException if a coordinate can not be computed.
@@ -133,30 +140,32 @@ public final class WraparoundApplicator {
         if (!(period > 0 && period != Double.POSITIVE_INFINITY)) {
             return tr;
         }
-        double m;
-        if (targetMedian == null) {
-            final CoordinateSystemAxis axis = 
targetCS.getAxis(wraparoundDimension);
-            m = (axis.getMinimumValue() + axis.getMaximumValue()) / 2;
-        } else try {
-            m = targetMedian.getOrdinate(wraparoundDimension);
+        double m, sm;
+        try {
+            if (targetMedian == null) {
+                final CoordinateSystemAxis axis = 
targetCS.getAxis(wraparoundDimension);
+                m = (axis.getMinimumValue() + axis.getMaximumValue()) / 2;
+            } else {
+                m = targetMedian.getOrdinate(wraparoundDimension);
+            }
+            if (!Double.isFinite(m)) {
+                if (targetMedian != null) {
+                    // Invalid median value. Assume caller means "no wrap".
+                    return tr;
+                }
+                /*
+                 * May happen if `WraparoundAdjustment.range(…)` recognized a 
longitude axis
+                 * despite the `CoordinateSystemAxis` not declarining 
minimum/maximum values.
+                 * Use 0 as the range center (e.g. center of [-180 … 180]° 
longitude range).
+                 */
+                m = 0;
+            }
+            sm = (sourceMedian != null) ? 
sourceMedian.getOrdinate(wraparoundDimension) : Double.NaN;
         } catch (BackingStoreException e) {
-            // Some implementations compute coordinates only when first needed.
+            // Some `DirectPosition` implementations compute coordinates only 
when first needed.
             throw e.unwrapOrRethrow(TransformException.class);
         }
-        if (!Double.isFinite(m)) {
-            if (targetMedian != null) {
-                // Invalid median value. Assume caller means "no wrap".
-                return tr;
-            }
-            /*
-             * May happen if `WraparoundAdjustment.range(…)` recognized a 
longitude axis
-             * despite the `CoordinateSystemAxis` not declarining 
minimum/maximum values.
-             * Use 0 as the range center (e.g. center of [-180 … 180]° 
longitude range).
-             */
-            m = 0;
-        }
-        final MathTransform wraparound = 
WraparoundTransform.create(tr.getTargetDimensions(), wraparoundDimension,
-                period, (sourceMedian == null) ? Double.NaN : 
sourceMedian.getOrdinate(wraparoundDimension), m);
+        final MathTransform wraparound = 
WraparoundTransform.create(tr.getTargetDimensions(), wraparoundDimension, 
period, sm, m);
         return MathTransforms.concatenate(tr, wraparound);
     }
 
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/package-info.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/package-info.java
index f279037..b31caf3 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/package-info.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/package-info.java
@@ -24,7 +24,7 @@
  * may change in incompatible ways in any future version without notice.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.2
  * @since   0.3
  * @module
  */

Reply via email to