sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1750660 - in /sis/branches/JDK8/core/sis-referencing/src: main/java/org/apache/sis/geometry/ main/java/org/apache/sis/internal/referencing/j2d/ test/java/org/apache/sis/geometry/ test/java/org/apache/sis/referencing/operation/transform/ te...
Date Wed, 29 Jun 2016 15:08:34 GMT
Author: desruisseaux
Date: Wed Jun 29 15:08:34 2016
New Revision: 1750660

URL: http://svn.apache.org/viewvc?rev=1750660&view=rev
Log:
Ported Shapes2D class and test methods from Geotk.

Added:
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Shapes2D.java   (with props)
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/Shapes2DTest.java   (with props)
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/TransformTestCase.java   (with props)
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformWrapper.java   (with props)
Modified:
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractDirectPosition.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition2D.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelope2D.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelopes.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/package-info.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ShapeUtilities.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/EnvelopesTest.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractDirectPosition.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractDirectPosition.java?rev=1750660&r1=1750659&r2=1750660&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractDirectPosition.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractDirectPosition.java [UTF-8] Wed Jun 29 15:08:34 2016
@@ -44,7 +44,7 @@ import java.util.Objects;
 
 
 /**
- * Base class for {@link DirectPosition} implementations.
+ * Default implementations of some {@code DirectPosition} methods, leaving the data storage to subclasses.
  * A direct position holds the coordinates for a position within some
  * {@linkplain org.apache.sis.referencing.crs.AbstractCRS coordinate reference system}.
  * This base class provides default implementations for {@link #toString()},

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java?rev=1750660&r1=1750659&r2=1750660&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java [UTF-8] Wed Jun 29 15:08:34 2016
@@ -53,7 +53,7 @@ import java.util.Objects;
 
 
 /**
- * Base class for {@link Envelope} implementations.
+ * Default implementations of most {@code Envelope} methods, leaving the data storage to subclasses.
  * This base class does not hold any state and does not implement the {@link java.io.Serializable}
  * or {@link Cloneable} interfaces. The internal representation, and the choice to be cloneable or
  * serializable, is left to subclasses.

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition2D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition2D.java?rev=1750660&r1=1750659&r2=1750660&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition2D.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition2D.java [UTF-8] Wed Jun 29 15:08:34 2016
@@ -33,7 +33,7 @@ import java.util.Objects;
 
 
 /**
- * A two-dimensional position on top of {@link Point2D}.
+ * A two-dimensional position on top of Java2D point.
  * This implementation is provided for inter-operability between Java2D and GeoAPI.
  *
  * <p>This class inherits {@linkplain #x x} and {@linkplain #y y} fields.

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelope2D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelope2D.java?rev=1750660&r1=1750659&r2=1750660&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelope2D.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelope2D.java [UTF-8] Wed Jun 29 15:08:34 2016
@@ -54,7 +54,7 @@ import java.util.Objects;
 
 
 /**
- * A two-dimensional envelope on top of {@link Rectangle2D}.
+ * A two-dimensional envelope on top of Java2D rectangle.
  * This implementation is provided for inter-operability between Java2D and GeoAPI.
  *
  * <p>This class inherits {@linkplain #x x} and {@linkplain #y y} fields.

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelopes.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelopes.java?rev=1750660&r1=1750659&r2=1750660&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelopes.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelopes.java [UTF-8] Wed Jun 29 15:08:34 2016
@@ -103,7 +103,7 @@ public final class Envelopes extends Sta
     /**
      * Returns {@code true} if the given axis is of kind "Wrap Around".
      */
-    private static boolean isWrapAround(final CoordinateSystemAxis axis) {
+    static boolean isWrapAround(final CoordinateSystemAxis axis) {
         return RangeMeaning.WRAPAROUND.equals(axis.getRangeMeaning());
     }
 
@@ -111,8 +111,8 @@ public final class Envelopes extends Sta
      * Invoked when a recoverable exception occurred. Those exceptions must be minor enough
      * that they can be silently ignored in most cases.
      */
-    private static void recoverableException(final TransformException exception) {
-        Logging.recoverableException(Logging.getLogger(Loggers.GEOMETRY), Envelopes.class, "transform", exception);
+    static void recoverableException(final Class<? extends Static> caller, final TransformException exception) {
+        Logging.recoverableException(Logging.getLogger(Loggers.GEOMETRY), caller, "transform", exception);
     }
 
     /**
@@ -129,7 +129,7 @@ public final class Envelopes extends Sta
      * @throws TransformException If the point can not be transformed
      *         or if a problem occurred while calculating the derivative.
      */
-    private static Matrix derivativeAndTransform(final MathTransform transform, final double[] srcPts,
+    static Matrix derivativeAndTransform(final MathTransform transform, final double[] srcPts,
             final double[] dstPts, final int dstOff, final boolean derivate) throws TransformException
     {
         if (transform instanceof AbstractMathTransform) {
@@ -296,7 +296,7 @@ public final class Envelopes extends Sta
                 }
                 isDerivativeSupported = false;
                 transform.transform(sourcePt, 0, ordinates, offset, 1);
-                recoverableException(e);        // Log only if the above call was successful.
+                recoverableException(Envelopes.class, e);       // Log only if the above call was successful.
             }
             /*
              * The transformed point has been saved for future reuse after the enclosing
@@ -554,7 +554,7 @@ public final class Envelopes extends Sta
          *    step. That ordinate is set to the minimal and maximal values of that axis.
          *
          *    Example: If the above steps found that the point (90°S, 30°W) need to be included,
-         *             then this step #3 will also test phe points (90°S, 180°W) and (90°S, 180°E).
+         *             then this step #3 will also test the points (90°S, 180°W) and (90°S, 180°E).
          *
          * NOTE: we test (-180°, centerY), (180°, centerY), (centerX, -90°) and (centerX, 90°)
          * at step #1 before to test (-180°, -90°), (180°, -90°), (-180°, 90°) and (180°, 90°)
@@ -604,7 +604,7 @@ public final class Envelopes extends Sta
                          * lost dimensions. So we don't log any warning in this case.
                          */
                         if (dimension >= mt.getSourceDimensions()) {
-                            recoverableException(exception);
+                            recoverableException(Envelopes.class, exception);
                         }
                         return transformed;
                     }
@@ -720,7 +720,7 @@ public final class Envelopes extends Sta
             }
         }
         if (warning != null) {
-            recoverableException(warning);
+            recoverableException(Envelopes.class, warning);
         }
         return transformed;
     }

