Improved accuracy of internal computation.

The improvement is obtained by using high accuracy linear combinations
and by preserving cos/sin as much as possible. This last part is
important in the frequent case of lines along y axis, i.e. when angle is
π/2. We want the cosine to remain 0 and not get about 10^-17. 

Project: http://git-wip-us.apache.org/repos/asf/commons-math/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-math/commit/5f667c03
Tree: http://git-wip-us.apache.org/repos/asf/commons-math/tree/5f667c03
Diff: http://git-wip-us.apache.org/repos/asf/commons-math/diff/5f667c03

Branch: refs/heads/master
Commit: 5f667c031cdf02adbee9ef83cb71990333c58ba3
Parents: c29e3d6
Author: Luc Maisonobe <l...@apache.org>
Authored: Sun Nov 30 11:44:07 2014 +0100
Committer: Luc Maisonobe <l...@apache.org>
Committed: Tue Dec 2 15:24:31 2014 +0100

----------------------------------------------------------------------
 .../math3/geometry/euclidean/twod/Line.java     | 54 ++++++++++----------
 1 file changed, 28 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-math/blob/5f667c03/src/main/java/org/apache/commons/math3/geometry/euclidean/twod/Line.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/commons/math3/geometry/euclidean/twod/Line.java 
b/src/main/java/org/apache/commons/math3/geometry/euclidean/twod/Line.java
index 70ab1ac..b40f0fa 100644
--- a/src/main/java/org/apache/commons/math3/geometry/euclidean/twod/Line.java
+++ b/src/main/java/org/apache/commons/math3/geometry/euclidean/twod/Line.java
@@ -31,6 +31,7 @@ import 
org.apache.commons.math3.geometry.partitioning.Hyperplane;
 import org.apache.commons.math3.geometry.partitioning.SubHyperplane;
 import org.apache.commons.math3.geometry.partitioning.Transform;
 import org.apache.commons.math3.util.FastMath;
+import org.apache.commons.math3.util.MathArrays;
 import org.apache.commons.math3.util.MathUtils;
 
 /** This class represents an oriented line in the 2D plane.
@@ -147,8 +148,8 @@ public class Line implements Hyperplane<Euclidean2D>, 
Embedding<Euclidean2D, Euc
      */
     public Line(final Line line) {
         angle        = MathUtils.normalizeAngle(line.angle, FastMath.PI);
-        cos          = FastMath.cos(angle);
-        sin          = FastMath.sin(angle);
+        cos          = line.cos;
+        sin          = line.sin;
         originOffset = line.originOffset;
         tolerance    = line.tolerance;
     }
@@ -174,9 +175,9 @@ public class Line implements Hyperplane<Euclidean2D>, 
Embedding<Euclidean2D, Euc
             originOffset = p1.getY();
         } else {
             angle        = FastMath.PI + FastMath.atan2(-dy, -dx);
-            cos          = FastMath.cos(angle);
-            sin          = FastMath.sin(angle);
-            originOffset = (p2.getX() * p1.getY() - p1.getX() * p2.getY()) / d;
+            cos          = dx / d;
+            sin          = dy / d;
+            originOffset = MathArrays.linearCombination(p2.getX(), p1.getY(), 
-p1.getX(), p2.getY()) / d;
         }
     }
 
@@ -188,7 +189,7 @@ public class Line implements Hyperplane<Euclidean2D>, 
Embedding<Euclidean2D, Euc
         this.angle   = MathUtils.normalizeAngle(alpha, FastMath.PI);
         cos          = FastMath.cos(this.angle);
         sin          = FastMath.sin(this.angle);
