sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1654404 - in /sis/branches/JDK8/core/sis-utility/src: main/java/org/apache/sis/math/Line.java main/java/org/apache/sis/math/Plane.java test/java/org/apache/sis/math/LineTest.java test/java/org/apache/sis/test/suite/UtilityTestSuite.java
Date Fri, 23 Jan 2015 22:07:05 GMT
Author: desruisseaux
Date: Fri Jan 23 22:07:04 2015
New Revision: 1654404

URL: http://svn.apache.org/r1654404
Log:
Partial port of the Line class. Does not yet include the methods computing shortest distance
between a point and the line, etc.

Added:
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/math/Line.java   (with
props)
    sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/math/LineTest.java   (with
props)
Modified:
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/math/Plane.java
    sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java

Added: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/math/Line.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/math/Line.java?rev=1654404&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/math/Line.java (added)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/math/Line.java [UTF-8]
Fri Jan 23 22:07:04 2015
@@ -0,0 +1,404 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.math;
+
+import java.io.Serializable;
+import org.opengis.geometry.DirectPosition;
+import org.opengis.geometry.MismatchedDimensionException;
+import org.apache.sis.internal.util.DoubleDouble;
+import org.apache.sis.internal.util.Numerics;
+import org.apache.sis.util.resources.Errors;
+
+import static java.lang.Double.*;
+
+
+/**
+ * Equation of a line in a two dimensional space (<var>x</var>,<var>y</var>).
+ * A line can be expressed by the <var>y</var> = <var>slope</var>⋅<var>x</var>
+ <var>y</var>₀ equation
+ * where <var>y</var>₀ is the value of <var>y</var> at <var>x</var>
= 0.
+ *
+ * <p>The equation parameters for a {@code Line} object can be set at construction
time or using one
+ * of the {@code setLine(…)} methods. The <var>y</var> value can be computed
for a given <var>x</var>
+ * value using the {@link #y(double)} method. Method {@link #x(double)} computes the converse
and should
+ * work even if the line is vertical.</p>
+ *
+ * <div class="note"><b>Comparison with Java2D geometries:</b>
+ * At the difference of {@link java.awt.geom.Line2D} which is bounded by (<var>x</var>₁,<var>y</var>₁)
+ * and (<var>x</var>₂,<var>y</var>₂) points, {@code Line} objects
extend toward infinity.</div>
+ *
+ * @author  Martin Desruisseaux (MPO, IRD)
+ * @since   0.5 (derived from geotk-1.0)
+ * @version 0.5
+ * @module
+ */
+public class Line implements Cloneable, Serializable {
+    /**
+     * Serial number for compatibility with different versions.
+     */
+    private static final long serialVersionUID = 2185952238314399110L;
+
+    /**
+     * Number of dimensions.
+     */
+    private static final int DIMENSION = 2;
+
+    /**
+     * The slope for this line.
+     */
+    private double slope;
+
+    /**
+     * The <var>y</var> value at <var>x</var> = 0.
+     */
+    private double y0;
+
+    /**
+     * Value of <var>x</var> at <var>y</var> = 0.
+     * This value is used for vertical lines.
+     */
+    private double x0;
+
+    /**
+     * Constructs an uninitialized line. All methods will return {@link Double#NaN}.
+     */
+    public Line() {
+        slope = y0 = x0 = NaN;
+    }
+
+    /**
+     * Constructs a line with the specified slope and offset.
+     * The linear equation will be <var>y</var> = <var>slope</var>⋅<var>x</var>
+ <var>y</var>₀.
+     *
+     * @param slope The slope.
+     * @param y0 The <var>y</var> value at <var>x</var> = 0.
+     *
+     * @see #setEquation(double, double)
+     */
+    public Line(final double slope, final double y0) {
+        this.slope =  slope;
+        this.y0    =  y0;
+        this.x0    = -y0 / slope;
+    }
+
+    /**
+     * Returns the slope.
+     *
+     * @return The slope.
+     *
+     * @see #x0()
+     * @see #y0()
+     */
+    public final double slope() {
+        return slope;
+    }
+
+    /**
+     * Returns the <var>x</var> value for <var>y</var> = 0.
+     * Coordinate (<var>x</var>₀, 0) is the intersection point with the <var>x</var>
axis.
+     *
+     * @return The <var>x</var> value for <var>y</var> = 0.
+     *
+     * @see #y0()
+     * @see #slope()
+     */
+    public final double x0() {
+        return x0;
+    }
+
+    /**
+     * Computes <var>x</var> = <var>f</var>⁻¹(<var>y</var>).
+     * If the line is horizontal, then this method returns an infinite value.
+     *
+     * @param  y The <var>y</var> value where to evaluate the inverse function.
+     * @return The <var>x</var> value for the given <var>y</var>
value.
+     *
+     * @see #y(double)
+     */
+    public final double x(final double y) {
+        return x0 + y/slope;
+    }
+
+    /**
+     * Returns the <var>y</var> value for <var>x</var> = 0.
+     * Coordinate (0, <var>y</var>₀) is the intersection point with the <var>y</var>
axis.
+     *
+     * @return The <var>y</var> value for <var>x</var> = 0.
+     *
+     * @see #x0()
+     * @see #slope()
+     */
+    public final double y0() {
+        return y0;
+    }
+
+    /**
+     * Computes <var>y</var> = <var>f</var>(<var>x</var>).
+     * If the line is vertical, then this method returns an infinite value.
+     *
+     * @param  x The <var>x</var> value where to evaluate the inverse function.
+     * @return The <var>y</var> value for the given <var>x</var>
value.
+     *
+     * @see #x(double)
+     */
+    public final double y(final double x) {
+        return y0 + x*slope;
+    }
+
+    /**
+     * Translates the line. The slope stay unchanged.
+     *
+     * @param dx The horizontal translation.
+     * @param dy The vertical translation.
+     */
+    public void translate(final double dx, final double dy) {
+        if (slope == 0 || isInfinite(slope)) {
+            x0 += dx;
+            y0 += dy;
+        } else {
+            x0 += dx - dy/slope;
+            y0 += dy - slope*dx;
+        }
+    }
+
+    /**
+     * Sets this line to the specified slope and offset.
+     * The linear equation will be <var>y</var> = <var>slope</var>⋅<var>x</var>
+ <var>y</var>₀.
+     *
+     * @param slope The slope.
+     * @param y0 The <var>y</var> value at <var>x</var> = 0.
+     *
+     * @see #setFromPoints(double, double, double, double)
+     * @see #fit(double[], double[])
+     */
+    public void setEquation(final double slope, final double y0) {
+        this.slope =  slope;
+        this.y0    =  y0;
+        this.x0    = -y0 / slope;
+    }
+
+    /**
+     * Sets a line through the specified points.
+     * The line will continue toward infinity after the points.
+     *
+     * @param x1 Ordinate <var>x</var> of the first point.
+     * @param y1 Ordinate <var>y</var> of the first point.
+     * @param x2 Ordinate <var>x</var> of the second point.
+     * @param y2 Ordinate <var>y</var> of the second point.
+     */
+    public void setFromPoints(final double x1, final double y1, final double x2, final double
y2) {
+        this.slope = (y2 - y1) / (x2 - x1);
+        this.x0    = x2 - y2/slope;
+        this.y0    = y2 - slope*x2;
+        if (isNaN(x0) && slope == 0) {
+            // Occurs for horizontal lines right on the x axis.
+            x0 = POSITIVE_INFINITY;
+        }
+        if (isNaN(y0) && isInfinite(slope)) {
+            // Occurs for vertical lines right on the y axis.
+            y0 = POSITIVE_INFINITY;
+        }
+    }
+
+    /**
+     * Given a set of data points <var>x</var>[0 … <var>n</var>-1],
<var>y</var>[0 … <var>n</var>-1],
+     * fits them to a straight line <var>y</var> = <var>slope</var>⋅<var>x</var>
+ <var>y</var>₀ in a
+     * least-squares senses. This method assume that the <var>x</var> values
are precise and all uncertainty
+     * is in <var>y</var>.
+     *
+     * @param x Vector of <var>x</var> values (independent variable).
+     * @param y Vector of <var>y</var> values (dependent variable).
+     * @return Estimation of the correlation coefficient. The closer this coefficient is
to 1, the better the fit.
+     *
+     * @throws IllegalArgumentException if <var>x</var> and <var>y</var>
do not have the same length.
+     */
+    public double fit(final double[] x, final double[] y) {
+        // Do not invoke an overrideable method with our tricky iterable.
+        return doFit(new CompoundDirectPositions(x, y));
+    }
+
+    /**
+     * Given a sequence of points, fits them to a straight line <var>y</var>
= <var>slope</var>⋅<var>x</var> +
+     * <var>y</var>₀ in a least-squares senses. This method assume that the
<var>x</var> values are precise and
+     * all uncertainty is in <var>y</var>.
+     *
+     * <p>Points shall be two dimensional with ordinate values in the (<var>x</var>,<var>y</var>)
order.
+     * {@link Double#NaN} ordinate values are ignored.</p>
+     *
+     * @param  points The two-dimensional points.
+     * @return Estimation of the correlation coefficient. The closer this coefficient is
to 1, the better the fit.
+     * @throws MismatchedDimensionException if a point is not two-dimensional.
+     */
+    public double fit(final Iterable<? extends DirectPosition> points) {
+        return doFit(points);
+    }
+
+    /**
+     * Implementation of public {@code fit(…)} methods.
+     */
+    private double doFit(final Iterable<? extends DirectPosition> points) {
+        int i = 0, n = 0;
+        final DoubleDouble mean_x = new DoubleDouble();
+        final DoubleDouble mean_y = new DoubleDouble();
+        for (final DirectPosition p : points) {
+            final int dimension = p.getDimension();
+            if (dimension != DIMENSION) {
+                throw new MismatchedDimensionException(Errors.format(
+                        Errors.Keys.MismatchedDimension_3, "points[" + i + ']', DIMENSION,
dimension));
+            }
+            i++;
+            final double x,y;
+            if (!isNaN(y = p.getOrdinate(1)) &&  // Test first the dimension which
is most likely to contain NaN.
+                !isNaN(x = p.getOrdinate(0)))
+            {
+                mean_x.add(x);
+                mean_y.add(y);
+                n++;
+            }
+        }
+        mean_x.divide(n, 0);
+        mean_y.divide(n, 0);
+        /*
+         * We have to solve two equations with two unknowns:
+         *
+         *   1)    mean(y)   = m⋅mean(x) + y₀
+         *   2)    mean(x⋅y) = m⋅mean(x²) + y₀⋅mean(x)
+         *
+         * Those formulas lead to a quadratic equation. However, the formulas become very
simples
+         * if we set 'mean(x) = 0'. We can achieve this result by computing instead of (2):
+         *
+         *   2b)   mean(Δx⋅y) = m⋅mean(Δx²)
+         *
+         * where dx = x-mean(x). In this case mean(Δx) == 0.
+         */
+        final DoubleDouble a       = new DoubleDouble();
+        final DoubleDouble b       = new DoubleDouble();
+        final DoubleDouble mean_x2 = new DoubleDouble();
+        final DoubleDouble mean_y2 = new DoubleDouble();
+        final DoubleDouble mean_xy = new DoubleDouble();
+        for (final DirectPosition p : points) {
+            final double y;
+            if (!isNaN(y       = p.getOrdinate(1)) &&  // Test first the dimension
which is most likely to contain NaN.
+                !isNaN(a.value = p.getOrdinate(0)))
+            {
+                a.error = 0;
+                a.subtract(mean_x);     // Δx = x - mean_x
+                b.setFrom(a);
+                b.multiply(a);          // (Δx)² = Δx * Δx
+                mean_x2.add(b);         // mean_x² += (Δx)²
+
+                a.multiply(y);          // xy = Δx * y
+                mean_xy.add(a);         // mean_xy += xy
+
+                a.setToProduct(y, y);   // y² = y * y
+                mean_y2.add(a);         // mean_y² += y²
+            }
+        }
+        mean_x2.divide(n, 0);
+        mean_y2.divide(n, 0);
+        mean_xy.divide(n, 0);
+        /*
+         * Assuming that 'mean(x) == 0', then the correlation
+         * coefficient can be approximate by:
+         *
+         * R = mean(xy) / sqrt( mean(x²) * (mean(y²) - mean(y)²) )
+         */
+        a.setFrom(mean_xy);
+        a.divide (mean_x2);     // slope = mean_xy / mean_x²
+        b.setFrom(mean_x);
+        b.multiply(a);
+        b.negate();
+        b.add(mean_y);          // y₀ = mean_y - mean_x * slope
+        setEquation(a.value, b.value);
+        /*
+         * Compute the correlation coefficient:
+         * mean_xy / sqrt(mean_x2 * (mean_y2 - mean_y * mean_y))
+         */
+        a.setFrom(mean_y);
+        a.multiply(mean_y);
+        a.negate();
+        a.add(mean_y2);
+        a.multiply(mean_x2);
+        a.sqrt();
+        a.inverseDivide(mean_xy);
+        return a.value;
+    }
+
+    /**
+     * Returns a clone of this line.
+     *
+     * @return A clone of this line.
+     */
+    @Override
+    public Line clone() {
+        try {
+            return (Line) super.clone();
+        } catch (CloneNotSupportedException exception) {
+            throw new AssertionError(exception);
+        }
+    }
+
+    /**
+     * Compares this line with the specified object for equality.
+     *
+     * @param object The object to compare with this line for equality.
+     * @return {@code true} if both objects are equal.
+     */
+    @Override
+    public boolean equals(final Object object) {
+        if (object != null && getClass() == object.getClass()) {
+            final Line that = (Line) object;
+            return Numerics.equals(this.slope, that.slope) &&
+                   Numerics.equals(this.y0,    that.y0   ) &&
+                   Numerics.equals(this.x0,    that.x0   );
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Returns a hash code value for this line.
+     */
+    @Override
+    public int hashCode() {
+        return Numerics.hashCode(serialVersionUID ^ (doubleToLongBits(slope) + 31*doubleToLongBits(y0)));
+    }
+
+    /**
+     * Returns a string representation of this line. This method returns the linear equation
+     * in the form <var>y</var> = <var>slope</var>⋅<var>x</var>
+ <var>y</var>₀.
+     *
+     * @return A string representation of this line.
+     */
+    @Override
+    public String toString() {
+        final StringBuilder buffer = new StringBuilder(50);
+        if (isInfinite(slope)) {
+            buffer.append("x = ").append(x0);
+        } else {
+            buffer.append("y = ");
+            String separator = "";
+            if (slope != 0) {
+                buffer.append(slope).append("⋅x");
+                separator = " + ";
+            }
+            if (y0 != 0) {
+                buffer.append(separator).append(y0);
+            }
+        }
+        return buffer.toString();
+    }
+}

Propchange: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/math/Line.java
------------------------------------------------------------------------------
    svn:eol-style = native

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

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/math/Plane.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/math/Plane.java?rev=1654404&r1=1654403&r2=1654404&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/math/Plane.java [UTF-8]
(original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/math/Plane.java [UTF-8]
Fri Jan 23 22:07:04 2015
@@ -54,6 +54,11 @@ public class Plane implements Cloneable,
     private static final long serialVersionUID = 2956201711131316723L;
 
     /**
+     * Number of dimensions.
+     */
+    private static final int DIMENSION = 3;
+
+    /**
      * Threshold value relative to 1 ULP of other terms in the  z = sx⋅x + sy⋅y + z₀
 equation.
      * A value of 1 would be theoretically sufficient since adding a value smaller to 1 ULP
to
      * a {@code double} has no effect. Nevertheless we use a smaller value as a safety because:
@@ -149,7 +154,7 @@ public class Plane implements Cloneable,
      * Computes the <var>x</var> value for the specified (<var>y</var>,<var>z</var>)
point.
      * The <var>x</var> value is computed using the following equation:
      *
-     * <blockquote>x(y,z) = (z - ({@linkplain #z0() z0} + {@linkplain #slopeY() sy}⋅y))
/ {@linkplain #slopeX() sx}</blockquote>
+     * <blockquote>x(y,z) = (z - ({@linkplain #z0() z₀} + {@linkplain #slopeY() sy}⋅y))
/ {@linkplain #slopeX() sx}</blockquote>
      *
      * @param y The <var>y</var> value where to compute <var>x</var>.
      * @param z The <var>z</var> value where to compute <var>x</var>.
@@ -163,7 +168,7 @@ public class Plane implements Cloneable,
      * Computes the <var>y</var> value for the specified (<var>x</var>,<var>z</var>)
point.
      * The <var>y</var> value is computed using the following equation:
      *
-     * <blockquote>y(x,z) = (z - ({@linkplain #z0() z0} + {@linkplain #slopeX() sx}⋅x))
/ {@linkplain #slopeY() sy}</blockquote>
+     * <blockquote>y(x,z) = (z - ({@linkplain #z0() z₀} + {@linkplain #slopeX() sx}⋅x))
/ {@linkplain #slopeY() sy}</blockquote>
      *
      * @param x The <var>x</var> value where to compute <var>y</var>.
      * @param z The <var>z</var> value where to compute <var>y</var>.
@@ -177,7 +182,7 @@ public class Plane implements Cloneable,
      * Computes the <var>z</var> value for the specified (<var>x</var>,<var>y</var>)
point.
      * The <var>z</var> value is computed using the following equation:
      *
-     * <blockquote>z(x,y) = {@linkplain #z0() z0} + {@linkplain #slopeX() sx}⋅x +
{@linkplain #slopeY() sy}⋅y</blockquote>
+     * <blockquote>z(x,y) = {@linkplain #z0() z₀} + {@linkplain #slopeX() sx}⋅x
+ {@linkplain #slopeY() sy}⋅y</blockquote>
      *
      * @param x The <var>x</var> value where to compute <var>z</var>.
      * @param y The <var>y</var> value where to compute <var>z</var>.
@@ -232,7 +237,7 @@ public class Plane implements Cloneable,
      * {@link Double#NaN} ordinate values are ignored.
      * The result is undetermined if all points are colinear.</p>
      *
-     * @param  points The three dimensional points.
+     * @param  points The three-dimensional points.
      * @return An estimation of the Pearson correlation coefficient.
      * @throws MismatchedDimensionException if a point is not three-dimensional.
      */
@@ -265,9 +270,9 @@ public class Plane implements Cloneable,
         final DoubleDouble zy     = new DoubleDouble();
         for (final DirectPosition p : points) {
             final int dimension = p.getDimension();
-            if (dimension != 3) {
+            if (dimension != DIMENSION) {
                 throw new MismatchedDimensionException(Errors.format(
-                        Errors.Keys.MismatchedDimension_3, "positions[" + i + ']', 3, dimension));
+                        Errors.Keys.MismatchedDimension_3, "points[" + i + ']', DIMENSION,
dimension));
             }
             i++;
             final double x = p.getOrdinate(0); if (Double.isNaN(x)) continue;
@@ -319,12 +324,6 @@ public class Plane implements Cloneable,
         z0.subtract(tmp);
         z0.divide(n, 0);
         /*
-         * Done - store the result.
-         */
-        this.sx = sx.value;
-        this.sy = sy.value;
-        this.z0 = z0.value;
-        /*
          * At this point, the model is computed. Now computes an estimation of the Pearson
          * correlation coefficient. Note that both the z array and the z computed from the
          * model have the same average, called sum_z below (the name is not true anymore).
@@ -335,7 +334,7 @@ public class Plane implements Cloneable,
         final double mean_x = sum_x.value / n;
         final double mean_y = sum_y.value / n;
         final double mean_z = sum_z.value / n;
-        final double offset = abs((this.sx * mean_x + this.sy * mean_y) + this.z0); // Offsetted
z₀ - see comment before usage.
+        final double offset = abs((sx.value * mean_x + sy.value * mean_y) + z0.value); //
Offsetted z₀ - see comment before usage.
         double sum_ds2 = 0, sum_dz2 = 0, sum_dsz = 0;
         for (final DirectPosition p : points) {
             final double x = (p.getOrdinate(0) - mean_x) * sx.value;
@@ -364,9 +363,13 @@ public class Plane implements Cloneable,
             if (detectZeroSy && abs(y) >= ulp(x * ZERO_THRESHOLD)) detectZeroSy
= false;
             if (detectZeroZ0 && offset >= ulp(s * ZERO_THRESHOLD)) detectZeroZ0
= false;
         }
-        if (detectZeroSx) this.sx = 0;
-        if (detectZeroSy) this.sy = 0;
-        if (detectZeroZ0) this.z0 = 0;
+        /*
+         * Store the result only when we are done, so we have a "all or nothing" behavior.
+         * We invoke the setEquation(sx, sy, z₀) method in case the user override it.
+         */
+        setEquation(detectZeroSx ? 0 : sx.value,
+                    detectZeroSy ? 0 : sy.value,
+                    detectZeroZ0 ? 0 : z0.value);
         return sum_dsz / sqrt(sum_ds2 * sum_dz2);
     }
 
@@ -408,7 +411,7 @@ public class Plane implements Cloneable,
     @Override
     public int hashCode() {
         return Numerics.hashCode(serialVersionUID
-                     ^ (Double.doubleToLongBits(z0 )
+                     ^ (Double.doubleToLongBits(z0)
                 + 31 * (Double.doubleToLongBits(sx)
                 + 31 * (Double.doubleToLongBits(sy)))));
     }
@@ -419,12 +422,12 @@ public class Plane implements Cloneable,
      *
      * <blockquote>
      *     <var>z</var>(<var>x</var>,<var>y</var>) =
{@linkplain #slopeX() sx}⋅<var>x</var>
-     *     + {@linkplain #slopeY() sy}⋅<var>y</var> + {@linkplain #z0() z0}
+     *     + {@linkplain #slopeY() sy}⋅<var>y</var> + {@linkplain #z0() z₀}
      * </blockquote>
      */
     @Override
     public String toString() {
-        final StringBuilder buffer = new StringBuilder("z(x,y) = ");
+        final StringBuilder buffer = new StringBuilder(60).append("z(x,y) = ");
         String separator = "";
         if (sx != 0) {
             buffer.append(sx).append("⋅x");
@@ -434,11 +437,6 @@ public class Plane implements Cloneable,
             buffer.append(separator).append(sy).append("⋅y");
             separator = " + ";
         }
-        if (z0 != 0) {
-            buffer.append(separator).append(z0);
-        } else if (separator.isEmpty()) {
-            buffer.append('0');
-        }
-        return buffer.toString();
+        return buffer.append(separator).append(z0).toString();
     }
 }

Added: sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/math/LineTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/math/LineTest.java?rev=1654404&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/math/LineTest.java (added)
+++ sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/math/LineTest.java [UTF-8]
Fri Jan 23 22:07:04 2015
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.math;
+
+import java.util.Random;
+import org.apache.sis.test.DependsOn;
+import org.apache.sis.test.TestCase;
+import org.junit.*;
+
+import static org.apache.sis.test.Assert.*;
+
+
+/**
+ * Tests the {@link Line} class.
+ *
+ * @author  Martin Desruisseaux (MPO, IRD)
+ * @since   0.5 (derived from geotk-2.0)
+ * @version 0.5
+ * @module
+ */
+@DependsOn(org.apache.sis.internal.util.DoubleDoubleTest.class)
+public final strictfp class LineTest extends TestCase {
+    /**
+     * Tolerance factor for comparisons for floating point values.
+     */
+    private static final double EPS = 1E-8;
+
+    /**
+     * Tests {@link Line#setFromPoints(double, double, double, double)}.
+     */
+    @Test
+    public void testSetFromPoints() {
+        final Line line = new Line();
+        line.setFromPoints(-2, 2,  8, 22);
+        assertEquals("slope", 2, line.slope(), EPS);
+        assertEquals("x₀",   -3, line.x0(),    EPS);
+        assertEquals("y₀",    6, line.y0(),    EPS);
+
+        // Horizontal line
+        line.setFromPoints(-2, 2,  8, 2);
+        assertEquals("slope", 0, line.slope(), EPS);
+        assertTrue  ("x₀", Double.isInfinite(line.x0()));
+        assertEquals("y₀",    2, line.y0(),    EPS);
+
+        // Vertical line
+        line.setFromPoints(-2, 2,  -2, 22);
+        assertTrue  ("slope", Double.isInfinite(line.slope()));
+        assertEquals("x₀", -2, line.x0(), EPS);
+        assertTrue  ("y₀", Double.isInfinite(line.y0()));
+
+        // Horizontal line on the x axis
+        line.setFromPoints(-2, 0, 8, 0);
+        assertEquals("slope", 0, line.slope(), EPS);
+        assertTrue  ("x₀", Double.isInfinite(line.x0()));
+        assertEquals("y₀", 0, line.y0(), EPS);
+
+        // Vertical line on the y axis
+        line.setFromPoints(0, 2, 0, 22);
+        assertTrue  ("slope", Double.isInfinite(line.slope()));
+        assertEquals("x₀", 0, line.x0(), EPS);
+        assertTrue  ("y₀", Double.isInfinite(line.y0()));
+    }
+
+    /**
+     * Tests {@link Line#fit(double[], double[])}.
+     */
+    @Test
+    public void testFit() {
+        final int    n = 10000;
+        final double slope = 5;
+        final double offset = 10;
+        final double[] x = new double[n];
+        final double[] y = new double[n];
+        final Random random = new Random(888576070);
+        for (int i=0; i<n; i++) {
+            final double xi = random.nextDouble() * (20*n) - 10*n;
+            final double yi = random.nextGaussian() * 100 + (slope * xi + offset);
+            x[i] = xi;
+            y[i] = yi;
+        }
+        final Line line = new Line();
+        final double correlation = line.fit(x, y);
+        assertEquals("slope", slope,        line.slope(), 1E-6);
+        assertEquals("x₀",    offset,       line.y0(),    0.5 );
+        assertEquals("y₀",   -offset/slope, line.x0(),    0.1 );
+        assertEquals("corr",  1.0,          correlation,  1E-6);
+    }
+
+    /**
+     * Tests serialization.
+     */
+    @Test
+    public void testSerialization() {
+        final Line local = new Line(9.5, -3.7);
+        assertNotSame(local, assertSerializedEquals(local));
+    }
+}

Propchange: sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/math/LineTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

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

Modified: sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java?rev=1654404&r1=1654403&r2=1654404&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
[UTF-8] Fri Jan 23 22:07:04 2015
@@ -61,6 +61,7 @@ import org.junit.BeforeClass;
     org.apache.sis.math.StatisticsFormatTest.class,
     org.apache.sis.internal.util.UtilitiesTest.class,
     org.apache.sis.internal.util.DoubleDoubleTest.class,
+    org.apache.sis.math.LineTest.class,
     org.apache.sis.math.PlaneTest.class,
 
     // Collections.



Mime
View raw message