Added: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Shapes2D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Shapes2D.java?rev=1750660&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Shapes2D.java (added)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Shapes2D.java [UTF-8] Wed Jun 29 15:08:34 2016
@@ -0,0 +1,576 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.geometry;
+
+import java.awt.geom.Point2D;
+import java.awt.geom.Line2D;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.AffineTransform;
+import org.opengis.geometry.MismatchedDimensionException;
+import org.opengis.referencing.cs.CoordinateSystem;
+import org.opengis.referencing.cs.CoordinateSystemAxis;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.CoordinateOperation;
+import org.opengis.referencing.operation.Matrix;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.MathTransform2D;
+import org.opengis.referencing.operation.NoninvertibleTransformException;
+import org.opengis.referencing.operation.TransformException;
+import org.apache.sis.internal.referencing.j2d.ShapeUtilities;
+import org.apache.sis.referencing.operation.matrix.AffineTransforms2D;
+import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.Static;
+
+
+/**
+ * Utility methods working on Java2D shapes.
+ * The {@code transform(…)} methods in this class work in the same way than the methods of the same signature
+ * in {@link Envelopes}, except that they work on {@link Rectangle2D} objects instead than {@code Envelope}.
+ * In particular, the same treatment for curvatures and poles is applied.
+ *
+ * @author  Martin Desruisseaux (IRD, Geomatys)
+ * @author  Johann Sorel (Geomatys)
+ * @since   0.8
+ * @version 0.8
+ * @module
+ */
+public final class Shapes2D extends Static {
+    /**
+     * Do not allow instantiation of this class.
+     */
+    private Shapes2D() {
+    }
+
+    /**
+     * Returns the intersection point between two line segments. The lines do not continue to infinity;
+     * if the intersection does not occur between the ending points {@linkplain Line2D#getP1() P1} and
+     * {@linkplain Line2D#getP2() P2} of the two line segments, then this method returns {@code null}.
+     *
+     * @param  a the first line segment.
+     * @param  b the second line segment.
+     * @return the intersection point, or {@code null} if none.
+     */
+    public static Point2D intersectionPoint(final Line2D a, final Line2D b) {
+        return ShapeUtilities.intersectionPoint(a.getX1(), a.getY1(), a.getX2(), a.getY2(),
+                                                b.getX1(), b.getY1(), b.getX2(), b.getY2());
+    }
+
+    /**
+     * Returns the point on the given {@code line} segment which is closest to the given {@code point}.
+     * Let {@code result} be the returned point. This method guarantees (except for rounding errors) that:
+     *
+     * <ul>
+     *   <li>{@code result} is a point on the {@code line} segment. It is located between
+     *       the {@linkplain Line2D#getP1() P1} and {@linkplain Line2D#getP2() P2} ending
+     *       points of that line segment.</li>
+     *   <li>The distance between the {@code result} point and the given {@code point} is
+     *       the shortest distance among the set of points meeting the previous condition.
+     *       This distance can be obtained with {@code point.distance(result)}.</li>
+     * </ul>
+     *
+     * @param  segment  the line on which to search for a point.
+     * @param  point    a point close to the given line.
+     * @return the nearest point on the given line.
+     *
+     * @see #colinearPoint(Line2D, Point2D, double)
+     */
+    public static Point2D nearestColinearPoint(final Line2D segment, final Point2D point) {
+        return ShapeUtilities.nearestColinearPoint(segment.getX1(), segment.getY1(),
+                                                   segment.getX2(), segment.getY2(),
+                                                     point.getX(),    point.getY());
+    }
+
+    /**
+     * Returns a point on the given {@code line} segment located at the given {@code distance} from that line.
+     * Let {@code result} be the returned point. If {@code result} is not null, then this method guarantees
+     * (except for rounding error) that:
+     *
+     * <ul>
+     *   <li>{@code result} is a point on the {@code line} segment. It is located between
+     *       the {@linkplain Line2D#getP1() P1} and {@linkplain Line2D#getP2() P2} ending
+     *       points of that line segment.</li>
+     *   <li>The distance between the {@code result} and the given {@code point} is exactly
+     *       equal to {@code distance}.</li>
+     * </ul>
+     *
+     * If no result point meets those conditions, then this method returns {@code null}.
+     * If two result points meet those conditions, then this method returns the point
+     * which is the closest to {@code line.getP1()}.
+     *
+     * @param  line      the line on which to search for a point.
+     * @param  point     a point close to the given line.
+     * @param  distance  the distance between the given point and the point to be returned.
+     * @return a point on the given line located at the given distance from the given point.
+     *
+     * @see #nearestColinearPoint(Line2D, Point2D)
+     */
+    public static Point2D colinearPoint(Line2D line, Point2D point, double distance) {
+        return ShapeUtilities.colinearPoint(line.getX1(), line.getY1(),
+                                            line.getX2(), line.getY2(),
+                                            point.getX(), point.getY(),
+                                            distance);
+    }
+
+    /**
+     * Returns a circle passing by the 3 given points.
+     *
+     * @param  P1 the first point.
+     * @param  P2 the second point.
+     * @param  P3 the third point.
+     * @return a circle passing by the given points.
+     */
+    public static Ellipse2D circle(final Point2D P1, final Point2D P2, final Point2D P3) {
+        final Point2D.Double center = ShapeUtilities.circleCentre(P1.getX(), P1.getY(),
+                                                                  P2.getX(), P2.getY(),
+                                                                  P3.getX(), P3.getY());
+        final double radius = center.distance(P2);
+        return new Ellipse2D.Double(center.x - radius,
+                                    center.y - radius,
+                                    2*radius, 2*radius);
+    }
+
+    /**
+     * Transforms a rectangular envelope using the given math transform.
+     * The transformation is only approximative: the returned envelope may be bigger than
+     * necessary, or smaller than required if the bounding box contains a pole.
+     *
+     * <p>Note that this method can not handle the case where the rectangle contains the North or South pole,
+     * or when it cross the ±180° longitude, because {@code MathTransform} does not carry sufficient informations.
+     * For a more robust rectangle transformation, use {@link #transform(CoordinateOperation, Rectangle2D, Rectangle2D)}
+     * instead.</p>
+     *
+     * @param  transform   the transform to use. Source and target dimension must be 2.
+     * @param  envelope    the rectangle to transform (may be {@code null}).
+     * @param  destination the destination rectangle (may be {@code envelope}).
+     *         If {@code null}, a new rectangle will be created and returned.
+     * @return {@code destination}, or a new rectangle if {@code destination} was non-null and {@code envelope} was null.
+     * @throws TransformException if a transform failed.
+     *
+     * @see #transform(CoordinateOperation, Rectangle2D, Rectangle2D)
+     * @see Envelopes#transform(MathTransform, Envelope)
+     */
+    public static Rectangle2D transform(final MathTransform2D transform,
+                                        final Rectangle2D     envelope,
+                                              Rectangle2D     destination)
+            throws TransformException
+    {
+        ArgumentChecks.ensureNonNull("transform", transform);
+        if (transform instanceof AffineTransform) {
+            // Common case implemented in a more efficient way (less points to transform).
+            return AffineTransforms2D.transform((AffineTransform) transform, envelope, destination);
+        }
+        return transform(transform, envelope, destination, new double[2]);
+    }
+
+    /**
+     * Implementation of {@link #transform(MathTransform2D, Rectangle2D, Rectangle2D)} with the
+     * opportunity to save the projected center coordinate. This method sets {@code point} to
+     * the center of the source envelope projected to the target CRS.
+     */
+    @SuppressWarnings("fallthrough")
+    private static Rectangle2D transform(final MathTransform2D transform,
+                                         final Rectangle2D     envelope,
+                                               Rectangle2D     destination,
+                                         final double[]        point)
+            throws TransformException
+    {
+        if (envelope == null) {
+            return null;
+        }
+        double xmin = Double.POSITIVE_INFINITY;
+        double ymin = Double.POSITIVE_INFINITY;
+        double xmax = Double.NEGATIVE_INFINITY;
+        double ymax = Double.NEGATIVE_INFINITY;
+        /*
+         * Notation (as if we were applying a map projection, but this is not necessarily the case):
+         *   - (λ,φ) are ordinate values before projection.
+         *   - (x,y) are ordinate values after projection.
+         *   - D[00|01|10|11] are the ∂x/∂λ, ∂x/∂φ, ∂y/∂λ and ∂y/∂φ derivatives respectively.
+         *   - Variables with indice 0 are for the very first point in iteration order.
+         *   - Variables with indice 1 are for the values of the previous iteration.
+         *   - Variables with indice 2 are for the current values in the iteration.
+         *   - P1-P2 form a line segment to be checked for curvature.
+         */
+        double x0=0, y0=0, λ0=0, φ0=0;
+        double x1=0, y1=0, λ1=0, φ1=0;
+        Matrix D0=null, D1=null, D2=null;
+        // x2 and y2 defined inside the loop.
+        boolean isDerivativeSupported = true;
+        final CurveExtremum extremum = new CurveExtremum();
+        for (int i=0; i<=8; i++) {
+            /*
+             * Iteration order (center must be last):
+             *
+             *   (6)────(5)────(4)
+             *    |             |
+             *   (7)    (8)    (3)
+             *    |             |
+             *   (0)────(1)────(2)
+             */
+            double λ2, φ2;
+            switch (i) {
+                case 0: case 6: case 7: λ2 = envelope.getMinX();    break;
+                case 1: case 5: case 8: λ2 = envelope.getCenterX(); break;
+                case 2: case 3: case 4: λ2 = envelope.getMaxX();    break;
+                default: throw new AssertionError(i);
+            }
+            switch (i) {
+                case 0: case 1: case 2: φ2 = envelope.getMinY();    break;
+                case 3: case 7: case 8: φ2 = envelope.getCenterY(); break;
+                case 4: case 5: case 6: φ2 = envelope.getMaxY();    break;
+                default: throw new AssertionError(i);
+            }
+            point[0] = λ2;
+            point[1] = φ2;
+            try {
+                D1 = D2;
+                D2 = Envelopes.derivativeAndTransform(transform, point, point, 0, isDerivativeSupported && i != 8);
+            } catch (TransformException e) {
+                if (!isDerivativeSupported) {
+                    throw e;                        // Derivative were already disabled, so something went wrong.
+                }
+                isDerivativeSupported = false; D2 = null;
+                point[0] = λ2;
+                point[1] = φ2;
+                transform.transform(point, 0, point, 0, 1);
+                Envelopes.recoverableException(Shapes2D.class, e);  // Log only if the above call was successful.
+            }
+            double x2 = point[0];
+            double y2 = point[1];
+            if (x2 < xmin) xmin = x2;
+            if (x2 > xmax) xmax = x2;
+            if (y2 < ymin) ymin = y2;
+            if (y2 > ymax) ymax = y2;
+            switch (i) {
+                case 0: {                           // Remember the first point.
+                    λ0=λ2; x0=x2;
+                    φ0=φ2; y0=y2;
+                    D0=D2;
+                    break;
+                }
+                case 8: {                           // Close the iteration with the first point.
+                    λ2=λ0; x2=x0;                   // Discard P2 because it is the rectangle center.
+                    φ2=φ0; y2=y0;
+                    D2=D0;
+                    break;
+                }
+            }
+            /*
+             * At this point, we expanded the rectangle using the projected points. Now try
+             * to use the information provided by derivatives at those points, if available.
+             * For the following block, notation is:
+             *
+             *   - s  are ordinate values in the source space (λ or φ)
+             *   - t  are ordinate values in the target space (x or y)
+             *
+             * They are not necessarily in the same dimension. For example would could have
+             * s=λ while t=y. This is typically the case when inspecting the top or bottom
+             * line segment of the rectangle.
+             *
+             * The same technic is also applied in the transform(MathTransform, Envelope) method.
+             * The general method is more "elegant", at the cost of more storage requirement.
+             */
+            if (D1 != null && D2 != null) {
+                final int srcDim;
+                final double s1, s2;                // Ordinate values in source space (before projection)
+                switch (i) {
+                    case 1: case 2: case 5: case 6: {assert φ2==φ1; srcDim=0; s1=λ1; s2=λ2; break;}     // Horizontal segment
+                    case 3: case 4: case 7: case 8: {assert λ2==λ1; srcDim=1; s1=φ1; s2=φ2; break;}     // Vertical segment
+                    default: throw new AssertionError(i);
+                }
+                final double min, max;
+                if (s1 < s2) {min=s1; max=s2;}
+                else         {min=s2; max=s1;}
+                int tgtDim = 0;
+                do { // Executed exactly twice, for dimensions 0 and 1 in the projected space.
+                    extremum.resolve(s1, (tgtDim == 0) ? x1 : y1, D1.getElement(tgtDim, srcDim),
+                                     s2, (tgtDim == 0) ? x2 : y2, D2.getElement(tgtDim, srcDim));
+                    /*
+                     * At this point we found the extremum of the projected line segment
+                     * using a cubic curve t = A + Bs + Cs² + Ds³ approximation.  Before
+                     * to add those extremum into the projected bounding box, we need to
+                     * ensure that the source ordinate is inside the the original
+                     * (unprojected) bounding box.
+                     */
+                    boolean isP2 = false;
+                    do { // Executed exactly twice, one for each point.
+                        final double se = isP2 ? extremum.ex2 : extremum.ex1;
+                        if (se > min && se < max) {
+                            final double te = isP2 ? extremum.ey2 : extremum.ey1;
+                            if ((tgtDim == 0) ? (te < xmin || te > xmax) : (te < ymin || te > ymax)) {
+                                /*
+                                 * At this point, we have determined that adding the extremum point
+                                 * to the rectangle would have expanded it. However we will not add
+                                 * that point directly, because maybe its position is not quite right
+                                 * (since we used a cubic curve approximation). Instead, we project
+                                 * the point on the rectangle border which is located vis-à-vis the
+                                 * extremum. Our tests show that the correction can be as much as 50
+                                 * metres.
+                                 */
+                                final double oldX = point[0];
+                                final double oldY = point[1];
+                                if (srcDim == 0) {
+                                    point[0] = se;
+                                    point[1] = φ1; // == φ2 since we have an horizontal segment.
+                                } else {
+                                    point[0] = λ1; // == λ2 since we have a vertical segment.
+                                    point[1] = se;
+                                }
+                                transform.transform(point, 0, point, 0, 1);
+                                final double x = point[0];
+                                final double y = point[1];
+                                if (x < xmin) xmin = x;
+                                if (x > xmax) xmax = x;
+                                if (y < ymin) ymin = y;
+                                if (y > ymax) ymax = y;
+                                point[0] = oldX;
+                                point[1] = oldY;
+                            }
+                        }
+                    } while ((isP2 = !isP2) == true);
+                } while (++tgtDim == 1);
+            }
+            λ1=λ2; x1=x2;
+            φ1=φ2; y1=y2;
+            D1=D2;
+        }
+        if (destination != null) {
+            destination.setRect(xmin, ymin, xmax-xmin, ymax-ymin);
+        } else {
+            destination = new Rectangle2D.Double(xmin, ymin, xmax - xmin, ymax - ymin);
+        }
+        /*
+         * Note: a previous version had an "assert" statement here comparing our calculation
+         * with the calculation performed by the more general method working on Envelope. We
+         * verified that the same values (coordinate points and derivatives) were ultimately
+         * passed to the CurveExtremum.resolve(…) method, so we would expect the same result.
+         * However the iteration order is different. The result seems insensitive to iteration
+         * order most of the time, but not always. However, it seems that the cases were the
+         * results are different are the cases where the methods working with CoordinateOperation
+         * object wipe out that difference anyway.
+         */
+        return destination;
+    }
+
+    /**
+     * Transforms a rectangular envelope using the given coordinate operation.
+     * The transformation is only approximative: the returned envelope may be bigger
+     * than the smallest possible bounding box, but should not be smaller in most cases.
+     *
+     * <p>This method can handle the case where the rectangle contains the North or South pole,
+     * or when it cross the ±180° longitude.</p>
+     *
+     * @param  operation    the operation to use. Source and target dimension must be 2.
+     * @param  envelope     the rectangle to transform (may be {@code null}).
+     * @param  destination  the destination rectangle (may be {@code envelope}).
+     *         If {@code null}, a new rectangle will be created and returned.
+     * @return {@code destination}, or a new rectangle if {@code destination} was non-null and {@code envelope} was null.
+     * @throws TransformException if a transform failed.
+     *
+     * @see #transform(MathTransform2D, Rectangle2D, Rectangle2D)
+     * @see Envelopes#transform(CoordinateOperation, Envelope)
+     */
+    public static Rectangle2D transform(final CoordinateOperation operation,
+                                        final Rectangle2D         envelope,
+                                              Rectangle2D         destination)
+            throws TransformException
+    {
+        ArgumentChecks.ensureNonNull("operation", operation);
+        if (envelope == null) {
+            return null;
+        }
+        final MathTransform transform = operation.getMathTransform();
+        if (!(transform instanceof MathTransform2D)) {
+            throw new MismatchedDimensionException(Errors.format(Errors.Keys.IllegalPropertyValueClass_3,
+                    "transform", MathTransform2D.class, MathTransform.class));
+        }
+        MathTransform2D mt = (MathTransform2D) transform;
+        final double[] center = new double[2];
+        destination = transform(mt, envelope, destination, center);
+        /*
+         * If the source envelope crosses the expected range of valid coordinates, also projects
+         * the range bounds as a safety. See the comments in transform(Envelope, ...).
+         */
+        final CoordinateReferenceSystem sourceCRS = operation.getSourceCRS();
+        if (sourceCRS != null) {
+            final CoordinateSystem cs = sourceCRS.getCoordinateSystem();
+            if (cs != null && cs.getDimension() == 2) {                         // Paranoiac check.
+                CoordinateSystemAxis axis = cs.getAxis(0);
+                double min = envelope.getMinX();
+                double max = envelope.getMaxX();
+                Point2D.Double pt = null;
+                for (int i=0; i<4; i++) {
+                    if (i == 2) {
+                        axis = cs.getAxis(1);
+                        min = envelope.getMinY();
+                        max = envelope.getMaxY();
+                    }
+                    final double v = (i & 1) == 0 ? axis.getMinimumValue() : axis.getMaximumValue();
+                    if (!(v > min && v < max)) {
+                        continue;
+                    }
+                    if (pt == null) {
+                        pt = new Point2D.Double();
+                    }
+                    if ((i & 2) == 0) {
+                        pt.x = v;
+                        pt.y = envelope.getCenterY();
+                    } else {
+                        pt.x = envelope.getCenterX();
+                        pt.y = v;
+                    }
+                    destination.add(mt.transform(pt, pt));
+                }
+            }
+        }
+        /*
+         * Now take the target CRS in account.
+         */
+        final CoordinateReferenceSystem targetCRS = operation.getTargetCRS();
+        if (targetCRS == null) {
+            return destination;
+        }
+        final CoordinateSystem targetCS = targetCRS.getCoordinateSystem();
+        if (targetCS == null || targetCS.getDimension() != 2) {
+            // It should be an error, but we keep this method tolerant.
+            return destination;
+        }
+        /*
+         * Checks for singularity points. See the Envelopes.transform(CoordinateOperation, Envelope)
+         * method for comments about the algorithm. The code below is the same algorithm adapted for
+         * the 2D case and the related objects (Point2D, Rectangle2D, etc.).
+         *
+         * The 'border' variable in the loop below is used in order to compress 2 dimensions
+         * and 2 extremums in a single loop, in this order: (xmin, xmax, ymin, ymax).
+         */
+        TransformException warning = null;
+        Point2D sourcePt = null;
+        Point2D targetPt = null;
+        int includedBoundsValue = 0;                        // A bitmask for each (dimension, extremum) pairs.
+        for (int border=0; border<4; border++) {            // 2 dimensions and 2 extremums compacted in a flag.
+            final int dimension = border >>> 1;             // The dimension index being examined.
+            final CoordinateSystemAxis axis = targetCS.getAxis(dimension);
+            if (axis == null) {                             // Should never be null, but check as a paranoiac safety.
+                continue;
+            }
+            final double extremum = (border & 1) == 0 ? axis.getMinimumValue() : axis.getMaximumValue();
+            if (Double.isInfinite(extremum) || Double.isNaN(extremum)) {
+                continue;
+            }
+            if (targetPt == null) {
+                try {
+                    mt = mt.inverse();
+                } catch (NoninvertibleTransformException exception) {
+                    Envelopes.recoverableException(Shapes2D.class, exception);
+                    return destination;
+                }
+                targetPt = new Point2D.Double();
+            }
+            switch (dimension) {
+                case 0: targetPt.setLocation(extremum,  center[1]); break;
+                case 1: targetPt.setLocation(center[0], extremum ); break;
+                default: throw new AssertionError(border);
+            }
+            try {
+                sourcePt = mt.transform(targetPt, sourcePt);
+            } catch (TransformException exception) {
+                if (warning == null) {
+                    warning = exception;
+                } else {
+                    warning.addSuppressed(exception);
+                }
+                continue;
+            }
+            if (envelope.contains(sourcePt)) {
+                destination.add(targetPt);
+                includedBoundsValue |= (1 << border);
+            }
+        }
+        /*
+         * Iterate over all dimensions of type "WRAPAROUND" for which minimal or maximal axis
+         * values have not yet been included in the envelope. We could inline this check inside
+         * the above loop, but we don't in order to have a chance to exclude the dimensions for
+         * which the point have already been added.
+         *
+         * See transform(CoordinateOperation, Envelope) for more comments about the algorithm.
+         */
+        if (includedBoundsValue != 0) {
+            /*
+             * Bits mask transformation:
+             *   1) Swaps the two dimensions               (YyXx  →  XxYy)
+             *   2) Insert a space between each bits       (XxYy  →  X.x.Y.y.)
+             *   3) Fill the space with duplicated values  (X.x.Y.y.  →  XXxxYYyy)
+             *
+             * In terms of bit positions 1,2,4,8 (not bit values), we have:
+             *
+             *   8421  →  22881144
+             *   i.e. (ymax, ymin, xmax, xmin)  →  (xmax², ymax², xmin², ymin²)
+             *
+             * Now look at the last part: (xmin², ymin²). The next step is to perform a bitwise
+             * AND operation in order to have only both of the following conditions:
+             *
+             *   Borders not yet added to the envelope: ~(ymax, ymin, xmax, xmin)
+             *   Borders in which a singularity exists:  (xmin, xmin, ymin, ymin)
+             *
+             * The same operation is repeated on the next 4 bits for (xmax, xmax, ymax, ymax).
+             */
+            int toTest = ((includedBoundsValue & 1) << 3) | ((includedBoundsValue & 4) >>> 1) |
+                         ((includedBoundsValue & 2) << 6) | ((includedBoundsValue & 8) << 2);
+            toTest |= (toTest >>> 1); // Duplicate the bit values.
+            toTest &= ~(includedBoundsValue | (includedBoundsValue << 4));
+            /*
+             * Forget any axes that are not of kind "WRAPAROUND". Then get the final
+             * bit pattern indicating which points to test. Iterate over that bits.
+             */
+            if ((toTest & 0x33333333) != 0 && !Envelopes.isWrapAround(targetCS.getAxis(0))) toTest &= 0xCCCCCCCC;
+            if ((toTest & 0xCCCCCCCC) != 0 && !Envelopes.isWrapAround(targetCS.getAxis(1))) toTest &= 0x33333333;
+            while (toTest != 0) {
+                final int border = Integer.numberOfTrailingZeros(toTest);
+                final int bitMask = 1 << border;
+                toTest &= ~bitMask;                                 // Clear now the bit, for the next iteration.
+                final int dimensionToAdd = (border >>> 1) & 1;
+                final CoordinateSystemAxis toAdd = targetCS.getAxis(dimensionToAdd);
+                final CoordinateSystemAxis added = targetCS.getAxis(dimensionToAdd ^ 1);
+                double x = (border & 1) == 0 ? toAdd.getMinimumValue() : toAdd.getMaximumValue();
+                double y = (border & 4) == 0 ? added.getMinimumValue() : added.getMaximumValue();
+                if (dimensionToAdd != 0) {
+                    final double t=x; x=y; y=t;
+                }
+                targetPt.setLocation(x, y);
+                try {
+                    sourcePt = mt.transform(targetPt, sourcePt);
+                } catch (TransformException exception) {
+                    if (warning == null) {
+                        warning = exception;
+                    } else {
+                        warning.addSuppressed(exception);
+                    }
+                    continue;
+                }
+                if (envelope.contains(sourcePt)) {
+                    destination.add(targetPt);
+                }
+            }
+        }
+        if (warning != null) {
+            Envelopes.recoverableException(Shapes2D.class, warning);
+        }
+        return destination;
+    }
+}

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Shapes2D.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Shapes2D.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/package-info.java?rev=1750660&r1=1750659&r2=1750660&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/package-info.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/package-info.java [UTF-8] Wed Jun 29 15:08:34 2016
@@ -45,6 +45,12 @@
  *   </tr>
  * </table>
  *
