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 d41d7fa8386e0d9e196fe92e5bbbd5c8dbac0041
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Sat Jul 2 17:36:42 2022 +0200

    Make a better use of new `MathTransforms.getDomain(…)` API in JavaFX viewer.
---
 .../sis/internal/map/coverage/RenderingData.java   | 67 ++++------------------
 .../java/org/apache/sis/geometry/Shapes2D.java     | 22 ++++++-
 2 files changed, 31 insertions(+), 58 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 bb24a390cb..f87b995e2e 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
@@ -30,7 +30,6 @@ import java.awt.geom.Rectangle2D;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.NoninvertibleTransformException;
 import org.opengis.util.FactoryException;
-import org.opengis.geometry.Envelope;
 import org.opengis.geometry.DirectPosition;
 import org.opengis.metadata.extent.GeographicBoundingBox;
 import org.opengis.referencing.datum.PixelInCell;
@@ -48,7 +47,6 @@ import org.apache.sis.coverage.grid.PixelTranslation;
 import org.apache.sis.coverage.SampleDimension;
 import org.apache.sis.geometry.AbstractEnvelope;
 import org.apache.sis.geometry.Envelope2D;
-import org.apache.sis.geometry.Envelopes;
 import org.apache.sis.geometry.Shapes2D;
 import org.apache.sis.image.PlanarImage;
 import org.apache.sis.image.ErrorHandler;
