You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by lu...@apache.org on 2014/12/02 22:20:29 UTC
[3/8] [math] Improved accuracy of internal computation.
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 <lu...@apache.org>
Authored: Sun Nov 30 11:44:07 2014 +0100
Committer: Luc Maisonobe <lu...@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,