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 ∂<var>x</var>/∂<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 ∂<var>x</var>/∂<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 ∂<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 ∂<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)
- {
- /*
- * 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.