@@ -185,21 +183,6 @@ public class RenderingData implements Cloneable {
      */
     private GridGeometry dataGeometry;
 
-    /**
-     * The domain of validity of the objective CRS in units of the {@link 
#data} image.
-     * This value needs to be recomputed when the objective CRS or the {@link 
#dataGeometry} changes.
-     * It is used for avoiding failure to project a part of the image too far 
from what the projection
-     * can handle, for example polar areas with a Mercator projection.
-     */
-    private Rectangle domainOfValidity;
-
-    /**
-     * A value for {@link #domainOfValidity} meaning that there is no limits. 
Should not be modified.
-     */
-    private static final Rectangle NO_LIMITS = new Rectangle(
-            Integer.MIN_VALUE/2, Integer.MIN_VALUE/2,
-            Integer.MAX_VALUE,   Integer.MAX_VALUE);
-
     /**
      * Ranges of sample values in each band of {@link #data}. This is used for 
determining on which sample values
      * to apply colors when user asked to apply a color ramp. May be {@code 
null}.
@@ -289,7 +272,6 @@ public class RenderingData implements Cloneable {
         changeOfCRS       = null;
         cornerToObjective = null;
         objectiveToCenter = null;
-        domainOfValidity  = null;
     }
 
     /**
@@ -439,7 +421,6 @@ public class RenderingData implements Cloneable {
             final MathTransform inverse = concatenate(PixelInCell.CELL_CENTER, 
old, dataGeometry, toNew);
             cornerToObjective = MathTransforms.concatenate(forward, 
cornerToObjective);
             objectiveToCenter = MathTransforms.concatenate(objectiveToCenter, 
inverse);
-            domainOfValidity  = null;       // Will be recomputed when needed.
         }
         return true;
     }
@@ -568,40 +549,6 @@ public class RenderingData implements Cloneable {
         }
     }
 
-    /**
-     * Returns the bounds of the given image clipped to the domain of validity 
of the objective CRS.
-     * The intent is to avoid a failure to reproject the image, for example if 
the image reaches the
-     * poles and the objective CRS is a Mercator projection.
-     */
-    private Rectangle getValidImageBounds(final RenderedImage image) throws 
TransformException {
-        Rectangle bounds = ImageUtilities.getBounds(image);
-        if (domainOfValidity == NO_LIMITS) {        // Identity comparison is 
okay here (quick check).
-            return bounds;
-        }
-        if (domainOfValidity == null) {
-            Envelope domain = 
MathTransforms.getDomain(changeOfCRS.getMathTransform().inverse()).orElse(null);
-            if (domain == null) {
-                domainOfValidity = NO_LIMITS;
-                return bounds;
-            }
-            domain = Envelopes.transform(cornerToObjective.inverse(), domain);
-            double x = domain.getMinimum(0);
-            double y = domain.getMinimum(1);
-            double w = domain.getSpan(0);
-            double h = domain.getSpan(1);
-            if (!(x >= Integer.MIN_VALUE)) x = Integer.MIN_VALUE/2;     // Use 
`!` for catching NaN.
-            if (!(y >= Integer.MIN_VALUE)) y = Integer.MIN_VALUE/2;
-            if (!(h <= Integer.MAX_VALUE)) h = Integer.MAX_VALUE;
-            if (!(w <= Integer.MAX_VALUE)) w = Integer.MAX_VALUE;
-            domainOfValidity = new Rectangle(
-                    (int) Math.min(x, Integer.MAX_VALUE),
-                    (int) Math.min(y, Integer.MAX_VALUE),
-                    (int) Math.max(w, 0),
-                    (int) Math.max(h, 0));
-        }
-        return bounds.intersection(domainOfValidity);
-    }
-
     /**
      * Creates the resampled image, then optionally applies an index color 
model.
      * This method will compute the {@link MathTransform} steps from image 
coordinate system
@@ -650,7 +597,7 @@ public class RenderingData implements Cloneable {
         /*
          * Create a resampled image for current zoom level. If the image is 
zoomed, the resampled image bounds
          * will be very large, potentially larger than 32 bit integer capacity 
(calculation done below clamps
-         * the result to 32 bit integer range). This is okay since only 
visible tiles will be created.
+         * the result to 32 bit integer range). This is okay because only 
visible tiles will be created.
          *
          * NOTE: if user pans image close to integer range limit, a new 
resampled image will need to be computed
          *       for shifting away from integer overflow risk situation. This 
check is done by the caller.
@@ -659,9 +606,15 @@ public class RenderingData implements Cloneable {
         displayToObjective = AffineTransforms2D.castOrCopy(inverse);
         MathTransform cornerToDisplay = 
MathTransforms.concatenate(cornerToObjective, objectiveToDisplay);
         MathTransform displayToCenter = MathTransforms.concatenate(inverse, 
objectiveToCenter);
-        final Rectangle bounds = (Rectangle) Shapes2D.transform(
-                MathTransforms.bidimensional(cornerToDisplay),
-                getValidImageBounds(recoloredImage), new Rectangle());
+        /*
+         * If the source image is world-wide and if the transform involves a 
projection that can not represent
+         * the whole world, then we need to clip the image to a domain 
supported by the map projection.
+         */
+        final Rectangle bounds = ImageUtilities.getBounds(recoloredImage);
+        MathTransforms.getDomain(cornerToDisplay).ifPresent((domain) -> {
+            Shapes2D.intersect(bounds, domain, 0, 1);
+        });
+        Shapes2D.transform(MathTransforms.bidimensional(cornerToDisplay), 
bounds, bounds);
         /*
          * Verify if wraparound is really necessary. We do this check because 
the `displayToCenter` transform
          * may be used for every pixels, so it is worth to make that transform 
more efficient if possible.
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/geometry/Shapes2D.java 
b/core/sis-referencing/src/main/java/org/apache/sis/geometry/Shapes2D.java
index ed6d594bf1..31b37d4f20 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/geometry/Shapes2D.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/geometry/Shapes2D.java
@@ -22,6 +22,8 @@ import java.awt.geom.Line2D;
 import java.awt.geom.Ellipse2D;
 import java.awt.geom.Rectangle2D;
 import java.awt.geom.AffineTransform;
+import java.awt.geom.RectangularShape;
+import org.opengis.geometry.Envelope;
 import org.opengis.referencing.cs.CoordinateSystem;
 import org.opengis.referencing.cs.CoordinateSystemAxis;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
@@ -49,7 +51,7 @@ import org.apache.sis.util.Static;
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @author  Johann Sorel (Geomatys)
- * @version 1.1
+ * @version 1.3
  * @since   0.8
  * @module
  */
@@ -148,6 +150,24 @@ public final class Shapes2D extends Static {
                                     2*radius, 2*radius);
     }
 
+    /**
+     * Sets the given shape to the intersection of that shape with the given 
envelope.
+     *
+     * @param  shape     the shape to intersect. Will be modified in-place.
+     * @param  envelope  the envelope to intersect with the given shape.
+     * @param  xdim      dimension of <var>x</var> coordinates in the 
envelope. This is usually 0.
+     * @param  ydim      dimension of <var>y</var> coordinates in the 
envelope. This is usually 1.
+     *
+     * @since 1.3
+     */
+    public static void intersect(final RectangularShape shape, final Envelope 
envelope, final int xdim, final int ydim) {
+        final double xmin = Math.max(shape.getMinX(), 
envelope.getMinimum(xdim));
+        final double ymin = Math.max(shape.getMinY(), 
envelope.getMinimum(ydim));
+        final double xmax = Math.min(shape.getMaxX(), 
envelope.getMaximum(xdim));
+        final double ymax = Math.min(shape.getMaxY(), 
envelope.getMaximum(ydim));
+        shape.setFrame(xmin, ymin, xmax - xmin, ymax - ymin);
+    }
+
     /**
      * Transforms a rectangular envelope using the given math transform.
      * The transformation is only approximated: the returned envelope may be 
bigger than

Reply via email to