+ * <div class="section">Java2D dependency</div>
+ * All classes having a name that ends with "2D" are designed for inter-operability with Java2D.
+ * All other classes have no dependency to Java2D.
+ * This clear separation aims to make easier to use Apache SIS on platforms that do not support Java2D
+ * (for example Android) or to avoid loading Java2D classes when only JavaFX is desired.
+ *
  * <div class="section">Envelopes spanning the anti-meridian of a Geographic CRS</div>
  * The Web Coverage Service (WCS) 1.1 specification uses an extended interpretation
  * of the bounding box definition. In a WCS 1.1 data structure, the
@@ -77,7 +83,7 @@
  *
  * @author Martin Desruisseaux (IRD, Geomatys)
  * @since   0.3
- * @version 0.3
+ * @version 0.8
  * @module
  */
 package org.apache.sis.geometry;

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ShapeUtilities.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ShapeUtilities.java?rev=1750660&r1=1750659&r2=1750660&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ShapeUtilities.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ShapeUtilities.java [UTF-8] Wed Jun 29 15:08:34 2016
@@ -63,9 +63,7 @@ public final class ShapeUtilities extend
      * @param  by2 <var>y</var> value of the last  point on the second line.
      * @return The intersection point, or {@code null} if none.
      *
-     * @todo This method is used by Geotk (a sandbox for code that may migrate to SIS), but not yet by SIS.
-     *       We temporarily keep this code here, but may delete or move it elsewhere in a future SIS version
-     *       depending whether we port to SIS the sandbox code.
+     * @see org.apache.sis.geometry.Shapes2D#intersectionPoint(Line2D, Line2D)
      */
     public static Point2D.Double intersectionPoint(final double ax1, final double ay1, double ax2, double ay2,
                                                    final double bx1, final double by1, double bx2, double by2)
