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 c094a3a01586f727b832a6f034084e1dc8517f2b
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Wed Aug 17 16:56:32 2022 +0200

    Optimization which replaces a "resample" operation by a translation
    can be applied only if the source and target coverages has the same size.
---
 .../sis/coverage/grid/GridCoverageProcessor.java   |  6 ++--
 .../org/apache/sis/coverage/grid/GridExtent.java   | 37 ++++++++++++++++++----
 .../sis/coverage/grid/ResampledGridCoverage.java   | 36 +++++++++++----------
 .../sis/coverage/grid/TranslatedGridCoverage.java  |  9 +++++-
 4 files changed, 63 insertions(+), 25 deletions(-)

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 031942f67f..67a458a3d0 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
@@ -164,8 +164,8 @@ public class GridCoverageProcessor implements Cloneable {
      * but may change other aspects (in a compatible way) such as the {@link 
GridCoverage} subclass
      * returned or the size of the underlying rendered images.
      *
-     * <p>By default all optimizations are enabled. Users may want to disable 
some optimizations
-     * for example in order to get more predictable results.</p>
+     * <p>By default the {@link #REPLACE_OPERATION} and {@link 
#REPLACE_SOURCE} optimizations are enabled.
+     * Users may want to disable some optimizations for example in order to 
get more predictable results.</p>
      *
      * @author  Martin Desruisseaux (Geomatys)
      * @version 1.3
@@ -178,6 +178,7 @@ public class GridCoverageProcessor implements Cloneable {
     public enum Optimization {
         /**
          * Allows the replacement of an operation by a more efficient one.
+         * This optimization is enabled by default.
          *
          * <div class="note"><b>Example:</b>
          * if the {@link #resample(GridCoverage, GridGeometry) resample(…)} 
method is invoked with parameter values
@@ -189,6 +190,7 @@ public class GridCoverageProcessor implements Cloneable {
 
         /**
          * Allows the replacement of source parameter by a more fundamental 
source.
+         * This optimization is enabled by default.
          *
          * <div class="note"><b>Example:</b>
          * if the {@link #resample(GridCoverage, GridGeometry) resample(…)} 
method is invoked with a source
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 e71d284659..af34fe7c5a 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
@@ -1703,14 +1703,28 @@ public class GridExtent implements GridEnvelope, 
LenientComparable, Serializable
     }
 
     /**
-     * Returns a hash value for this grid extent. This value needs not to 
remain
-     * consistent between different implementations of the same class.
+     * Returns whether this grid extent has the same size than the given 
extent.
+     * If the given extent is {@code null} or has a different number of 
dimensions,
+     * then this method returns {@code false}.
      *
-     * @return a hash value for this grid extent.
+     * <p>This method is not public because we do not yet have a policy
+     * about whether we should verify if axis {@link #types} match.</p>
+     *
+     * @param  other  the other extent to compare with this extent. Can be 
{@code null}.
+     * @return whether the two extents has the same size.
      */
-    @Override
-    public int hashCode() {
-        return Arrays.hashCode(coordinates) + Arrays.hashCode(types) ^ (int) 
serialVersionUID;
+    final boolean isSameSize(final GridExtent other) {
+        if (other == null || coordinates.length != other.coordinates.length) {
+            return false;
+        }
+        final int dimension = getDimension();
+        final long[] oc = other.coordinates;
+        for (int i=0; i<dimension; i++) {
+            if (coordinates[i+dimension] - coordinates[i] != oc[i+dimension] - 
oc[i]) {
+                return false;
+            }
+        }
+        return true;
     }
 
     /**
@@ -1755,6 +1769,17 @@ public class GridExtent implements GridEnvelope, 
LenientComparable, Serializable
         return false;
     }
 
+    /**
+     * Returns a hash value for this grid extent. This value needs not to 
remain
+     * consistent between different implementations of the same class.
+     *
+     * @return a hash value for this grid extent.
+     */
+    @Override
+    public int hashCode() {
+        return Arrays.hashCode(coordinates) + Arrays.hashCode(types) ^ (int) 
serialVersionUID;
+    }
+
     /**
      * Returns a string representation of this grid extent. The returned string
      * is implementation dependent and is provided for debugging purposes only.
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 92ffd45d8a..e3114ab04a 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
@@ -184,10 +184,10 @@ final class ResampledGridCoverage extends 
DerivedGridCoverage {
      * If this coverage can be represented as a {@link GridCoverage2D} 
instance,
      * returns such instance. Otherwise returns {@code this}.
      *
-     * @param  isGeometryExplicit  whether grid extent or "grid to CRS" 
transform have been explicitly
-     *         specified by user. In such case, this method will not be 
allowed to change those values.
+     * @param  allowGeometryReplacement   whether to allow the replacement of 
grid geometry in the target coverage.
+     * @param  allowOperationReplacement  whether to allow the replacement of 
this operation by a more efficient one.
      */
-    private GridCoverage specialize(final boolean isGeometryExplicit, final 
boolean allowOperationReplacement)
+    private GridCoverage specialize(final boolean allowGeometryReplacement, 
final boolean allowOperationReplacement)
             throws TransformException
     {
         if (allowOperationReplacement) {
@@ -196,7 +196,8 @@ final class ResampledGridCoverage extends 
DerivedGridCoverage {
                 (translation = getIntegerTranslation(toSourceCorner)) != null)
             {
                 // No need to allow source replacement because it is already 
done by caller.
-                return TranslatedGridCoverage.create(source, gridGeometry, 
translation, false);
+                GridCoverage c = TranslatedGridCoverage.create(source, 
gridGeometry, translation, false);
+                if (c != null) return c;
             }
         }
         GridExtent extent = gridGeometry.getExtent();
@@ -210,7 +211,7 @@ final class ResampledGridCoverage extends 
DerivedGridCoverage {
          * (i.e. user specified only a target CRS), keep same image with a 
different `gridToCRS` transform instead
          * than doing a resampling. The intent is to avoid creating a new 
image if user apparently doesn't care.
          */
-        if (!isGeometryExplicit && toSourceCorner instanceof LinearTransform) {
+        if (allowGeometryReplacement && toSourceCorner instanceof 
LinearTransform) {
             MathTransform gridToCRS = 
gridGeometry.getGridToCRS(PixelInCell.CELL_CORNER);
             if (gridToCRS instanceof LinearTransform) {
                 final GridGeometry sourceGG = source.getGridGeometry();
@@ -287,8 +288,10 @@ final class ResampledGridCoverage extends 
DerivedGridCoverage {
      *     result.</li>
      * </ul>
      *
-     * @param  source  the grid coverage to resample.
-     * @param  target  the desired geometry of returned grid coverage. May be 
incomplete.
+     * @param  source     the grid coverage to resample.
+     * @param  target     the desired geometry of returned grid coverage. May 
be incomplete.
+     * @param  processor  the processor to use for executing the resample 
operation on images.
+     * @param  allowOperationReplacement  whether to allow the replacement of 
this operation by a more efficient one.
      * @return a grid coverage with the characteristics specified in the given 
grid geometry.
      * @throws IncompleteGridGeometryException if the source grid geometry is 
missing an information.
      * @throws TransformException if some coordinates can not be transformed 
to the specified target.
@@ -452,33 +455,34 @@ final class ResampledGridCoverage extends 
DerivedGridCoverage {
          * Build the final target GridGeometry if any components were missing.
          * If an envelope is defined, resample only that sub-region.
          */
-        GridGeometry resampled = target;
+        GridGeometry complete = target;
         ComparisonMode mode = ComparisonMode.IGNORE_METADATA;
         if (!target.isDefined(GridGeometry.EXTENT | GridGeometry.GRID_TO_CRS | 
GridGeometry.CRS)) {
             final CoordinateReferenceSystem targetCRS = 
changeOfCRS.getTargetCRS();
-            resampled = new GridGeometry(targetExtent, 
PixelInCell.CELL_CENTER, targetCenterToCRS, targetCRS);
+            complete = new GridGeometry(targetExtent, PixelInCell.CELL_CENTER, 
targetCenterToCRS, targetCRS);
             mode = ComparisonMode.APPROXIMATE;
             if (target.isDefined(GridGeometry.ENVELOPE)) {
-                final MathTransform targetCornerToCRS = 
resampled.getGridToCRS(PixelInCell.CELL_CORNER);
-                GeneralEnvelope bounds = new 
GeneralEnvelope(resampled.getEnvelope());
+                final MathTransform targetCornerToCRS = 
complete.getGridToCRS(PixelInCell.CELL_CORNER);
+                GeneralEnvelope bounds = new 
GeneralEnvelope(complete.getEnvelope());
                 bounds.intersect(target.getEnvelope());
                 bounds = Envelopes.transform(targetCornerToCRS.inverse(), 
bounds);
                 targetExtent = new GridExtent(bounds, 
GridRoundingMode.NEAREST, GridClippingMode.STRICT, null, null, targetExtent, 
null);
-                resampled = new GridGeometry(targetExtent, 
PixelInCell.CELL_CENTER, targetCenterToCRS, targetCRS);
+                complete = new GridGeometry(targetExtent, 
PixelInCell.CELL_CENTER, targetCenterToCRS, targetCRS);
                 isGeometryExplicit = true;
             }
         }
-        if (sourceGG.equals(resampled, mode)) {
+        if (sourceGG.equals(complete, mode)) {
             return source;
         }
         /*
          * Complete the "target to source" transform.
          */
-        final MathTransform targetCornerToCRS = 
resampled.getGridToCRS(PixelInCell.CELL_CORNER);
-        return new ResampledGridCoverage(source, resampled,
+        final MathTransform targetCornerToCRS = 
complete.getGridToCRS(PixelInCell.CELL_CORNER);
+        final ResampledGridCoverage resampled = new 
ResampledGridCoverage(source, complete,
                 MathTransforms.concatenate(targetCornerToCRS, 
crsToSourceCorner),
                 MathTransforms.concatenate(targetCenterToCRS, 
crsToSourceCenter),
-                changeOfCRS, processor).specialize(isGeometryExplicit, 
allowOperationReplacement);
+                changeOfCRS, processor);
+        return resampled.specialize(!isGeometryExplicit, 
allowOperationReplacement);
     }
 
     /**
diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/TranslatedGridCoverage.java
 
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/TranslatedGridCoverage.java
index 81bb354bbe..c6e2dae659 100644
--- 
a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/TranslatedGridCoverage.java
+++ 
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/TranslatedGridCoverage.java
@@ -42,6 +42,7 @@ final class TranslatedGridCoverage extends 
DerivedGridCoverage {
     /**
      * Constructs a new grid coverage which will delegate the rendering 
operation to the given source.
      * This coverage will take the same sample dimensions than the source.
+     * The {@code domain} size must be the same than the source grid geometry 
size.
      *
      * @param  source       the source on which to delegate rendering 
operations.
      * @param  domain       the grid extent, CRS and conversion from cell 
indices to CRS.
@@ -56,10 +57,14 @@ final class TranslatedGridCoverage extends 
DerivedGridCoverage {
      * Returns a grid coverage which will use the {@code domain} grid geometry.
      * This coverage will take the same sample dimensions than the source.
      *
+     * <p>If {@code domain} is non-null, then it should have the same size 
than the source grid geometry size.
+     * If this is not the case, then this method returns {@code null}.</p>
+     *
      * @param  source       the source on which to delegate rendering 
operations.
      * @param  domain       the geometry of the grid coverage to return, or 
{@code null} for automatic.
      * @param  translation  translation to apply on the argument given to 
{@link #render(GridExtent)}.
-     * @return the coverage. May be the {@code source} returned as-is.
+     * @return the coverage, or {@code null} if {@code domain} is non-null but 
does not have the expected size.
+     *         May be the {@code source} returned as-is.
      */
     static GridCoverage create(GridCoverage source, GridGeometry domain, 
long[] translation,
                                final boolean allowSourceReplacement)
@@ -81,6 +86,8 @@ final class TranslatedGridCoverage extends 
DerivedGridCoverage {
         final GridGeometry gridGeometry = source.getGridGeometry();
         if (domain == null) {
             domain = gridGeometry.translate(translation);
+        } else if (!domain.extent.isSameSize(gridGeometry.extent)) {
+            return null;
         }
         if (domain.equals(gridGeometry)) {
             return source;                  // All (potentially updated) 
translation terms are zero.

Reply via email to