You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2015/01/07 12:18:03 UTC

svn commit: r1650035 - in /sis/branches/JDK8/core/sis-referencing/src: main/java/org/apache/sis/geometry/ main/java/org/apache/sis/geometry/doc-files/ main/java/org/apache/sis/internal/referencing/j2d/ test/java/org/apache/sis/geometry/ test/java/org/a...

Author: desruisseaux
Date: Wed Jan  7 11:18:03 2015
New Revision: 1650035

URL: http://svn.apache.org/r1650035
Log:
Avoid dependency to Java2D in the Envelopes class.
Added documentation and bug fix in ShapeUtilities.toPrimitive(Shape).

Added:
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/CurveExtremum.java
      - copied, changed from r1649878, sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ShapeUtilities.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/doc-files/ConicArea.png   (with props)
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/doc-files/GeographicArea.png   (with props)
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/CurveExtremumTest.java
      - copied, changed from r1650004, sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/j2d/ShapeUtilitiesTest.java
Modified:
    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/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/internal/referencing/j2d/ShapeUtilitiesTest.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java

Copied: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/CurveExtremum.java (from r1649878, 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/geometry/CurveExtremum.java?p2=sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/CurveExtremum.java&p1=sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ShapeUtilities.java&r1=1649878&r2=1650035&rev=1650035&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/geometry/CurveExtremum.java [UTF-8] Wed Jan  7 11:18:03 2015
@@ -14,392 +14,65 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.sis.internal.referencing.j2d;
-
-import java.awt.Shape;
-import java.awt.geom.Line2D;
-import java.awt.geom.Path2D;
-import java.awt.geom.Point2D;
-import java.awt.geom.QuadCurve2D;
-import java.awt.geom.CubicCurve2D;
-import java.awt.geom.PathIterator;
-import org.apache.sis.util.Static;
+package org.apache.sis.geometry;
 
 import static java.lang.Math.*;
 
 
 /**
- * Static methods operating on shapes from the {@link java.awt.geom} package.
+ * Finds the extremum of the unique cubic curve which fit the two given points and derivatives.
+ * First, this method finds the A, B, C and D coefficients for the following equation:
+ *
+ * <blockquote><var>y</var> = A + B<var>x</var> + C<var>x</var><sup>2</sup> + D<var>x</var><sup>3</sup></blockquote>
+ *
+ * Next, this method finds the extremum by finding the (<var>x</var>,<var>y</var>) values
+ * that satisfy the following equation (which is the derivative of the above equation):
+ *
+ * <blockquote>B + 2C<var>x</var> + 3D<var>x</var><sup>2</sup> = 0</blockquote>
+ *
+ * A cubic curve can have two extremum, which are stored in this object in no particular order.
+ * The distance separating the two extremum is sometime a useful information for determining if
+ * a quadratic equation would be a sufficient approximation.
  *
- * @author  Martin Desruisseaux (MPO, IRD, Geomatys)
- * @since   0.5 (derived from geotk-1.1)
+ * <p>The points stored in this object may contains {@linkplain Double#NaN NaN} values if the
+ * given geometry is actually a line segment ({@code dy1} = {@code dy2} = slope from P1 to P2).</p>
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.5
  * @version 0.5
  * @module
  */
-public final class ShapeUtilities extends Static {
-    /**
-     * Threshold value for determining whether two points are the same, or whether two lines are colinear.
-     */
-    private static final double EPS = 1E-6;
-
-    /**
-     * Do not allow instantiation of this class.
-     */
-    private ShapeUtilities() {
-    }
-
-    /**
-     * 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  ax1 <var>x</var> value of the first point on the first  line.
-     * @param  ay1 <var>y</var> value of the first point on the first  line.
-     * @param  ax2 <var>x</var> value of the last  point on the first  line.
-     * @param  ay2 <var>y</var> value of the last  point on the first  line.
-     * @param  bx1 <var>x</var> value of the first point on the second line.
-     * @param  by1 <var>y</var> value of the first point on the second line.
-     * @param  bx2 <var>x</var> value of the last  point on the second line.
-     * @param  by2 <var>y</var> value of the last  point on the second line.
-     * @return The intersection point, or {@code null} if none.
-     */
-    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)
-    {
-        ax2 -= ax1;
-        ay2 -= ay1;
-        bx2 -= bx1;
-        by2 -= by1;
-        double x = ay2 * bx2;
-        double y = ax2 * by2;
-        /*
-         * The above (x,y) coordinate is temporary. If and only if the two line are parallel, then x == y.
-         * Following code computes the real (x,y) coordinates of the intersection point.
-         */
-        x = ((by1-ay1) * (ax2*bx2) + x*ax1 - y*bx1) / (x-y);
-        y = abs(bx2) > abs(ax2) ?
-                (by2 / bx2) * (x - bx1) + by1 :
-                (ay2 / ax2) * (x - ax1) + ay1;
-        /*
-         * The '!=0' expressions below are important for avoiding rounding errors with
-         * horizontal or vertical lines. The '!' are important for handling NaN values.
-         */
-        if (ax2 != 0 && !(ax2 < 0 ? (x <= ax1 && x >= ax1 + ax2) : (x >= ax1 && x <= ax1 + ax2))) return null;
-        if (bx2 != 0 && !(bx2 < 0 ? (x <= bx1 && x >= bx1 + bx2) : (x >= bx1 && x <= bx1 + bx2))) return null;
-        if (ay2 != 0 && !(ay2 < 0 ? (y <= ay1 && y >= ay1 + ay2) : (y >= ay1 && y <= ay1 + ay2))) return null;
-        if (by2 != 0 && !(by2 < 0 ? (y <= by1 && y >= by1 + by2) : (y >= by1 && y <= by1 + by2))) return null;
-        return new Point2D.Double(x,y);
-    }
-
-    /**
-     * 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  x1 <var>x</var> value of the first point on the line.
-     * @param  y1 <var>y</var> value of the first point on the line.
-     * @param  x2 <var>x</var> value of the last  point on the line.
-     * @param  y2 <var>y</var> value of the last  point on the line.
-     * @param  x  <var>x</var> value of a point close to the given line.
-     * @param  y  <var>y</var> value of a point close to the given line.
-     * @return The nearest point on the given line.
-     *
-     * @see #colinearPoint(double,double , double,double , double,double , double)
-     */
-    public static Point2D.Double nearestColinearPoint(final double x1, final double y1,
-                                                      final double x2, final double y2,
-                                                            double x,        double y)
-    {
-        final double slope = (y2-y1) / (x2-x1);
-        if (!Double.isInfinite(slope)) {
-            final double y0 = (y2 - slope*x2);
-            x = ((y - y0) * slope + x) / (slope*slope + 1);
-            y = x*slope + y0;
-        } else {
-            x = x2;
-        }
-        if (x1 <= x2) {
-            if (x < x1) x = x1;
-            if (x > x2) x = x2;
-        } else {
-            if (x > x1) x = x1;
-            if (x < x2) x = x2;
-        }
-        if (y1 <= y2) {
-            if (y < y1) y = y1;
-            if (y > y2) y = y2;
-        } else {
-            if (y > y1) y = y1;
-            if (y < y2) y = y2;
-        }
-        return new Point2D.Double(x,y);
-    }
-
-    /**
-     * 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  x1 <var>x</var> value of the first point on the line.
-     * @param  y1 <var>y</var> value of the first point on the line.
-     * @param  x2 <var>x</var> value of the last  point on the line.
-     * @param  y2 <var>y</var> value of the last  point on the line.
-     * @param  x  <var>x</var> value of a point close to the given line.
-     * @param  y  <var>y</var> value of 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(double,double , double,double , double,double)
-     */
-    public static Point2D.Double colinearPoint(double x1, double y1, double x2, double y2,
-                                               double x, double y, double distance)
-    {
-        final double ox1 = x1;
-        final double oy1 = y1;
-        final double ox2 = x2;
-        final double oy2 = y2;
-        distance *= distance;
-        if (x1 == x2) {
-            double dy = x1 - x;
-            dy = sqrt(distance - dy*dy);
-            y1 = y - dy;
-            y2 = y + dy;
-        } else if (y1 == y2) {
-            double dx = y1 - y;
-            dx = sqrt(distance - dx*dx);
-            x1 = x - dx;
-            x2 = x + dx;
-        } else {
-            final double m  = (y1-y2) / (x2-x1);
-            final double y0 = (y2-y) + m*(x2-x);
-            final double B  = m * y0;
-            final double A  = m*m + 1;
-            final double C  = sqrt(B*B + A*(distance - y0*y0));
-            x1 = (B+C) / A;
-            x2 = (B-C) / A;
-            y1 = y + y0 - m*x1;
-            y2 = y + y0 - m*x2;
-            x1 += x;
-            x2 += x;
-        }
-        boolean in1, in2;
-        if (oy1 > oy2) {
-            in1 = (y1 <= oy1 && y1 >= oy2);
-            in2 = (y2 <= oy1 && y2 >= oy2);
-        } else {
-            in1 = (y1 >= oy1 && y1 <= oy2);
-            in2 = (y2 >= oy1 && y2 <= oy2);
-        }
-        if (ox1 > ox2) {
-            in1 &= (x1 <= ox1 && x1 >= ox2);
-            in2 &= (x2 <= ox1 && x2 >= ox2);
-        } else {
-            in1 &= (x1 >= ox1 && x1 <= ox2);
-            in2 &= (x2 >= ox1 && x2 <= ox2);
-        }
-        if (!in1 && !in2) return null;
-        if (!in1) return new Point2D.Double(x2,y2);
-        if (!in2) return new Point2D.Double(x1,y1);
-        x = x1 - ox1;
-        y = y1 - oy1;
-        final double d1 = x*x + y*y;
-        x = x2 - ox1;
-        y = y2 - oy1;
-        final double d2 = x*x + y*y;
-        if (d1 > d2) return new Point2D.Double(x2,y2);
-        else         return new Point2D.Double(x1,y1);
-    }
-
+final class CurveExtremum {
     /**
-     * Returns a quadratic curve passing by the 3 given points. There is an infinity of quadratic curves passing by
-     * 3 points. We can express the curve we are looking for as a parabolic equation of the form {@code y=ax²+bx+c}
-     * but where the <var>x</var> axis is not necessarily horizontal. The orientation of the <var>x</var> axis in
-     * the above equation is determined by the {@code horizontal} parameter:
-     *
-     * <ul>
-     *   <li>A value of {@code true} means that the <var>x</var> axis must be horizontal. The quadratic curve
-     *       will then look like an ordinary parabolic curve as we see in mathematic school book.</li>
-     *   <li>A value of {@code false} means that the <var>x</var> axis must be parallel to the
-     *       line segment joining the {@code P0} and {@code P2} ending points.</li>
-     * </ul>
-     *
-     * Note that if {@code P0.y == P2.y}, then both {@code horizontal} values produce the same result.
-     *
-     * @param  x0 <var>x</var> value of the starting point.
-     * @param  y0 <var>y</var> value of the starting point.
-     * @param  x1 <var>x</var> value of a passing point.
-     * @param  y1 <var>y</var> value of a passing point.
-     * @param  x2 <var>x</var> value of the ending point.
-     * @param  y2 <var>y</var> value of the ending point.
-     * @param  horizontal If {@code true}, the <var>x</var> axis is considered horizontal while computing the
-     *         {@code y=ax²+bx+c} equation terms. If {@code false}, it is considered parallel to the line
-     *         joining the {@code P0} and {@code P2} points.
-     * @return A quadratic curve passing by the given points. The curve starts at {@code P0} and ends at {@code P2}.
-     *         If two points are too close or if the three points are colinear, then this method returns {@code null}.
+     * Coordinate of the first extremum point (P1).
      */
-    public static QuadCurve2D.Double fitParabol(final double x0, final double y0,
-                                                final double x1, final double y1,
-                                                final double x2, final double y2,
-                                                final boolean horizontal)
-    {
-        final Point2D.Double p = parabolicControlPoint(x0, y0, x1, y1, x2, y2, horizontal);
-        return (p != null) ? new QuadCurve2D.Double(x0, y0, p.x, p.y, x2, y2) : null;
-    }
+    double ex1, ey1;
 
     /**
-     * Returns the control point of a quadratic curve passing by the 3 given points. There is an infinity of quadratic
-     * curves passing by 3 points. We can express the curve we are looking for as a parabolic equation of the form
-     * {@code y = ax²+bx+c}, but the <var>x</var> axis is not necessarily horizontal. The <var>x</var> axis orientation
-     * in the above equation is determined by the {@code horizontal} parameter:
-     *
-     * <ul>
-     *   <li>A value of {@code true} means that the <var>x</var> axis must be horizontal.
-     *       The quadratic curve will then look like an ordinary parabolic curve as we see
-     *       in mathematic school book.</li>
-     *   <li>A value of {@code false} means that the <var>x</var> axis must be parallel to the
-     *       line segment joining the {@code P0} and {@code P2} ending points.</li>
-     * </ul>
-     *
-     * Note that if {@code P0.y == P2.y}, then both {@code horizontal} values produce the same result.
-     *
-     * @param  x0 <var>x</var> value of the starting point.
-     * @param  y0 <var>y</var> value of the starting point.
-     * @param  x1 <var>x</var> value of a passing point.
-     * @param  y1 <var>y</var> value of a passing point.
-     * @param  x2 <var>x</var> value of the ending point.
-     * @param  y2 <var>y</var> value of the ending point.
-     * @param  horizontal If {@code true}, the <var>x</var> axis is considered horizontal while computing the
-     *         {@code y = ax²+bx+c} equation terms. If {@code false}, it is considered parallel to the line
-     *         joining the {@code P0} and {@code P2} points.
-     * @return The control point of a quadratic curve passing by the given points. The curve starts at {@code (x0,y0)}
-     *         and ends at {@code (x2,y2)}. If two points are too close or if the three points are colinear, then this
-     *         method returns {@code null}.
+     * Coordinate of the second extremum point (P2).
      */
-    public static Point2D.Double parabolicControlPoint(final double x0, final double y0,
-            double x1, double y1, double x2, double y2, final boolean horizontal)
-    {
-        /*
-         * Apply a translation in such a way that (x0,y0) become the coordinate system origin.
-         * After this translation, we shall not use (x0,y0) until we are done.
-         */
-        x1 -= x0;
-        y1 -= y0;
-        x2 -= x0;
-        y2 -= y0;
-        if (horizontal) {
-            final double a = (y2 - y1*x2/x1) / (x2-x1); // 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.
-            final double b = y2/x2 - a;
-            x1 = (1 + b/(2*a))*x2 - y2/(2*a);
-            y1 = y0 + b*x1;
-            x1 += x0;
-        } else {
-            /*
-             * Apply a rotation in such a way that (x2,y2)
-             * lies on the x axis, i.e. y2 = 0.
-             */
-            final double rx2 = x2;
-            final double ry2 = y2;
-            x2 = hypot(x2,y2);
-            y2 = (x1*rx2 + y1*ry2) / x2; // use 'y2' as a temporary variable for 'x1'
-            y1 = (y1*rx2 - x1*ry2) / x2;
-            x1 = y2;
-            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 = (y1*x*x2) / (x1*(x2-x1));  // 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.
-            /*
-             * Applies the inverse rotation then a translation to bring
-             * us back to the original coordinate system.
-             */
-            x1 = (x*rx2 - y*ry2) + x0;
-            y1 = (y*rx2 + x*ry2) + y0;
-        }
-        return new Point2D.Double(x1,y1);
-    }
+    double ex2, ey2;
 
     /**
-     * Returns 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.
-     * @param  y1 <var>y</var> value of the first  point.
-     * @param  x2 <var>x</var> value of the second point.
-     * @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.
+     * Creates a new object for computing curve extremum.
      */
-    public static Point2D.Double circleCentre(double x1, double y1,
-                                              double x2, double y2,
-                                              double x3, double y3)
-    {
-        x2 -= x1;
-        x3 -= x1;
-        y2 -= y1;
-        y3 -= y1;
-        final double sq2 = (x2*x2 + y2*y2);
-        final double sq3 = (x3*x3 + y3*y3);
-        final double x   = (y2*sq3 - y3*sq2) / (y2*x3 - y3*x2);
-        return new Point2D.Double(x1 + 0.5*x, y1 + 0.5*(sq2 - x*x2)/y2);
+    CurveExtremum() {
     }
 
     /**
      * Finds the extremum of the unique cubic curve which fit the two given points and derivatives.
-     * First, this method finds the A, B, C and D coefficients for the following equation:
-     *
-     * <blockquote><var>y</var> = A + B<var>x</var> + C<var>x</var><sup>2</sup> + D<var>x</var><sup>3</sup></blockquote>
-     *
-     * Next, this method finds the extremum by finding the (<var>x</var>,<var>y</var>) values
-     * that satisfy the following equation (which is the derivative of the above equation):
-     *
-     * <blockquote>B + 2C<var>x</var> + 3D<var>x</var><sup>2</sup> = 0</blockquote>
-     *
-     * A cubic curve can have two extremum, which are returned in a {@link Line2D} construct in
-     * no particular order. The length of the returned line is the distance separating the two
-     * extremum (often a useful information for determining if a quadratic equation would be a
-     * sufficient approximation).
-     *
-     * <p>The line returned by this method may contains {@linkplain Double#NaN NaN} values if the
-     * given geometry is actually a line segment ({@code dy1} = {@code dy2} = slope from P1 to P2).</p>
+     * See class javadoc for more information.
      *
      * @param  x1   The <var>x</var> ordinate of the first point.
      * @param  y1   The <var>y</var> ordinate of the first point.
-     * @param  dy1  The &part;<var>x</var>/&part;<var>y</var> value at the first point.
+     * @param  dy1  The ∂<var>x</var>/∂<var>y</var> value at the first point.
      * @param  x2   The <var>x</var> ordinate of the second point.
      * @param  y2   The <var>y</var> ordinate of the second point.
-     * @param  dy2  The &part;<var>x</var>/&part;<var>y</var> value at the second point.
+     * @param  dy2  The ∂<var>x</var>/∂<var>y</var> value at the second point.
      * @return The two points located on the extremum of the fitted cubic curve.
      */
-    public static Line2D.Double cubicCurveExtremum(double x1, double y1, final double dy1,
-                                                   double x2, double y2, final double dy2)
+    void resolve(double x1, double y1, final double dy1,
+                 double x2, double y2, final double dy2)
     {
         /*
          * Equation for a cubic curve is y = A + Bx + Cx² + Dx³.
@@ -417,47 +90,20 @@ public final class ShapeUtilities extend
         final double D = (2*w + d)     / x2;
         final double C = -3*w - d;
         /*
-         * For location the minimum, we search the location where the derivative is null:
+         * For locating the minimum, we search the location where the derivative is zero:
          *
          *    B + 2Cx + 3Dx² == 0    ⇒    x = (-b ± √(b² - 4ac)) / (2a)
          *
          * where, a = 3*D,  b = 2*C  and  c = B = dy1
          */
-        final double a  = 3*D;
-        final double b  = 2*C;
-        final double q  = -0.5*(b + copySign(sqrt(b*b - 4*a*dy1), b));
+        final double a  = 3 * D;
+        final double b  = 2 * C;
+        final double q  = -0.5 * (b + copySign(sqrt(b*b - 4*a*dy1), b));
         final double r1 = q / a;
         final double r2 = dy1 / q;
-        return new Line2D.Double(
-                x1 + r1, y1 + r1*(dy1 + r1*(C + r1*D)),
-                x1 + r2, y1 + r2*(dy1 + r2*(C + r2*D)));
-    }
-
-    /**
-     * Attempts to replace an arbitrary shape by one of the standard Java2D constructs.
-     * For example if the given {@code path} is a {@link Path2D} containing only a single
-     * line or a quadratic curve, then this method replaces it by a {@link Line2D} or
-     * {@link QuadCurve2D} object respectively.
-     *
-     * @param  path The shape to replace by a simpler Java2D construct.
-     *         This is generally an instance of {@link Path2D}, but not necessarily.
-     * @return A simpler Java construct, or {@code path} if no better construct is proposed.
-     */
-    public static Shape toPrimitive(final Shape path) {
-        final double[] buffer = new double[6];
-        final PathIterator it = path.getPathIterator(null);
-        if (!it.isDone() && it.currentSegment(buffer) == PathIterator.SEG_MOVETO && !it.isDone()) {
-            final double x1 = buffer[0];
-            final double y1 = buffer[1];
-            final int code = it.currentSegment(buffer);
-            if (it.isDone()) {
-                switch (code) {
-                    case PathIterator.SEG_LINETO:  return new       Line2D.Double(x1,y1, buffer[0], buffer[1]);
-                    case PathIterator.SEG_QUADTO:  return new  QuadCurve2D.Double(x1,y1, buffer[0], buffer[1], buffer[2], buffer[3]);
-                    case PathIterator.SEG_CUBICTO: return new CubicCurve2D.Double(x1,y1, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]);
-                }
-            }
-        }
-        return path;
+        ex1 = x1 + r1;
+        ex2 = x1 + r2;
+        ey1 = y1 + r1*(dy1 + r1*(C + r1*D));
+        ey2 = y1 + r2*(dy1 + r2*(C + r2*D));
     }
 }

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=1650035&r1=1650034&r2=1650035&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 Jan  7 11:18:03 2015
@@ -16,6 +16,11 @@
  */
 package org.apache.sis.geometry;
 
+/*
+ * Do not add dependency to java.awt.Rectangle2D in this class, because not every platforms
+ * support Java2D (e.g. Android),  or applications that do not need it may want to avoid to
+ * force installation of the Java2D module (e.g. JavaFX/SWT).
+ */
 import org.opengis.geometry.Envelope;
 import org.opengis.geometry.DirectPosition;
 import org.opengis.geometry.MismatchedDimensionException;
@@ -44,19 +49,38 @@ import org.apache.sis.internal.system.De
 import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
 import static org.apache.sis.util.StringBuilders.trimFractionalPart;
 
-/*
- * TODO: We would like to avoid java.awt.geom dependency in this class, because not every platforms
- * support Java2D (e.g. Android) or some applications (e.g. JavaFX or SWT) may want to avoid forcing
- * Java2D initialization. However we do not yet have an Apache SIS geometry module that we could use.
- * So we temporarily accept Java2D dependency, but should revisit this issue in a future SIS version.
- */
-import java.awt.geom.Line2D;
-import org.apache.sis.internal.referencing.j2d.ShapeUtilities;
-
 
 /**
- * Utility methods for envelopes. This utility class is made up of static functions working
- * with arbitrary implementations of GeoAPI interfaces.
+ * Transforms envelopes to new Coordinate Reference Systems, and miscellaneous utilities.
+ *
+ * {@section Envelope transformations}
+ * All {@code transform(…)} methods in this class take in account the curvature of the transformed shape.
+ * For example in order to get an envelope that fully encompass the shape shown below on the right side,
+ * projecting the four corners is not sufficient:
+ *
+ * <center><table>
+ *   <caption>Example of curvature induced by a map projection</caption>
+ *   <tr>
+ *     <th>Envelope before map projection</th>
+ *     <th>Shape of the projected envelope</th>
+ *   </tr><tr>
+ *     <td><img src="doc-files/GeographicArea.png" alt="Envelope in a geographic CRS"></td>
+ *     <td><img src="doc-files/ConicArea.png" alt="Shape of the envelope transformed in a conic projection"></td>
+ *   </tr>
+ * </table></center>
+ *
+ * The {@code transform(…)} methods expect an arbitrary {@link Envelope} with <strong>one</strong> of the following
+ * arguments: {@link MathTransform}, {@link CoordinateOperation} or {@link CoordinateReferenceSystem}.
+ * The recommended method is the one expecting a {@code CoordinateOperation} object,
+ * since it contains sufficient information for handling the cases of envelopes that encompass a pole.
+ * The method expecting a {@code CoordinateReferenceSystem} object is merely a convenience method that
+ * infers the {@code CoordinateOperation} itself, but at the cost of performance if the same operation
+ * needs to be applied on many envelopes.
+ *
+ * <p>While optional, it is strongly recommended that all {@code MathTransform} implementations involved
+ * in the operation (directly or indirectly) support the {@link MathTransform#derivative(DirectPosition)}
+ * operation, for more accurate calculation of curve extremum.
+ * This is the case of most Apache SIS implementations.</p>
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @author  Johann Sorel (Geomatys)
@@ -326,14 +350,15 @@ public final class Envelopes extends Sta
          */
         DirectPosition temporary = null;
         final DirectPositionView sourceView = new DirectPositionView(sourcePt, 0, sourceDim);
+        final CurveExtremum extremum = new CurveExtremum();
         for (pointIndex=0; pointIndex < derivatives.length; pointIndex++) {
             final Matrix D1 = derivatives[pointIndex];
             if (D1 != null) {
-                int indexBase3=pointIndex, power3=1;
+                int indexBase3 = pointIndex, power3 = 1;
                 for (int i=sourceDim; --i>=0; indexBase3 /= 3, power3 *= 3) {
                     final int digitBase3 = indexBase3 % 3;
                     if (digitBase3 != 2) { // Process only if we are not already located on the median along the dimension i.
-                        final int medianIndex = pointIndex + power3*(2-digitBase3);
+                        final int medianIndex = pointIndex + power3 * (2 - digitBase3);
                         final Matrix D2 = derivatives[medianIndex];
                         if (D2 != null) {
                             final double xmin = envelope.getMinimum(i);
@@ -343,14 +368,13 @@ public final class Envelopes extends Sta
                             final int offset1 = targetDim * pointIndex;
                             final int offset2 = targetDim * medianIndex;
                             for (int j=0; j<targetDim; j++) {
-                                final Line2D.Double extremum = ShapeUtilities.cubicCurveExtremum(
-                                        x1, ordinates[offset1 + j], D1.getElement(j,i),
-                                        x2, ordinates[offset2 + j], D2.getElement(j,i));
+                                extremum.resolve(x1, ordinates[offset1 + j], D1.getElement(j,i),
+                                                 x2, ordinates[offset2 + j], D2.getElement(j,i));
                                 boolean isP2 = false;
                                 do { // Executed exactly twice, one for each extremum point.
-                                    final double x = isP2 ? extremum.x2 : extremum.x1;
+                                    final double x = isP2 ? extremum.ex2 : extremum.ex1;
                                     if (x > xmin && x < xmax) {
-                                        final double y = isP2 ? extremum.y2 : extremum.y1;
+                                        final double y = isP2 ? extremum.ey2 : extremum.ey1;
                                         if (y < transformed.getMinimum(j) ||
                                             y > transformed.getMaximum(j))
                                         {

Added: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/doc-files/ConicArea.png
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/doc-files/ConicArea.png?rev=1650035&view=auto
==============================================================================
Binary file - no diff available.

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/doc-files/ConicArea.png
------------------------------------------------------------------------------
    svn:mime-type = image/png

Added: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/doc-files/GeographicArea.png
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/doc-files/GeographicArea.png?rev=1650035&view=auto
==============================================================================
Binary file - no diff available.

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/doc-files/GeographicArea.png
------------------------------------------------------------------------------
    svn:mime-type = image/png

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=1650035&r1=1650034&r2=1650035&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 Jan  7 11:18:03 2015
@@ -372,68 +372,6 @@ public final class ShapeUtilities extend
     }
 
     /**
-     * Finds the extremum of the unique cubic curve which fit the two given points and derivatives.
-     * First, this method finds the A, B, C and D coefficients for the following equation:
-     *
-     * <blockquote><var>y</var> = A + B<var>x</var> + C<var>x</var><sup>2</sup> + D<var>x</var><sup>3</sup></blockquote>
-     *
-     * Next, this method finds the extremum by finding the (<var>x</var>,<var>y</var>) values
-     * that satisfy the following equation (which is the derivative of the above equation):
-     *
-     * <blockquote>B + 2C<var>x</var> + 3D<var>x</var><sup>2</sup> = 0</blockquote>
-     *
-     * A cubic curve can have two extremum, which are returned in a {@link Line2D} construct in
-     * no particular order. The length of the returned line is the distance separating the two
-     * extremum (often a useful information for determining if a quadratic equation would be a
-     * sufficient approximation).
-     *
-     * <p>The line returned by this method may contains {@linkplain Double#NaN NaN} values if the
-     * given geometry is actually a line segment ({@code dy1} = {@code dy2} = slope from P1 to P2).</p>
-     *
-     * @param  x1   The <var>x</var> ordinate of the first point.
-     * @param  y1   The <var>y</var> ordinate of the first point.
-     * @param  dy1  The &part;<var>x</var>/&part;<var>y</var> value at the first point.
-     * @param  x2   The <var>x</var> ordinate of the second point.
-     * @param  y2   The <var>y</var> ordinate of the second point.
-     * @param  dy2  The &part;<var>x</var>/&part;<var>y</var> value at the second point.
-     * @return The two points located on the extremum of the fitted cubic curve.
-     */
-    public static Line2D.Double cubicCurveExtremum(double x1, double y1, final double dy1,
-                                                   double x2, double y2, final double dy2)
-    {
-        /*
-         * Equation for a cubic curve is y = A + Bx + Cx² + Dx³.
-         * Before to compute, translate the curve such that (x1,y1) = (0,0),
-         * which simplify a lot the equation. In such case:
-         *
-         *   A = 0
-         *   B = dy1
-         *   C and D: see code below.
-         */
-        x2 -= x1;
-        y2 -= y1;
-        final double d = (dy2 - dy1)   / x2;
-        final double w = (dy1 - y2/x2) / x2;
-        final double D = (2*w + d)     / x2;
-        final double C = -3*w - d;
-        /*
-         * For location the minimum, we search the location where the derivative is null:
-         *
-         *    B + 2Cx + 3Dx² == 0    ⇒    x = (-b ± √(b² - 4ac)) / (2a)
-         *
-         * where, a = 3*D,  b = 2*C  and  c = B = dy1
-         */
-        final double a  = 3*D;
-        final double b  = 2*C;
-        final double q  = -0.5*(b + copySign(sqrt(b*b - 4*a*dy1), b));
-        final double r1 = q / a;
-        final double r2 = dy1 / q;
-        return new Line2D.Double(
-                x1 + r1, y1 + r1*(dy1 + r1*(C + r1*D)),
-                x1 + r2, y1 + r2*(dy1 + r2*(C + r2*D)));
-    }
-
-    /**
      * Attempts to replace an arbitrary shape by one of the standard Java2D constructs.
      * For example if the given {@code path} is a {@link Path2D} containing only a single
      * line or a quadratic curve, then this method replaces it by a {@link Line2D} or
@@ -444,17 +382,23 @@ public final class ShapeUtilities extend
      * @return A simpler Java construct, or {@code path} if no better construct is proposed.
      */
     public static Shape toPrimitive(final Shape path) {
-        final double[] buffer = new double[6];
         final PathIterator it = path.getPathIterator(null);
-        if (!it.isDone() && it.currentSegment(buffer) == PathIterator.SEG_MOVETO && !it.isDone()) {
-            final double x1 = buffer[0];
-            final double y1 = buffer[1];
-            final int code = it.currentSegment(buffer);
-            if (it.isDone()) {
-                switch (code) {
-                    case PathIterator.SEG_LINETO:  return new       Line2D.Double(x1,y1, buffer[0], buffer[1]);
-                    case PathIterator.SEG_QUADTO:  return new  QuadCurve2D.Double(x1,y1, buffer[0], buffer[1], buffer[2], buffer[3]);
-                    case PathIterator.SEG_CUBICTO: return new CubicCurve2D.Double(x1,y1, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]);
+        if (!it.isDone()) {
+            final double[] buffer = new double[6];
+            if (it.currentSegment(buffer) == PathIterator.SEG_MOVETO) {
+                it.next();
+                if (!it.isDone()) {
+                    final double x1 = buffer[0];
+                    final double y1 = buffer[1];
+                    final int code = it.currentSegment(buffer);
+                    it.next();
+                    if (it.isDone()) {
+                        switch (code) {
+                            case PathIterator.SEG_LINETO:  return new       Line2D.Double(x1,y1, buffer[0], buffer[1]);
+                            case PathIterator.SEG_QUADTO:  return new  QuadCurve2D.Double(x1,y1, buffer[0], buffer[1], buffer[2], buffer[3]);
+                            case PathIterator.SEG_CUBICTO: return new CubicCurve2D.Double(x1,y1, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]);
+                        }
+                    }
                 }
             }
         }

Copied: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/CurveExtremumTest.java (from r1650004, sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/j2d/ShapeUtilitiesTest.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/CurveExtremumTest.java?p2=sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/CurveExtremumTest.java&p1=sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/j2d/ShapeUtilitiesTest.java&r1=1650004&r2=1650035&rev=1650035&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/j2d/ShapeUtilitiesTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/CurveExtremumTest.java [UTF-8] Wed Jan  7 11:18:03 2015
@@ -14,10 +14,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.sis.internal.referencing.j2d;
+package org.apache.sis.geometry;
 
-import java.awt.geom.Line2D;
-import java.awt.geom.Point2D;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
@@ -25,43 +23,42 @@ import static org.junit.Assert.*;
 
 
 /**
- * Tests the {@link ShapeUtilities} class.
+ * Tests the {@link CurveExtremum} class.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @since   0.5 (derived from geotk-3.20)
+ * @since   0.5
  * @version 0.5
  * @module
  */
-public final strictfp class ShapeUtilitiesTest extends TestCase {
+public final strictfp class CurveExtremumTest extends TestCase {
     /**
      * Tolerance factor for the tests in this class.
      */
     private static final double EPS = 1E-8;
 
     /**
-     * Tests {@link ShapeUtilities#cubicCurveExtremum(double, double, double, double, double, double)}.
+     * Tests {@link CurveExtremum#resolve(double, double, double, double, double, double)}.
      */
     @Test
-    public void testCubicCurveExtremum() {
-        final Point2D.Double P1 = new Point2D.Double();
-        final Point2D.Double P2 = new Point2D.Double();
-        double dy1, dy2;
-        Line2D extremums;
-
-        P1.x =  0; P1.y =  0; dy1 =   7;
-        P2.x = -4; P2.y =  0; dy2 = -12;
-        extremums = ShapeUtilities.cubicCurveExtremum(P1.x, P1.y, dy1, P2.x, P2.y, dy2);
-        assertEquals("X1",   3.31741507, extremums.getX1(), EPS);
-        assertEquals("Y1",  17.31547745, extremums.getY1(), EPS);
-        assertEquals("X2",  -2.25074840, extremums.getX2(), EPS);
-        assertEquals("Y2",  -9.65918115, extremums.getY2(), EPS);
-
-        P1.x = 0; P1.y =  0; dy1 = 5;
-        P2.x = 5; P2.y = 20; dy2 = 1;
-        extremums = ShapeUtilities.cubicCurveExtremum(P1.x, P1.y, dy1, P2.x, P2.y, dy2);
-        assertEquals("X1",   5.47313697, extremums.getX1(), EPS);
-        assertEquals("Y1",  20.24080512, extremums.getY1(), EPS);
-        assertEquals("X2",  -3.80647030, extremums.getX2(), EPS);
-        assertEquals("Y2", -11.72228660, extremums.getY2(), EPS);
+    public void testResolve() {
+        final CurveExtremum extremum = new CurveExtremum();
+        double x1, y1, dy1;
+        double x2, y2, dy2;
+
+        x1 =  0; y1 =  0; dy1 =   7;
+        x2 = -4; y2 =  0; dy2 = -12;
+        extremum.resolve(x1, y1, dy1, x2, y2, dy2);
+        assertEquals("X1",   3.31741507, extremum.ex1, EPS);
+        assertEquals("Y1",  17.31547745, extremum.ey1, EPS);
+        assertEquals("X2",  -2.25074840, extremum.ex2, EPS);
+        assertEquals("Y2",  -9.65918115, extremum.ey2, EPS);
+
+        x1 = 0; y1 =  0; dy1 = 5;
+        x2 = 5; y2 = 20; dy2 = 1;
+        extremum.resolve(x1, y1, dy1, x2, y2, dy2);
+        assertEquals("X1",   5.47313697, extremum.ex1, EPS);
+        assertEquals("Y1",  20.24080512, extremum.ey1, EPS);
+        assertEquals("X2",  -3.80647030, extremum.ex2, EPS);
+        assertEquals("Y2", -11.72228660, extremum.ey2, EPS);
     }
 }

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=1650035&r1=1650034&r2=1650035&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 Jan  7 11:18:03 2015
@@ -34,8 +34,17 @@ import static org.opengis.test.Validator
  * @version 0.3
  * @module
  */
-@DependsOn(GeneralEnvelopeTest.class)
+@DependsOn({
+    GeneralEnvelopeTest.class,
+    CurveExtremumTest.class
+})
 public final strictfp class EnvelopesTest extends TestCase {
+
+    /*
+     * 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.
+     */
+
     /**
      * Tests {@link Envelopes#fromWKT(CharSequence)}. This test is provided as a matter of principle,
      * but the real test is done by {@link GeneralEnvelopeTest#testWktParsing()}.

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/j2d/ShapeUtilitiesTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/j2d/ShapeUtilitiesTest.java?rev=1650035&r1=1650034&r2=1650035&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/j2d/ShapeUtilitiesTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/j2d/ShapeUtilitiesTest.java [UTF-8] Wed Jan  7 11:18:03 2015
@@ -16,12 +16,16 @@
  */
 package org.apache.sis.internal.referencing.j2d;
 
-import java.awt.geom.Line2D;
+import java.awt.Shape;
+import java.awt.geom.Path2D;
 import java.awt.geom.Point2D;
+import java.awt.geom.Line2D;
+import java.awt.geom.QuadCurve2D;
+import java.awt.geom.CubicCurve2D;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
-import static org.junit.Assert.*;
+import static org.opengis.test.Assert.*;
 
 
 /**
@@ -39,29 +43,35 @@ public final strictfp class ShapeUtiliti
     private static final double EPS = 1E-8;
 
     /**
-     * Tests {@link ShapeUtilities#cubicCurveExtremum(double, double, double, double, double, double)}.
+     * Tests {@link ShapeUtilities#toPrimitive(Shape)}.
      */
     @Test
-    public void testCubicCurveExtremum() {
-        final Point2D.Double P1 = new Point2D.Double();
-        final Point2D.Double P2 = new Point2D.Double();
-        double dy1, dy2;
-        Line2D extremums;
-
-        P1.x =  0; P1.y =  0; dy1 =   7;
-        P2.x = -4; P2.y =  0; dy2 = -12;
-        extremums = ShapeUtilities.cubicCurveExtremum(P1.x, P1.y, dy1, P2.x, P2.y, dy2);
-        assertEquals("X1",   3.31741507, extremums.getX1(), EPS);
-        assertEquals("Y1",  17.31547745, extremums.getY1(), EPS);
-        assertEquals("X2",  -2.25074840, extremums.getX2(), EPS);
-        assertEquals("Y2",  -9.65918115, extremums.getY2(), EPS);
-
-        P1.x = 0; P1.y =  0; dy1 = 5;
-        P2.x = 5; P2.y = 20; dy2 = 1;
-        extremums = ShapeUtilities.cubicCurveExtremum(P1.x, P1.y, dy1, P2.x, P2.y, dy2);
-        assertEquals("X1",   5.47313697, extremums.getX1(), EPS);
-        assertEquals("Y1",  20.24080512, extremums.getY1(), EPS);
-        assertEquals("X2",  -3.80647030, extremums.getX2(), EPS);
-        assertEquals("Y2", -11.72228660, extremums.getY2(), EPS);
+    public void testToPrimitive() {
+        final Path2D path = new Path2D.Double();
+        path.moveTo(4, 5);
+        path.lineTo(7, 9);
+        Shape p = ShapeUtilities.toPrimitive(path);
+        assertInstanceOf("toPrimitive", Line2D.class, p);
+        assertEquals("P1", new Point2D.Double(4, 5), ((Line2D) p).getP1());
+        assertEquals("P2", new Point2D.Double(7, 9), ((Line2D) p).getP2());
+
+        path.reset();
+        path.moveTo(4, 5);
+        path.quadTo(6, 7, 8, 5);
+        p = ShapeUtilities.toPrimitive(path);
+        assertInstanceOf("toPrimitive", QuadCurve2D.class, p);
+        assertEquals("P1",     new Point2D.Double(4, 5), ((QuadCurve2D) p).getP1());
+        assertEquals("CtrlPt", new Point2D.Double(6, 7), ((QuadCurve2D) p).getCtrlPt());
+        assertEquals("P2",     new Point2D.Double(8, 5), ((QuadCurve2D) p).getP2());
+
+        path.reset();
+        path.moveTo(4, 5);
+        path.curveTo(6, 7, 8, 6, 9, 4);
+        p = ShapeUtilities.toPrimitive(path);
+        assertInstanceOf("toPrimitive", CubicCurve2D.class, p);
+        assertEquals("P1",     new Point2D.Double(4, 5), ((CubicCurve2D) p).getP1());
+        assertEquals("CtrlP1", new Point2D.Double(6, 7), ((CubicCurve2D) p).getCtrlP1());
+        assertEquals("CtrlP2", new Point2D.Double(8, 6), ((CubicCurve2D) p).getCtrlP2());
+        assertEquals("P2",     new Point2D.Double(9, 4), ((CubicCurve2D) p).getP2());
     }
 }

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=1650035&r1=1650034&r2=1650035&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 Jan  7 11:18:03 2015
@@ -114,6 +114,7 @@ import org.junit.BeforeClass;
     org.apache.sis.geometry.SubEnvelopeTest.class,
     org.apache.sis.geometry.ImmutableEnvelopeTest.class,
     org.apache.sis.geometry.Envelope2DTest.class,
+    org.apache.sis.geometry.CurveExtremumTest.class,
     org.apache.sis.geometry.EnvelopesTest.class,
 
     org.apache.sis.distance.LatLonPointRadiusTest.class, // Pending refactoring in a geometry package.