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 6dd5c5754d1b5b6a0c6bf611134a4cb24a57f87a
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Thu May 26 19:39:34 2022 +0200

    Add a `PixelInCell` argument to the `GridExtent.getPointOfInterest()` 
method.
    It matter when we use that method for getting the coordinates of a slice.
---
 .../coverage/grid/CoordinateOperationFinder.java   |  2 +-
 .../sis/coverage/grid/GridCoverageProcessor.java   |  2 +-
 .../apache/sis/coverage/grid/GridDerivation.java   |  7 ++++--
 .../apache/sis/coverage/grid/GridEvaluator.java    |  2 +-
 .../org/apache/sis/coverage/grid/GridExtent.java   | 29 ++++++++++++++++++++--
 .../org/apache/sis/coverage/grid/GridGeometry.java | 17 +++++++------
 .../sis/coverage/grid/ResampledGridCoverage.java   |  9 ++++---
 .../apache/sis/coverage/grid/SliceGeometry.java    |  7 +++---
 .../sis/internal/coverage/CoverageCombiner.java    |  4 +--
 .../main/java/org/apache/sis/portrayal/Canvas.java |  2 +-
 .../org/apache/sis/portrayal/CanvasExtent.java     | 10 +++++---
 .../org/apache/sis/portrayal/package-info.java     |  2 +-
 .../sis/storage/geotiff/MultiResolutionImage.java  |  6 ++---
 13 files changed, 67 insertions(+), 32 deletions(-)

diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/CoordinateOperationFinder.java
 
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/CoordinateOperationFinder.java
index 11f1c65f34..2b2fefbc6d 100644
--- 
a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/CoordinateOperationFinder.java
+++ 
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/CoordinateOperationFinder.java
@@ -645,7 +645,7 @@ apply:          if (forwardChangeOfCRS == null) {
             @SuppressWarnings("ReturnOfCollectionOrArrayField")
             private double[] coordinates() {
                 if (coordinates == null) try {
-                    final double[] poi = grid.getExtent().getPointOfInterest();
+                    final double[] poi = 
grid.getExtent().getPointOfInterest(PixelInCell.CELL_CENTER);
                     MathTransform tr = 
grid.getGridToCRS(PixelInCell.CELL_CENTER);
                     if (changeOfCRS != null) {
                         tr = MathTransforms.concatenate(tr, changeOfCRS);
diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverageProcessor.java
 
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverageProcessor.java
index 0e855321e1..d00e268bc1 100644
--- 
a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverageProcessor.java
+++ 
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverageProcessor.java
@@ -273,7 +273,7 @@ public class GridCoverageProcessor implements Cloneable {
      *   </tr><tr>
      *     <td>{@linkplain GridGeometry#getExtent() Grid extent}</td>
      *     <td>A default size preserving resolution at source
-     *       {@linkplain GridExtent#getPointOfInterest() point of 
interest}.</td>
+     *       {@linkplain GridExtent#getPointOfInterest(PixelInCell) point of 
interest}.</td>
      *   </tr><tr>
      *     <td>{@linkplain GridGeometry#getGridToCRS Grid to CRS 
transform}</td>
      *     <td>Whatever it takes for fitting data inside the supplied 
extent.</td>
diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridDerivation.java
 
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridDerivation.java
index cbf5981039..44772cba57 100644
--- 
a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridDerivation.java
+++ 
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridDerivation.java
@@ -520,7 +520,7 @@ public class GridDerivation {
                 throw new IllegalGridGeometryException(e, "areaOfInterest");
             }
             // The `domain` extent must be the source of the `mapCenters` 
transform.
-            scales = GridGeometry.resolution(mapCenters, domain);
+            scales = GridGeometry.resolution(mapCenters, domain, 
PixelInCell.CELL_CENTER);
         }
         /*
          * The subsampling will determine the scale factors in the transform 
from the given desired grid geometry
@@ -771,9 +771,12 @@ public class GridDerivation {
      * Returns the point of interest of current {@link #baseExtent}, keeping 
only the remaining
      * dimensions after {@link #dropUnusedDimensions(MathTransform, int)} 
execution.
      * The position is in units of {@link #base} grid coordinates.
+     *
+     * <p>This method assumes that the transform will be used with a "cell 
corner to CRS" transform
+     * instead of the usual "cell center to CRS".</p>
      */
     private double[] getPointOfInterest() {
-        final double[] pointOfInterest = baseExtent.getPointOfInterest();
+        final double[] pointOfInterest = 
baseExtent.getPointOfInterest(PixelInCell.CELL_CORNER);
         if (modifiedDimensions == null) {
             return pointOfInterest;
         }
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 4fd6641959..8feb79b4ef 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
@@ -187,7 +187,7 @@ public class GridEvaluator implements 
GridCoverage.Evaluator {
                 final GridExtent extent = gridGeometry.getExtent();
                 MathTransform gridToCRS = 
gridGeometry.getGridToCRS(PixelInCell.CELL_CENTER);
                 gridToWraparound = MathTransforms.concatenate(gridToCRS, 
f.preferredToSpecified.inverse());
-                final Matrix m = gridToWraparound.derivative(new 
DirectPositionView.Double(extent.getPointOfInterest()));
+                final Matrix m = gridToWraparound.derivative(new 
DirectPositionView.Double(extent.getPointOfInterest(PixelInCell.CELL_CENTER)));
                 /*
                  * `gridToWraparound` is the transform from grid coordinates 
to a CRS where wraparound axes exist.
                  * It may be the coverage CRS or its base CRS. The wraparound 
axes are identified by `periods`.
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 5ff27e6569..3376c00fe0 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
@@ -33,6 +33,7 @@ import org.opengis.metadata.spatial.DimensionNameType;
 import org.opengis.referencing.cs.AxisDirection;
 import org.opengis.referencing.cs.CoordinateSystem;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.datum.PixelInCell;
 import org.opengis.referencing.operation.Matrix;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.TransformException;
@@ -785,23 +786,47 @@ public class GridExtent implements GridEnvelope, 
LenientComparable, Serializable
         return Numerics.toUnsignedDouble(size);
     }
 
+    /**
+     * @deprecated Replaced by {@link #getPointOfInterest(PixelInCell)}.
+     *
+     * @return the grid coordinates of a representative point.
+     */
+    @Deprecated
+    public double[] getPointOfInterest() {
+        return getPointOfInterest(PixelInCell.CELL_CORNER);
+    }
+
     /**
      * Returns the grid coordinates of a representative point.
      * This point may be used for estimating a {@linkplain 
GridGeometry#getResolution(boolean) grid resolution}.
      * The default implementation returns the median (or center) coordinates 
of this grid extent,
      * but subclasses can override this method if another point is considered 
more representative.
      *
+     * <p>The {@code anchpr} argument tells {@linkplain 
GridGeometry#getGridToCRS(PixelInCell) which transform}
+     * the caller intend to use for converting the grid coordinates to "real 
world" coordinates.
+     * With the default implementation, the coordinate values returned with 
{@code CELL_CORNER}
+     * are 0.5 cell units higher than the coordinate values returned with 
{@code CELL_CENTER}.
+     * Subclasses are free to ignore this argument.</p>
+     *
+     * @param  anchor  the convention to be used for conversion to "real 
world" coordinates.
      * @return the grid coordinates of a representative point.
+     *
+     * @since 1.3
      */
-    public double[] getPointOfInterest() {
+    public double[] getPointOfInterest(final PixelInCell anchor) {
         final int dimension = getDimension();
         final double[] center = new double[dimension];
+        final boolean isCorner = PixelInCell.CELL_CORNER.equals(anchor);
         for (int i=0; i<dimension; i++) {
             /*
              * We want the average of (low + hi+1). However for the purpose of 
computing an average, it does
              * not matter if we add 1 to `low` or `hi`. So we add 1 to `low` 
because it should not overflow.
              */
-            center[i] = 
MathFunctions.average(Math.incrementExact(coordinates[i]), coordinates[i + 
dimension]);
+            long low = coordinates[i];
+            if (isCorner) {
+                low = Math.incrementExact(coordinates[i]);
+            }
+            center[i] = MathFunctions.average(low, coordinates[i + dimension]);
         }
         return center;
     }
diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java 
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
index 7a9d5c481d..d7108e3167 100644
--- 
a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
+++ 
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
@@ -129,7 +129,7 @@ import static org.apache.sis.referencing.CRS.findOperation;
  * The same instance can be shared by different {@link GridCoverage} instances.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 1.2
+ * @version 1.3
  * @since   1.0
  * @module
  */
@@ -367,12 +367,12 @@ public class GridGeometry implements LenientComparable, 
Serializable {
                         MathTransforms.uniformTranslation(dimension, -0.5));
                 cornerToCRS = MathTransforms.concatenate(toOther, 
other.cornerToCRS);
                 gridToCRS   = MathTransforms.concatenate(centerShift, 
other.gridToCRS);
-                resolution  = resolution(gridToCRS, extent);
+                resolution  = resolution(gridToCRS, extent, 
PixelInCell.CELL_CENTER);
                 nonLinears  = findNonLinearTargets(gridToCRS);
             } else {
                 cornerToCRS = null;
                 gridToCRS   = null;
-                resolution  = resolution(toOther, extent);      // Save 
resolution even if `gridToCRS` is null.
+                resolution  = resolution(toOther, extent, 
PixelInCell.CELL_CENTER);     // Save resolution even if `gridToCRS` is null.
                 nonLinears  = findNonLinearTargets(toOther);
             }
         }
@@ -445,7 +445,7 @@ public class GridGeometry implements LenientComparable, 
Serializable {
             this.gridToCRS   = PixelTranslation.translate(gridToCRS, anchor, 
PixelInCell.CELL_CENTER);
             this.cornerToCRS = PixelTranslation.translate(gridToCRS, anchor, 
PixelInCell.CELL_CORNER);
             this.envelope    = computeEnvelope(gridToCRS, crs, null);   // 
`gridToCRS` specified by the user, not `this.gridToCRS`.
-            this.resolution  = resolution(gridToCRS, extent);           // 
`gridToCRS` or `cornerToCRS` does not matter here.
+            this.resolution  = resolution(gridToCRS, extent, anchor);   // 
`gridToCRS` or `cornerToCRS` does not matter here.
             this.nonLinears  = findNonLinearTargets(gridToCRS);
         } catch (TransformException e) {
             throw new IllegalGridGeometryException(e, "gridToCRS");
@@ -541,7 +541,7 @@ public class GridGeometry implements LenientComparable, 
Serializable {
             this.envelope = new ImmutableEnvelope(env);
             if (scales == null) try {
                 // `gridToCRS` can not be null if `cornerToCRS` is non-null.
-                scales = gridToCRS.derivative(new 
DirectPositionView.Double(extent.getPointOfInterest()));
+                scales = gridToCRS.derivative(new 
DirectPositionView.Double(extent.getPointOfInterest(anchor)));
                 numToIgnore = 0;
             } catch (TransformException e) {
                 recoverableException("<init>", e);
@@ -1029,7 +1029,7 @@ public class GridGeometry implements LenientComparable, 
Serializable {
      * <ul>
      *   <li>{@link Double#NaN} if {@code allowEstimates} is {@code 
false}.</li>
      *   <li>An arbitrary representative resolution otherwise.
-     *       Current implementation computes the resolution at {@link 
GridExtent#getPointOfInterest() grid center},
+     *       Current implementation computes the resolution at {@link 
GridExtent#getPointOfInterest(PixelInCell) grid center},
      *       but different implementations may use alternative algorithms.</li>
      * </ul>
      *
@@ -1067,14 +1067,15 @@ public class GridGeometry implements LenientComparable, 
Serializable {
      * @param  gridToCRS  a transform for which to compute the resolution, or 
{@code null} if none.
      * @param  domain     the domain for which to get a resolution, or {@code 
null} if none.
      *                    If non-null, must be the source of {@code gridToCRS}.
+     * @param  anchor     the pixel corner versus pixel center convention to 
use.
      * @return the resolutions as positive numbers. May contain NaN values.
      */
-    static double[] resolution(final MathTransform gridToCRS, final GridExtent 
domain) {
+    static double[] resolution(final MathTransform gridToCRS, final GridExtent 
domain, final PixelInCell anchor) {
         final Matrix matrix = MathTransforms.getMatrix(gridToCRS);
         if (matrix != null) {
             return resolution(matrix, 1);
         } else if (domain != null && gridToCRS != null) try {
-            return resolution(gridToCRS.derivative(new 
DirectPositionView.Double(domain.getPointOfInterest())), 0);
+            return resolution(gridToCRS.derivative(new 
DirectPositionView.Double(domain.getPointOfInterest(anchor))), 0);
         } catch (TransformException e) {
             recoverableException("resolution", e);
         }
diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ResampledGridCoverage.java
 
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ResampledGridCoverage.java
index d095047bd1..6df6d5d925 100644
--- 
a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ResampledGridCoverage.java
+++ 
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ResampledGridCoverage.java
@@ -52,7 +52,7 @@ import org.apache.sis.util.Utilities;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Johann Sorel (Geomatys)
- * @version 1.2
+ * @version 1.3
  * @since   1.1
  * @module
  */
@@ -134,7 +134,7 @@ final class ResampledGridCoverage extends GridCoverage {
      * For a source dimension <var>i</var>, {@code dependentDimensions[i]} is 
a bitmask with bits set to 1
      * for each target dimension which require the source dimension 
<var>i</var> for its calculation.
      *
-     * @param  mt      the transform for which to determine dimension 
dependencies.
+     * @param  mt      the transform (mapping pixel centers) for which to 
determine dimension dependencies.
      * @param  domain  domain of this {@code}.
      * @return for each source dimension, a bitmask of target dependent 
dimensions.
      *         May be {@code null} if the mapping can not be computed or if it 
is not needed.
@@ -144,7 +144,8 @@ final class ResampledGridCoverage extends GridCoverage {
         if (srcDim <= BIDIMENSIONAL) return null;                           // 
Dimension mapping not needed.
         Matrix derivative = MathTransforms.getMatrix(mt);
         if (derivative == null) try {
-            derivative = mt.derivative(new 
DirectPositionView.Double(domain.getExtent().getPointOfInterest()));
+            derivative = mt.derivative(new DirectPositionView.Double(
+                    
domain.getExtent().getPointOfInterest(PixelInCell.CELL_CENTER)));
         } catch (TransformException e) {
             GridCoverageProcessor.recoverableException("resample", e);      // 
Public caller of this method.
             return null;
@@ -306,7 +307,7 @@ final class ResampledGridCoverage extends GridCoverage {
              * `originToPOI` vector (the integer digits do not matter; they 
will be cancelled later).
              */
             final GridExtent sourceExtent = sourceGG.getExtent();
-            final double[]   sourcePOI    = sourceExtent.getPointOfInterest();
+            final double[]   sourcePOI    = 
sourceExtent.getPointOfInterest(PixelInCell.CELL_CENTER);
             final double[]   targetPOI    = new 
double[sourceCenterToCRS.getTargetDimensions()];
             final MatrixSIS  vectors      = 
MatrixSIS.castOrCopy(MathTransforms.derivativeAndTransform(
                                                         sourceCenterToCRS, 
sourcePOI, 0, targetPOI, 0));
diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/SliceGeometry.java
 
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/SliceGeometry.java
index 0279bacbe4..18e56c8b0e 100644
--- 
a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/SliceGeometry.java
+++ 
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/SliceGeometry.java
@@ -20,6 +20,7 @@ import java.util.function.Function;
 import java.awt.image.RenderedImage;
 import java.awt.image.ImagingOpException;
 import org.opengis.util.FactoryException;
+import org.opengis.referencing.datum.PixelInCell;
 import org.opengis.referencing.operation.Matrix;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
@@ -47,7 +48,7 @@ import org.apache.sis.util.resources.Errors;
  * That function is invoked (indirectly) by {@link 
org.apache.sis.internal.coverage.j2d.TiledImage#getProperty(String)}.</p>
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.3
  * @since   1.1
  * @module
  */
@@ -221,7 +222,7 @@ final class SliceGeometry implements 
Function<RenderedImage, GridGeometry> {
          * from the original grid geometry.
          */
         if (useSubExtent || resolution == null) {
-            resolution = GridGeometry.resolution(gridToCRS, extent);
+            resolution = GridGeometry.resolution(gridToCRS, extent, 
PixelInCell.CELL_CENTER);
         } else if (resolution.length != n) {
             resolution = new double[n];
             for (int i=0; i<n; i++) {
@@ -296,7 +297,7 @@ final class SliceGeometry implements 
Function<RenderedImage, GridGeometry> {
         Matrix derivative = MathTransforms.getMatrix(gridToCRS);
         if (derivative == null) {
             if (extent != null) try {
-                derivative = gridToCRS.derivative(new 
DirectPositionView.Double(extent.getPointOfInterest()));
+                derivative = gridToCRS.derivative(new 
DirectPositionView.Double(extent.getPointOfInterest(PixelInCell.CELL_CENTER)));
             } catch (TransformException e) {
                 // GridGeometry.reduce(…) is the public method invoking 
indirectly this method.
                 GridGeometry.recoverableException("reduce", e);
diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/CoverageCombiner.java
 
b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/CoverageCombiner.java
index e8c4b09818..e47aa35218 100644
--- 
a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/CoverageCombiner.java
+++ 
b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/CoverageCombiner.java
@@ -65,7 +65,7 @@ import static 
org.apache.sis.internal.util.Numerics.saturatingSubtract;
  * be outside the bounds of destination coverage.</p>
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
  *
  * @see ImageCombiner
  *
@@ -233,7 +233,7 @@ next:   for (int j=0; j<sources.length; j++) {
          */
         final long[] minSliceIndices = minIndices.clone();
         final long[] maxSliceIndices = maxIndices.clone();
-        final double[] centerIndices = targetEx.getPointOfInterest();
+        final double[] centerIndices = 
targetEx.getPointOfInterest(PixelInCell.CELL_CENTER);
         final Dimension margin = processor.getInterpolation().getSupportSize();
         margin.width  = ((margin.width  + 1) >> 1) + 1;
         margin.height = ((margin.height + 1) >> 1) + 1;
diff --git 
a/core/sis-portrayal/src/main/java/org/apache/sis/portrayal/Canvas.java 
b/core/sis-portrayal/src/main/java/org/apache/sis/portrayal/Canvas.java
index 26b29e0cc0..20f03709a0 100644
--- a/core/sis-portrayal/src/main/java/org/apache/sis/portrayal/Canvas.java
+++ b/core/sis-portrayal/src/main/java/org/apache/sis/portrayal/Canvas.java
@@ -1079,7 +1079,7 @@ public class Canvas extends Observable implements 
Localized {
                 crs = null;
                 newPOI = new 
GeneralDirectPosition(gridToCRS.getTargetDimensions());
             }
-            gridToCRS.transform(extent.getPointOfInterest(), 0, 
newPOI.coordinates, 0, 1);
+            
gridToCRS.transform(extent.getPointOfInterest(PixelInCell.CELL_CORNER), 0, 
newPOI.coordinates, 0, 1);
             /*
              * Get the CRS component in the dimensions shown by this canvas.
              *
diff --git 
a/core/sis-portrayal/src/main/java/org/apache/sis/portrayal/CanvasExtent.java 
b/core/sis-portrayal/src/main/java/org/apache/sis/portrayal/CanvasExtent.java
index 8ef655ce5f..2f0ba14db3 100644
--- 
a/core/sis-portrayal/src/main/java/org/apache/sis/portrayal/CanvasExtent.java
+++ 
b/core/sis-portrayal/src/main/java/org/apache/sis/portrayal/CanvasExtent.java
@@ -18,6 +18,7 @@ package org.apache.sis.portrayal;
 
 import java.util.List;
 import org.opengis.geometry.DirectPosition;
+import org.opengis.referencing.datum.PixelInCell;
 import org.opengis.referencing.operation.Matrix;
 import org.opengis.referencing.cs.AxisDirection;
 import org.opengis.referencing.cs.CoordinateSystem;
@@ -40,7 +41,7 @@ import org.apache.sis.internal.util.Numerics;
  * This class contains also static help functions for the construction of 
{@link GridGeometry}.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.3
  * @since   1.1
  * @module
  */
@@ -54,7 +55,7 @@ final class CanvasExtent extends GridExtent {
      * The grid coordinates of a representative point. The {@code 
CanvasExtent} point of interest
      * is the {@code Canvas} point of interest converted to (typically) pixel 
coordinates.
      *
-     * @see #getPointOfInterest()
+     * @see #getPointOfInterest(PixelInCell)
      */
     private final double[] pointOfInterest;
 
@@ -75,10 +76,13 @@ final class CanvasExtent extends GridExtent {
      * Returns the grid coordinates of a representative point.
      * This is the canvas point of interest converted to (typically) pixel 
coordinates.
      *
+     * @param  anchor  the convention to be used for conversion to "real 
world" coordinates.
+     * @return the grid coordinates of a representative point.
+     *
      * @see Canvas#getPointOfInterest(boolean)
      */
     @Override
-    public double[] getPointOfInterest() {
+    public double[] getPointOfInterest(final PixelInCell anchor) {
         return pointOfInterest.clone();
     }
 
diff --git 
a/core/sis-portrayal/src/main/java/org/apache/sis/portrayal/package-info.java 
b/core/sis-portrayal/src/main/java/org/apache/sis/portrayal/package-info.java
index 2b8bbb237f..18b7fc3e2e 100644
--- 
a/core/sis-portrayal/src/main/java/org/apache/sis/portrayal/package-info.java
+++ 
b/core/sis-portrayal/src/main/java/org/apache/sis/portrayal/package-info.java
@@ -25,7 +25,7 @@
  * Synchronization, if desired, must be done by the caller.
  *
  * @author  Johann Sorel (Geomatys)
- * @version 1.1
+ * @version 1.3
  * @since   1.1
  * @module
  */
diff --git 
a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/MultiResolutionImage.java
 
b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/MultiResolutionImage.java
index 8ca1b4d1ba..d5cf951dbe 100644
--- 
a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/MultiResolutionImage.java
+++ 
b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/MultiResolutionImage.java
@@ -152,8 +152,8 @@ final class MultiResolutionImage extends 
GridResourceWrapper {
             }
             image.initReducedResolution(base, scales);
             if (geometry.isDefined(GridGeometry.GRID_TO_CRS)) {
-                final MatrixSIS gridToCRS = 
MatrixSIS.castOrCopy(geometry.getGridToCRS(PixelInCell.CELL_CENTER)
-                                  .derivative(new 
DirectPositionView.Double(fullExtent.getPointOfInterest())));
+                DirectPosition poi = new 
DirectPositionView.Double(fullExtent.getPointOfInterest(PixelInCell.CELL_CENTER));
+                MatrixSIS gridToCRS = 
MatrixSIS.castOrCopy(geometry.getGridToCRS(PixelInCell.CELL_CENTER).derivative(poi));
                 resolution = gridToCRS.multiply(scales);
             } else {
                 // Assume an identity transform for the `gridToCRS` of full 
resolution image.
@@ -211,7 +211,7 @@ final class MultiResolutionImage extends 
GridResourceWrapper {
                  * If the `domain` grid geometry has a resolution and an 
envelope, then it should have
                  * an extent and a "grid to CRS" transform (otherwise it may 
be a `GridGeometry` bug)
                  */
-                DirectPosition poi = new 
DirectPositionView.Double(domain.getExtent().getPointOfInterest());
+                DirectPosition poi = new 
DirectPositionView.Double(domain.getExtent().getPointOfInterest(PixelInCell.CELL_CENTER));
                 poi = 
domain.getGridToCRS(PixelInCell.CELL_CENTER).transform(poi, null);
                 final MatrixSIS derivative = 
MatrixSIS.castOrCopy(sourceToCoverage.derivative(poi));
                 resolution = derivative.multiply(resolution);

Reply via email to