@@ -118,9 +116,7 @@ public final class ShapeUtilities extend
      *
      * @see #colinearPoint(double,double , double,double , double,double , double)
      *
-     * @todo This method is used by Geotk (a sandbox for code that may migrate to SIS), but not yet by SIS.
-     *       We temporarily keep this code here, but may delete or move it elsewhere in a future SIS version
-     *       depending whether we port to SIS the sandbox code.
+     * @see org.apache.sis.geometry.Shapes2D#nearestColinearPoint(Line2D, Point2D)
      */
     public static Point2D.Double nearestColinearPoint(final double x1, final double y1,
                                                       final double x2, final double y2,
@@ -179,9 +175,7 @@ public final class ShapeUtilities extend
      *
      * @see #nearestColinearPoint(double,double , double,double , double,double)
      *
-     * @todo This method is used by Geotk (a sandbox for code that may migrate to SIS), but not yet by SIS.
-     *       We temporarily keep this code here, but may delete or move it elsewhere in a future SIS version
-     *       depending whether we port to SIS the sandbox code.
+     * @see org.apache.sis.geometry.Shapes2D#colinearPoint(Line2D, Point2D, double)
      */
     public static Point2D.Double colinearPoint(double x1, double y1, double x2, double y2,
                                                double x, double y, double distance)
@@ -323,10 +317,10 @@ public final class ShapeUtilities extend
         x2 -= x1;
         y2 -= y1;
         if (horizontal) {
-            final double a = (y2 - py*x2/px) / (x2-px); // Actually "a*x2"
+            final double a = (y2 - py*x2/px) / (x2-px);     // Actually "a*x2"
             final double check = abs(a);
-            if (!(check <= 1/EPS)) return null; // Two points have the same coordinates.
-            if (!(check >=   EPS)) return null; // The three points are co-linear.
+            if (!(check <= 1/EPS)) return null;             // Two points have the same coordinates.
+            if (!(check >=   EPS)) return null;             // The three points are co-linear.
             final double b = y2/x2 - a;
             px = (1 + b/(2*a))*x2 - y2/(2*a);
             py = y1 + b*px;
@@ -339,18 +333,18 @@ public final class ShapeUtilities extend
             final double rx2 = x2;
             final double ry2 = y2;
             x2 = hypot(x2,y2);
-            y2 = (px*rx2 + py*ry2) / x2; // use 'y2' as a temporary variable for 'x1'
+            y2 = (px*rx2 + py*ry2) / x2;                    // use 'y2' as a temporary variable for 'x1'
             py = (py*rx2 - px*ry2) / x2;
             px = y2;
-            y2 = 0; // set as a matter of principle (but not used).
+            y2 = 0;                                         // set as a matter of principle (but not used).
             /*
              * Now compute the control point coordinates in our new coordinate system axis.
              */
-            final double x = 0.5;                       // Actually "x/x2"
-            final double y = (py*x*x2) / (px*(x2-px));  // Actually "y/y2"
+            final double x = 0.5;                           // Actually "x/x2"
+            final double y = (py*x*x2) / (px*(x2-px));      // Actually "y/y2"
             final double check = abs(y);
-            if (!(check <= 1/EPS)) return null; // Two points have the same coordinates.
-            if (!(check >=   EPS)) return null; // The three points are co-linear.
+            if (!(check <= 1/EPS)) return null;             // Two points have the same coordinates.
+            if (!(check >=   EPS)) return null;             // The three points are co-linear.
             /*
              * Applies the inverse rotation then a translation to bring
              * us back to the original coordinate system.
@@ -362,7 +356,7 @@ public final class ShapeUtilities extend
     }
 
     /**
-     * Returns a circle passing by the 3 given points. The distance between the returned
+     * Returns the center of a circle passing by the 3 given points. The distance between the returned
      * point and any of the given points will be constant; it is the circle radius.
      *
      * @param  x1 <var>x</var> value of the first  point.
@@ -371,11 +365,9 @@ public final class ShapeUtilities extend
      * @param  y2 <var>y</var> value of the second point.
      * @param  x3 <var>x</var> value of the third  point.
      * @param  y3 <var>y</var> value of the third  point.
-     * @return A circle passing by the given points.
+     * @return The center of a circle passing by the given points.
      *
-     * @todo This method is used by Geotk (a sandbox for code that may migrate to SIS), but not yet by SIS.
-     *       We temporarily keep this code here, but may delete or move it elsewhere in a future SIS version
-     *       depending whether we port to SIS the sandbox code.
+     * @see org.apache.sis.geometry.Shapes2D#circle(Point2D, Point2D, Point2D)
      */
     public static Point2D.Double circleCentre(double x1, double y1,
                                               double x2, double y2,

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/EnvelopesTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/EnvelopesTest.java?rev=1750660&r1=1750659&r2=1750660&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/EnvelopesTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/EnvelopesTest.java [UTF-8] Wed Jun 29 15:08:34 2016
@@ -16,34 +16,87 @@
  */
 package org.apache.sis.geometry;
 
+import java.util.Collections;
 import org.opengis.geometry.Envelope;
 import org.opengis.util.FactoryException;
-import org.apache.sis.test.TestCase;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.CoordinateOperation;
+import org.opengis.referencing.operation.MathTransform2D;
+import org.opengis.referencing.operation.TransformException;
+import org.apache.sis.referencing.crs.DefaultCompoundCRS;
+import org.apache.sis.referencing.crs.HardCodedCRS;
+import org.apache.sis.referencing.operation.transform.MathTransformWrapper;
 import org.apache.sis.test.DependsOn;
 import org.junit.Test;
 
-import static org.apache.sis.test.Assert.*;
+import static org.apache.sis.test.ReferencingAssert.*;
 import static org.opengis.test.Validators.validate;
 
 
 /**
  * Tests the {@link Envelopes} class.
+ * This class inherits the test methods defined in {@link TransformTestCase}.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.3
- * @version 0.3
+ * @version 0.8
  * @module
  */
 @DependsOn({
     GeneralEnvelopeTest.class,
     CurveExtremumTest.class
 })
-public final strictfp class EnvelopesTest extends TestCase {
+public final strictfp class EnvelopesTest extends TransformTestCase<GeneralEnvelope> {
+    /**
+     * Creates an envelope for the given CRS and coordinate values.
+     */
+    @Override
+    GeneralEnvelope createFromExtremums(CoordinateReferenceSystem crs, double xmin, double ymin, double xmax, double ymax) {
+        final GeneralEnvelope env = new GeneralEnvelope(crs);
+        env.setRange(0, xmin, xmax);
+        env.setRange(1, ymin, ymax);
+        return env;
+    }
 
-    /*
-     * Tests of the 'transform' methods are not yet ported because they need more MathTransform
-     * implementations. Those tests will be ported in a future Apache SIS version.
+    /**
+     * Transforms an envelope using the given math transform.
+     * This transformation can not handle poles.
+     *
+     * <p>This method wraps the math transform into an opaque object for hiding the fact that the given
+     * transform implement the {@link MathTransform2D} interface. The intend is to disable optimization
+     * paths (if any), in order to test the generic path.</p>
      */
+    @Override
+    GeneralEnvelope transform(CoordinateReferenceSystem targetCRS, MathTransform2D transform, GeneralEnvelope envelope) throws TransformException {
+        final GeneralEnvelope env = Envelopes.transform(new MathTransformWrapper(transform), envelope);
+        env.setCoordinateReferenceSystem(targetCRS);
+        return env;
+    }
+
+    /**
+     * Transforms an envelope using the given operation.
+     * This transformation can handle poles.
+     */
+    @Override
+    GeneralEnvelope transform(CoordinateOperation operation, GeneralEnvelope envelope) throws TransformException {
+        return Envelopes.transform(operation, envelope);
+    }
+
+    /**
+     * Returns {@code true} if the outer envelope contains the inner one.
+     */
+    @Override
+    boolean contains(GeneralEnvelope outer, GeneralEnvelope inner) {
+        return outer.contains(inner);
+    }
+
+    /**
+     * Asserts that the given envelope is equals to the expected value.
+     */
+    @Override
+    void assertGeometryEquals(GeneralEnvelope expected, GeneralEnvelope actual, double tolx, double toly) {
+        assertEnvelopeEquals(expected, actual, tolx, toly);
+    }
 
     /**
      * Tests {@link Envelopes#fromWKT(CharSequence)}. This test is provided as a matter of principle,
@@ -83,4 +136,39 @@ public final strictfp class EnvelopesTes
         envelope.setRange(1, 20, 25);
         assertEquals("POLYGON((40 20, 40 25, 50 25, 50 20, 40 20))", Envelopes.toPolygonWKT(envelope));
     }
+
+    /**
+     * Tests the transformation of an envelope from a 4D CRS to a 2D CRS
+     * where the ordinates in one dimension are NaN.
+     *
+     * @throws TransformException if an error occurred while transforming the envelope.
+     *
+     * @since 0.8
+     */
+    @Test
+    public void testTransform4to2D() throws TransformException {
+        final CoordinateReferenceSystem targetCRS = HardCodedCRS.WGS84;
+        final CoordinateReferenceSystem sourceCRS = new DefaultCompoundCRS(
+                Collections.singletonMap(DefaultCompoundCRS.NAME_KEY, "4D CRS"),
+                HardCodedCRS.WGS84,
+                HardCodedCRS.GRAVITY_RELATED_HEIGHT,
+                HardCodedCRS.TIME);
+
+        final GeneralEnvelope env = new GeneralEnvelope(sourceCRS);
+        env.setRange(0, -170, 170);
+        env.setRange(1, -80,   80);
+        env.setRange(2, -50,  -50);
+        env.setRange(3, Double.NaN, Double.NaN);
+        assertFalse("isAllNaN", env.isAllNaN());        // Opportunist test (not really the topic of this method).
+        assertTrue ("isEmpty",  env.isEmpty());         // Opportunist test (not really the topic of this method).
+        /*
+         * If the referencing framework has selected the CopyTransform implementation
+         * as expected, then the envelope ordinates should not be NaN.
+         */
+        final Envelope env2D = Envelopes.transform(env, targetCRS);
+        assertEquals(-170, env2D.getMinimum(0), 0);
+        assertEquals( 170, env2D.getMaximum(0), 0);
+        assertEquals( -80, env2D.getMinimum(1), 0);
+        assertEquals(  80, env2D.getMaximum(1), 0);
+    }
 }

Added: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/Shapes2DTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/Shapes2DTest.java?rev=1750660&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/Shapes2DTest.java (added)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/Shapes2DTest.java [UTF-8] Wed Jun 29 15:08:34 2016
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.geometry;
+
+import java.awt.geom.Rectangle2D;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.CoordinateOperation;
+import org.opengis.referencing.operation.MathTransform2D;
+import org.opengis.referencing.operation.TransformException;
+import org.apache.sis.test.DependsOn;
+
+import static org.apache.sis.test.ReferencingAssert.*;
+
+
+/**
+ * Tests the {@link Shapes2D} class.
+ * This class inherits the test methods defined in {@link TransformTestCase}.
+ *
+ * @author  Martin Desruisseaux (IRD, Geomatys)
+ * @since   0.8
+ * @version 0.8
+ * @module
+ */
+@DependsOn(CurveExtremumTest.class)
+public final strictfp class Shapes2DTest extends TransformTestCase<Rectangle2D> {
+    /**
+     * Creates a rectangle for the given CRS and coordinate values.
+     */
+    @Override
+    Rectangle2D createFromExtremums(CoordinateReferenceSystem crs, double xmin, double ymin, double xmax, double ymax) {
+        return new Rectangle2D.Double(xmin, ymin, xmax - xmin, ymax - ymin);
+    }
+
+    /**
+     * Transforms a rectangle using the given math transform.
+     * This transformation can not handle poles.
+     */
+    @Override
+    Rectangle2D transform(CoordinateReferenceSystem targetCRS, MathTransform2D transform, Rectangle2D envelope) throws TransformException {
+        return Shapes2D.transform(transform, envelope, null);
+    }
+
+    /**
+     * Transforms a rectangle using the given operation.
+     * This transformation can handle poles.
+     */
+    @Override
+    Rectangle2D transform(CoordinateOperation operation, Rectangle2D envelope) throws TransformException {
+        return Shapes2D.transform(operation, envelope, null);
+    }
+
+    /**
+     * Returns {@code true} if the outer rectangle contains the inner one.
+     */
+    @Override
+    boolean contains(Rectangle2D outer, Rectangle2D inner) {
+        return outer.contains(inner);
+    }
+
+    /**
+     * Asserts that the given rectangle is equals to the expected value.
+     */
+    @Override
+    void assertGeometryEquals(Rectangle2D expected, Rectangle2D actual, double tolx, double toly) {
+        assertRectangleEquals(expected, actual, tolx, toly);
+    }
+}

Propchange: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/Shapes2DTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/Shapes2DTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Added: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/TransformTestCase.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/TransformTestCase.java?rev=1750660&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/TransformTestCase.java (added)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/TransformTestCase.java [UTF-8] Wed Jun 29 15:08:34 2016
@@ -0,0 +1,199 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.geometry;
+
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.crs.GeographicCRS;
+import org.opengis.referencing.crs.ProjectedCRS;
+import org.opengis.referencing.operation.Conversion;
+import org.opengis.referencing.operation.CoordinateOperation;
+import org.opengis.referencing.operation.MathTransform2D;
+import org.opengis.referencing.operation.NoninvertibleTransformException;
+import org.opengis.referencing.operation.TransformException;
+import org.opengis.util.FactoryException;
+import org.apache.sis.referencing.CRS;
+import org.apache.sis.referencing.CommonCRS;
+import org.apache.sis.referencing.IdentifiedObjects;
+import org.apache.sis.referencing.operation.DefaultConversion;
+import org.apache.sis.test.DependsOnMethod;
+import org.apache.sis.test.DependsOn;
+import org.apache.sis.test.TestCase;
+import org.junit.Test;
+
+import static org.apache.sis.internal.referencing.Formulas.ANGULAR_TOLERANCE;
+import static org.apache.sis.internal.referencing.Formulas.LINEAR_TOLERANCE;
+import static org.apache.sis.test.ReferencingAssert.*;
+
+
+/**
+ * Tests envelope transformations using either {@link Envelopes} or {@link Shapes2D} transform methods.
+ * This base class allows us to perform the same tests on both kind of objects.
+ * All tests performed by this class are two-dimensional.
+ *
+ * @param <G> the type of geometric objects, either {@link GeneralEnvelope} or {@link java.awt.geom.Rectangle2D}.
+ *
+ * @author  Martin Desruisseaux (IRD, Geomatys)
+ * @since   0.8
+ * @version 0.8
+ * @module
+ */
+@DependsOn(CurveExtremumTest.class)
+public abstract strictfp class TransformTestCase<G> extends TestCase {
+    /**
+     * Creates an envelope or rectangle for the given CRS and coordinate values.
+     */
+    abstract G createFromExtremums(CoordinateReferenceSystem crs, double xmin, double ymin, double xmax, double ymax);
+
+    /**
+     * Transforms an envelope or rectangle using the given math transform.
+     * This transformation can not handle poles.
+     */
+    abstract G transform(CoordinateReferenceSystem targetCRS, MathTransform2D transform, G envelope) throws TransformException;
+
+    /**
+     * Transforms an envelope or rectangle using the given operation.
+     * This transformation can handle poles.
+     */
+    abstract G transform(CoordinateOperation operation, G envelope) throws TransformException;
+
+    /**
+     * Returns {@code true} if the outer envelope or rectangle contains the inner one.
+     */
+    abstract boolean contains(G outer, G inner);
+
+    /**
+     * Asserts that the given envelope or rectangle is equals to the expected value.
+     */
+    abstract void assertGeometryEquals(G expected, G actual, double tolx, double toly);
+
+    /**
+     * Tests the transformation of an envelope or rectangle. This is a relatively simple test case
+     * working in the two-dimensional space only, with a coordinate operation of type "conversion"
+     * (not a "transformation") and with no need to adjust for poles.
+     *
+     * @throws FactoryException if an error occurred while creating the operation.
+     * @throws TransformException if an error occurred while transforming the envelope.
+     */
+    @Test
+    public final void testTransform() throws FactoryException, TransformException {
+        final ProjectedCRS    targetCRS  = CommonCRS.WGS84.UTM(10, -123.5);
+        final GeographicCRS   sourceCRS  = targetCRS.getBaseCRS();
+        final Conversion      conversion = targetCRS.getConversionFromBase();
+        final MathTransform2D transform  = (MathTransform2D) conversion.getMathTransform();
+        /*
+         * Transforms envelopes using MathTransform. Geographic coordinates are in (latitude, longitude) order.
+         * Opportunistically check that the transform using a CoordinateOperation object produces the same result.
+         */
+        final G rectλφ = createFromExtremums(sourceCRS, -20, -126, 40, -120);
+        final G rectXY = transform(targetCRS, transform, rectλφ);
+        assertEquals("Conversion should produce the same result.", rectXY, transform(conversion, rectλφ));
+        /*
+         * Expected values are determined empirically by projecting many points.
+         * Those values are the same than in EnvelopesTest.testTransform().
+         */
+        final G expected = createFromExtremums(targetCRS, 166021.56, -2214294.03,
+                                                          833978.44,  4432069.06);
+        assertGeometryEquals(expected, rectXY, LINEAR_TOLERANCE, LINEAR_TOLERANCE);
+        /*
+         * Test the inverse conversion.
+         * Final envelope should be slightly bigger than the original.
+         */
+        final G rectBack = transform(sourceCRS, transform.inverse(), rectXY);
+        assertTrue("Transformed envelope should not be smaller than the original one.", contains(rectBack, rectλφ));
+        assertGeometryEquals(rectλφ, rectBack, 0.05, 1.0);
+    }
+
+    /**
+     * Tests conversions of an envelope or rectangle over a pole using a coordinate operation.
+     *
+     * @throws FactoryException if an error occurred while creating the operation.
+     * @throws TransformException if an error occurred while transforming the envelope.
+     */
+    @Test
+    @DependsOnMethod("testTransform")
+    public final void testTransformOverPole() throws FactoryException, TransformException {
+        final ProjectedCRS sourceCRS = (ProjectedCRS) CRS.fromWKT(
+                "PROJCS[“WGS 84 / Antarctic Polar Stereographic”,\n" +
+                "  GEOGCS[“WGS 84”,\n" +
+                "    DATUM[“World Geodetic System 1984”,\n" +
+                "      SPHEROID[“WGS 84”, 6378137.0, 298.257223563]],\n" +
+                "    PRIMEM[“Greenwich”, 0.0],\n" +
+                "    UNIT[“degree”, 0.017453292519943295]],\n" +
+                "  PROJECTION[“Polar Stereographic (variant B)”],\n" +
+                "  PARAMETER[“standard_parallel_1”, -71.0],\n" +
+                "  UNIT[“m”, 1.0]]");
+        final GeographicCRS   targetCRS  = sourceCRS.getBaseCRS();
+        final Conversion      conversion = inverse(sourceCRS.getConversionFromBase());
+        final MathTransform2D transform  = (MathTransform2D) conversion.getMathTransform();
+        /*
+         * The rectangle to test, which contains the South pole.
+         */
+        G rectangle = createFromExtremums(sourceCRS,
+                -3943612.4042124213, -4078471.954436003,
+                 3729092.5890516187,  4033483.085688618);
+        /*
+         * This is what we get without special handling of singularity point.
+         * Note that is does not include the South pole as we would expect.
+         * The commented out values are what we get by projecting an arbitrary
+         * larger amount of points.
+         */
+        G expected = createFromExtremums(targetCRS,
+            //  -178.4935231040927  -56.61747883535035          // empirical values
+                -179.8650137390031, -88.99136583196396,         // anti-regression values
+            //   178.8122742080059  -40.90577500420587]         // empirical values
+                 137.9769431693009, -40.90577500420587);        // anti-regression values
+        /*
+         * Tests what we actually get. First, test using the method working on MathTransform.
+         * Next, test again the same transform, but using the API on Envelope objects.
+         */
+        G actual = transform(targetCRS, transform, rectangle);
+        assertGeometryEquals(expected, actual, ANGULAR_TOLERANCE, ANGULAR_TOLERANCE);
+        /*
+         * Using the transform(CoordinateOperation, …) method,
+         * the singularity at South pole is taken in account.
+         */
+        expected = createFromExtremums(targetCRS, -180, -90, 180, -40.905775004205864);
+        actual   = transform(conversion, rectangle);
+        assertGeometryEquals(expected, actual, ANGULAR_TOLERANCE, ANGULAR_TOLERANCE);
+        /*
+         * Another rectangle containing the South pole, but this time the south
+         * pole is almost in a corner of the rectangle
+         */
+        rectangle = createFromExtremums(sourceCRS, -4000000, -4000000, 300000, 30000);
+        expected  = createFromExtremums(targetCRS, -180, -90, 180, -41.03163170198091);
+        actual    = transform(conversion, rectangle);
+        assertGeometryEquals(expected, actual, ANGULAR_TOLERANCE, ANGULAR_TOLERANCE);
+        /*
+         * Another rectangle with the South pole close to the border.
+         * This test should execute the step #3 in the transform method code.
+         */
+        rectangle = createFromExtremums(sourceCRS, -2000000, -1000000, 200000, 2000000);
+        expected  = createFromExtremums(targetCRS, -180, -90, 180, -64.3861643256928);
+        actual    = transform(conversion, rectangle);
+        assertGeometryEquals(expected, actual, ANGULAR_TOLERANCE, ANGULAR_TOLERANCE);
+    }
+
+    /**
+     * Returns the inverse of the given conversion. This method is not strictly correct
+     * since we reuse the properties (name, aliases, etc.) from the given conversion.
+     * However those properties are not significant for the purpose of this test.
+     */
+    private static Conversion inverse(final Conversion conversion) throws NoninvertibleTransformException {
+        return new DefaultConversion(IdentifiedObjects.getProperties(conversion), conversion.getTargetCRS(),
+                conversion.getSourceCRS(), null, conversion.getMethod(), conversion.getMathTransform().inverse());
+    }
+}

Propchange: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/TransformTestCase.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/TransformTestCase.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Added: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformWrapper.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformWrapper.java?rev=1750660&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformWrapper.java (added)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformWrapper.java [UTF-8] Wed Jun 29 15:08:34 2016
@@ -0,0 +1,224 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.referencing.operation.transform;
+
+import java.io.Serializable;
+import org.opengis.referencing.operation.Matrix;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.NoninvertibleTransformException;
+import org.opengis.referencing.operation.TransformException;
+import org.opengis.geometry.MismatchedDimensionException;
+import org.opengis.geometry.DirectPosition;
+import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.io.wkt.Formatter;
+import org.apache.sis.io.wkt.FormattableObject;
+import org.apache.sis.io.wkt.UnformattableObjectException;
+
+// Branch-dependent imports
+import java.util.Objects;
+
+
+/**
+ * The base class of math transform wrappers. Despite being a concrete class, there is no point
+ * to instantiate directly this base class. Instantiate one of the subclasses instead.
+ *
+ * <strong>Do not implement {@code MathTransform2D} in this base class</strong>.
+ * This wrapper is sometime used for hiding the fact that a transform implements
+ * the {@code MathTransform2D} interface, typically for testing a different code
+ * path in a JUnit test.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.8
+ * @version 0.8
+ * @module
+ */
+public strictfp class MathTransformWrapper extends FormattableObject implements MathTransform, Serializable {
+    /**
+     * Serial number for inter-operability with different versions.
+     */
+    private static final long serialVersionUID = -5180954407422828265L;
+
+    /**
+     * The math transform on which to delegate the work.
+     */
+    public final MathTransform transform;
+
+    /**
+     * Creates a new wrapper which delegates its work to the specified math transform.
+     *
+     * @param transform the math transform on which to delegate the work.
+     */
+    public MathTransformWrapper(final MathTransform transform) {
+        ArgumentChecks.ensureNonNull("transform", transform);
+        this.transform = transform;
+    }
+
+    /**
+     * Gets the dimension of input points.
+     */
+    @Override
+    public final int getSourceDimensions() {
+        return transform.getTargetDimensions();
+    }
+
+    /**
+     * Gets the dimension of output points.
+     */
+    @Override
+    public final int getTargetDimensions() {
+        return transform.getSourceDimensions();
+    }
+
+    /**
+     * Transforms the specified {@code ptSrc} and stores the result in {@code ptDst}.
+     *
+     * @throws MismatchedDimensionException if {@code ptSrc} or
+     *         {@code ptDst} doesn't have the expected dimension.
+     * @throws TransformException if the point can not be transformed.
+     */
+    @Override
+    public final DirectPosition transform(final DirectPosition ptSrc, final DirectPosition ptDst)
+            throws MismatchedDimensionException, TransformException
+    {
+        return transform.transform(ptSrc, ptDst);
+    }
+
+    /**
+     * Transforms many coordinates in a list of ordinal values.
+     */
+    @Override
+    public final void transform(final double[] srcPts, final int srcOff,
+                                final double[] dstPts, final int dstOff,
+                                final int numPts) throws TransformException
+    {
+        transform.transform(srcPts, srcOff, dstPts, dstOff, numPts);
+    }
+
+    /**
+     * Transforms many coordinates in a list of ordinal values.
+     */
+    @Override
+    public final void transform(final float[] srcPts, final int srcOff,
+                                final float[] dstPts, final int dstOff,
+                                final int numPts) throws TransformException
+    {
+        transform.transform(srcPts, srcOff, dstPts, dstOff, numPts);
+    }
+
+    /**
+     * Transforms many coordinates in a list of ordinal values.
+     */
+    @Override
+    public final void transform(final float [] srcPts, final int srcOff,
+                                final double[] dstPts, final int dstOff,
+                                final int numPts) throws TransformException
+    {
+        transform.transform(srcPts, srcOff, dstPts, dstOff, numPts);
+    }
+
+    /**
+     * Transforms many coordinates in a list of ordinal values.
+     */
+    @Override
+    public final void transform(final double[] srcPts, final int srcOff,
+                                final float [] dstPts, final int dstOff,
+                                final int numPts) throws TransformException
+    {
+        transform.transform(srcPts, srcOff, dstPts, dstOff, numPts);
+    }
+
+    /**
+     * Gets the derivative of this transform at a point.
+     */
+    @Override
+    public final Matrix derivative(final DirectPosition point) throws TransformException {
+        return transform.derivative(point);
+    }
+
+    /**
+     * Returns the inverse of this math transform.
+     * The inverse is wrapped in a new {@code MathTransformWrapper} instance.
+     */
+    @Override
+    public MathTransform inverse() throws NoninvertibleTransformException {
+        return new MathTransformWrapper(transform.inverse());
+    }
+
+    /**
+     * Tests whether this transform does not move any points.
+     */
+    @Override
+    public final boolean isIdentity() {
+        return transform.isIdentity();
+    }
+
+    /**
+     * Compares the specified object with this math transform for equality.
+     *
+     * @param  object  the object to compare with this transform.
+     * @return {@code true} if the given object is of the same class and if the wrapped transforms are equal.
+     */
+    @Override
+    public final boolean equals(final Object object) {
+        if (object != null && object.getClass() == getClass()) {
+            final MathTransformWrapper that = (MathTransformWrapper) object;
+            return Objects.equals(this.transform, that.transform);
+        }
+        return false;
+    }
+
+    /**
+     * Returns a hash code value for this math transform.
+     */
+    @Override
+    public final int hashCode() {
+        return getClass().hashCode() ^ transform.hashCode() ^ (int) serialVersionUID;
+    }
+
+    /**
+     * Returns a <cite>Well Known Text</cite> (WKT) for this transform.
+     *
+     * @throws UnsupportedOperationException If this object can't be formatted as WKT.
+     */
+    @Override
+    public final String toWKT() throws UnsupportedOperationException {
+        return transform.toWKT();
+    }
+
+    /**
+     * Returns a string representation for this transform.
+     */
+    @Override
+    public final String toString() {
+        return transform.toString();
+    }
+
+    /**
+     * Delegates the WKT formatting to the wrapped math transform. This class is usually used
+     * with Apache SIS implementations of math transform, so the exception is unlikely to be thrown.
+     *
+     * @param  formatter the formatter to use.
+     * @return the WKT element name, which is {@code "Param_MT"} in the default implementation.
+     */
+    @Override
+    protected final String formatTo(final Formatter formatter) {
+        if (transform instanceof AbstractMathTransform) {
+            return ((AbstractMathTransform) transform).formatTo(formatter);
+        }
+        throw new UnformattableObjectException();
+    }
+}

Propchange: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformWrapper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformWrapper.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java?rev=1750660&r1=1750659&r2=1750660&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java [UTF-8] Wed Jun 29 15:08:34 2016
@@ -26,7 +26,7 @@ import org.junit.BeforeClass;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
- * @version 0.7
+ * @version 0.8
  * @module
  */
 @Suite.SuiteClasses({
@@ -233,6 +233,7 @@ import org.junit.BeforeClass;
     org.apache.sis.geometry.ImmutableEnvelopeTest.class,
     org.apache.sis.geometry.Envelope2DTest.class,
     org.apache.sis.geometry.CurveExtremumTest.class,
+    org.apache.sis.geometry.Shapes2DTest.class,                 // Simpler than EnvelopesTest.
     org.apache.sis.geometry.EnvelopesTest.class,
     org.apache.sis.internal.referencing.ServicesForMetadataTest.class,
 



Mime
View raw message