-        originOffset = cos * p.getY() - sin * p.getX();
+        originOffset = MathArrays.linearCombination(cos, p.getY(), -sin, 
p.getX());
     }
 
     /** Revert the instance.
@@ -235,14 +236,14 @@ public class Line implements Hyperplane<Euclidean2D>, 
Embedding<Euclidean2D, Euc
     /** {@inheritDoc} */
     public Vector1D toSubSpace(final Point<Euclidean2D> point) {
         Vector2D p2 = (Vector2D) point;
-        return new Vector1D(cos * p2.getX() + sin * p2.getY());
+        return new Vector1D(MathArrays.linearCombination(cos, p2.getX(), sin, 
p2.getY()));
     }
 
     /** {@inheritDoc} */
     public Vector2D toSpace(final Point<Euclidean1D> point) {
         final double abscissa = ((Vector1D) point).getX();
-        return new Vector2D(abscissa * cos - originOffset * sin,
-                            abscissa * sin + originOffset * cos);
+        return new Vector2D(MathArrays.linearCombination(abscissa, cos, 
-originOffset, sin),
+                            MathArrays.linearCombination(abscissa, sin,  
originOffset, cos));
     }
 
     /** Get the intersection point of the instance and another line.
@@ -251,12 +252,12 @@ public class Line implements Hyperplane<Euclidean2D>, 
Embedding<Euclidean2D, Euc
      * or null if there are no intersection points
      */
     public Vector2D intersection(final Line other) {
-        final double d = sin * other.cos - other.sin * cos;
+        final double d = MathArrays.linearCombination(sin, other.cos, 
-other.sin, cos);
         if (FastMath.abs(d) < tolerance) {
             return null;
         }
-        return new Vector2D((cos * other.originOffset - other.cos * 
originOffset) / d,
-                            (sin * other.originOffset - other.sin * 
originOffset) / d);
+        return new Vector2D(MathArrays.linearCombination(cos, 
other.originOffset, -other.cos, originOffset) / d,
+                            MathArrays.linearCombination(sin, 
other.originOffset, -other.sin, originOffset) / d);
     }
 
     /** {@inheritDoc}
@@ -298,7 +299,7 @@ public class Line implements Hyperplane<Euclidean2D>, 
Embedding<Euclidean2D, Euc
      */
     public double getOffset(final Line line) {
         return originOffset +
-               ((cos * line.cos + sin * line.sin > 0) ? -line.originOffset : 
line.originOffset);
+               (MathArrays.linearCombination(cos, line.cos, sin, line.sin) > 0 
? -line.originOffset : line.originOffset);
     }
 
     /** Get the offset (oriented distance) of a vector.
@@ -312,13 +313,13 @@ public class Line implements Hyperplane<Euclidean2D>, 
Embedding<Euclidean2D, Euc
     /** {@inheritDoc} */
     public double getOffset(final Point<Euclidean2D> point) {
         Vector2D p2 = (Vector2D) point;
-        return sin * p2.getX() - cos * p2.getY() + originOffset;
+        return MathArrays.linearCombination(sin, p2.getX(), -cos, p2.getY(), 
1.0, originOffset);
     }
 
     /** {@inheritDoc} */
     public boolean sameOrientationAs(final Hyperplane<Euclidean2D> other) {
         final Line otherL = (Line) other;
-        return (sin * otherL.sin + cos * otherL.cos) >= 0.0;
+        return MathArrays.linearCombination(sin, otherL.sin, cos, otherL.cos) 
>= 0.0;
     }
 
     /** Get one point from the plane.
@@ -330,7 +331,8 @@ public class Line implements Hyperplane<Euclidean2D>, 
Embedding<Euclidean2D, Euc
     public Vector2D getPointAt(final Vector1D abscissa, final double offset) {
         final double x       = abscissa.getX();
         final double dOffset = offset - originOffset;
-        return new Vector2D(x * cos + dOffset * sin, x * sin - dOffset * cos);
+        return new Vector2D(MathArrays.linearCombination(x, cos,  dOffset, 
sin),
+                            MathArrays.linearCombination(x, sin, -dOffset, 
cos));
     }
 
     /** Check if the line contains a point.
@@ -360,14 +362,14 @@ public class Line implements Hyperplane<Euclidean2D>, 
Embedding<Euclidean2D, Euc
      * (they can have either the same or opposite orientations)
      */
     public boolean isParallelTo(final Line line) {
-        return FastMath.abs(sin * line.cos - cos * line.sin) < tolerance;
+        return FastMath.abs(MathArrays.linearCombination(sin, line.cos, -cos, 
line.sin)) < tolerance;
     }
 
     /** Translate the line to force it passing by a point.
      * @param p point by which the line should pass
      */
     public void translateToPoint(final Vector2D p) {
-        originOffset = cos * p.getY() - sin * p.getX();
+        originOffset = MathArrays.linearCombination(cos, p.getY(), -sin, 
p.getX());
     }
 
     /** Get the angle of the line.
@@ -457,9 +459,9 @@ public class Line implements Hyperplane<Euclidean2D>, 
Embedding<Euclidean2D, Euc
             cYY = m[3];
             cY1 = m[5];
 
-            c1Y = cXY * cY1 - cYY * cX1;
-            c1X = cXX * cY1 - cYX * cX1;
-            c11 = cXX * cYY - cYX * cXY;
+            c1Y = MathArrays.linearCombination(cXY, cY1, -cYY, cX1);
+            c1X = MathArrays.linearCombination(cXX, cY1, -cYX, cX1);
+            c11 = MathArrays.linearCombination(cXX, cYY, -cYX, cXY);
 
             if (FastMath.abs(c11) < 1.0e-20) {
                 throw new 
MathIllegalArgumentException(LocalizedFormats.NON_INVERTIBLE_TRANSFORM);
@@ -472,16 +474,16 @@ public class Line implements Hyperplane<Euclidean2D>, 
Embedding<Euclidean2D, Euc
             final Vector2D p2D = (Vector2D) point;
             final double  x   = p2D.getX();
             final double  y   = p2D.getY();
-            return new Vector2D(cXX * x + cXY * y + cX1,
-                               cYX * x + cYY * y + cY1);
+            return new Vector2D(MathArrays.linearCombination(cXX, x, cXY, y, 
cX1, 1),
+                                MathArrays.linearCombination(cYX, x, cYY, y, 
cY1, 1));
         }
 
         /** {@inheritDoc} */
         public Line apply(final Hyperplane<Euclidean2D> hyperplane) {
             final Line   line    = (Line) hyperplane;
-            final double rOffset = c1X * line.cos + c1Y * line.sin + c11 * 
line.originOffset;
-            final double rCos    = cXX * line.cos + cXY * line.sin;
-            final double rSin    = cYX * line.cos + cYY * line.sin;
+            final double rOffset = MathArrays.linearCombination(c1X, line.cos, 
c1Y, line.sin, c11, line.originOffset);
+            final double rCos    = MathArrays.linearCombination(cXX, line.cos, 
cXY, line.sin);
+            final double rSin    = MathArrays.linearCombination(cYX, line.cos, 
cYY, line.sin);
             final double inv     = 1.0 / FastMath.sqrt(rSin * rSin + rCos * 
rCos);
             return new Line(FastMath.PI + FastMath.atan2(-rSin, -rCos),
                             inv * rCos, inv * rSin,

Reply via email to