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 dc743d4a4d9a75ba2f9d6ee9ee070912eab2afb8
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Wed Aug 3 18:40:56 2022 +0200

    More robust check for wraparound in `GridEvaluator` when the given point 
has less dimensions than the grid geometry.
---
 .../org/apache/sis/gui/map/ValuesUnderCursor.java  |  1 +
 .../apache/sis/coverage/grid/GridEvaluator.java    | 37 ++++++++++++++++++----
 2 files changed, 32 insertions(+), 6 deletions(-)

diff --git 
a/application/sis-javafx/src/main/java/org/apache/sis/gui/map/ValuesUnderCursor.java
 
b/application/sis-javafx/src/main/java/org/apache/sis/gui/map/ValuesUnderCursor.java
index 8a8a1e0c2a..d618731a48 100644
--- 
a/application/sis-javafx/src/main/java/org/apache/sis/gui/map/ValuesUnderCursor.java
+++ 
b/application/sis-javafx/src/main/java/org/apache/sis/gui/map/ValuesUnderCursor.java
@@ -318,6 +318,7 @@ public abstract class ValuesUnderCursor {
             }
             evaluator = coverage.forConvertedValues(true).evaluator();
             evaluator.setNullIfOutside(true);
+            evaluator.setWraparoundEnabled(true);
             canvas(property).ifPresent((c) -> setSlice(c.getSliceExtent()));
             if (previous != null && 
bands.equals(previous.getSampleDimensions())) {
                 // Same configuration than previous coverage.
diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridEvaluator.java
 
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridEvaluator.java
index 5e22a9d539..a13ca901d3 100644
--- 
a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridEvaluator.java
+++ 
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridEvaluator.java
@@ -183,7 +183,7 @@ public class GridEvaluator implements 
GridCoverage.Evaluator {
     /**
      * Returns the default slice where to perform evaluation, or an empty map 
if unspecified.
      * Keys are dimensions from 0 inclusive to {@link 
GridGeometry#getDimension()} exclusive,
-     * and values are the grid coordinate of the slice in that dimension.
+     * and values are the grid coordinates of the slice in the dimension 
specified by the key.
      *
      * <p>This information allows to invoke {@link #apply(DirectPosition)} 
with for example two-dimensional points
      * even if the underlying coverage is three-dimensional. The missing 
coordinate values are replaced by the
@@ -204,7 +204,7 @@ public class GridEvaluator implements 
GridCoverage.Evaluator {
 
     /**
      * Sets the default slice where to perform evaluation when the points do 
not have enough dimensions.
-     * A {@code null} argument restore the default value, which is to infer 
the slice from the coverage
+     * A {@code null} argument restores the default value, which is to infer 
the slice from the coverage
      * grid geometry.
      *
      * @param  slice  the default slice where to perform evaluation, or an 
empty map if none.
@@ -214,6 +214,7 @@ public class GridEvaluator implements 
GridCoverage.Evaluator {
      *
      * @since 1.3
      */
+    @SuppressWarnings("AssignmentToCollectionOrArrayFieldFromParameter")
     public void setDefaultSlice(Map<Integer,Long> slice) {
         if (!Objects.equals(this.slice, slice)) {
             if (slice != null) {
@@ -475,7 +476,6 @@ public class GridEvaluator implements 
GridCoverage.Evaluator {
          * If most cases, the work of this method ends here. The remaining 
code in this method
          * is for handling wraparound axes. If a coordinate is outside the 
coverage extent,
          * check if a wraparound on some axes would bring the coordinates 
inside the extent.
-         * The first step is to get the point closest to the extent.
          */
         long axes = wraparoundAxes;
         if (axes != 0) {
@@ -487,6 +487,12 @@ public class GridEvaluator implements 
GridCoverage.Evaluator {
                 final double c = coordinates[i];
                 double border;
                 if (c < (border = wraparoundExtent[j++]) || c > (border = 
wraparoundExtent[j])) {
+                    /*
+                     * Detected that the point is outside the grid extent 
along an axis where wraparound is possible.
+                     * The first time that we find such axis, expand the 
coordinates array for storing two points.
+                     * The two points will have the same coordinates, except 
on all axes where the point is outside.
+                     * On those axes, the coordinate of the first point is set 
to the closest border of the grid.
+                     */
                     if (outsideAxes == 0) {
                         final int n = coordinates.length;
                         coordinates = Arrays.copyOf(coordinates, 2*Math.max(n, 
gridToWraparound.getTargetDimensions()));
@@ -502,7 +508,10 @@ public class GridEvaluator implements 
GridCoverage.Evaluator {
             /*
              * If a coordinate was found outside the grid, transform to a CRS 
where we can apply shift.
              * It may be the same CRS than the coverage CRS or the source CRS, 
but not necessarily.
-             * Current version does not try to optimize by checking if `point` 
argument can be reused.
+             * For example if the CRS is projected, then we need to use a 
geographic intermediate CRS.
+             * In the common case where the source CRS is already geographic, 
the second point in the
+             * `coordinates` array after `transform(…)` will contain the same 
coordinates as `point`,
+             * but potentially with more dimensions.
              */
             if (outsideAxes != 0) {
                 gridToWraparound.transform(coordinates, 0, coordinates, 0, 2);
@@ -515,7 +524,7 @@ public class GridEvaluator implements 
GridCoverage.Evaluator {
                          * then round that shift to an integer amount of 
periods. Modify the original
                          * coordinate by applying that modified translation.
                          */
-                        final int oi = i + s;
+                        final int oi = i + s;                       // Index 
of original coordinates.
                         double shift = coordinates[i] - coordinates[oi];
                         shift = Math.copySign(Math.ceil(Math.abs(shift) / 
period), shift) * period;
                         coordinates[oi] += shift;
@@ -536,7 +545,23 @@ public class GridEvaluator implements 
GridCoverage.Evaluator {
                     }
                     outsideAxes &= ~(1L << i);
                 } while (outsideAxes != 0);
-                System.arraycopy(coordinates, 0, position.coordinates, 0, 
position.coordinates.length);
+                /*
+                 * Copy shifted coordinate values to the final 
`FractionalGridCoordinates`, except the NaN values.
+                 * NaN values may exist if the given `point` has less 
dimensions than the grid geometry, in which
+                 * case missing values have been replaced by `slice` values in 
the `target` array but not in the
+                 * `coordinates` array. We want to keep the `slice` values in 
the `target` array.
+                 *
+                 * TODO: to be strict, we should skip the copy only if 
`slice.containsKey(i)` is true, because it
+                 * could happen that a transform resulted in NaN values in 
other dimensions. But that check would
+                 * be costly, so we avoid it for now.
+                 */
+                final double[] target = position.coordinates;
+                for (int i = target.length; --i >= 0;) {
+                    final double value = coordinates[i];
+                    if (!Double.isNaN(value)) {
+                        target[i] = value;
+                    }
+                }
             }
         }
         return position;

Reply via email to