You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ma...@apache.org on 2021/06/22 12:22:21 UTC
[commons-geometry] branch master updated: GEOMETRY-126: replacing
usage of commons-numbers LinearCombination with Sum;
adding VectorXD.Sum classes
This is an automated email from the ASF dual-hosted git repository.
mattjuntunen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-geometry.git
The following commit(s) were added to refs/heads/master by this push:
new 3d138dc GEOMETRY-126: replacing usage of commons-numbers LinearCombination with Sum; adding VectorXD.Sum classes
3d138dc is described below
commit 3d138dc6019eb2d18bb9d063e443e57a165ff9c6
Author: Matt Juntunen <ma...@apache.org>
AuthorDate: Mon Jun 21 18:14:56 2021 -0400
GEOMETRY-126: replacing usage of commons-numbers LinearCombination with Sum; adding VectorXD.Sum classes
---
.../euclidean/threed/SphereGenerator.java | 2 +-
.../enclosing/euclidean/twod/DiskGenerator.java | 2 +-
.../euclidean/threed/SphereGeneratorTest.java | 4 +-
.../euclidean/threed/WelzlEncloser3DTest.java | 4 +-
.../euclidean/twod/DiskGeneratorTest.java | 4 +-
.../geometry/euclidean/EuclideanVectorSum.java | 51 ++++++
.../geometry/euclidean/internal/Vectors.java | 35 ++++
.../commons/geometry/euclidean/oned/Vector1D.java | 153 ++++++++--------
.../euclidean/threed/AffineTransformMatrix3D.java | 35 ++--
.../geometry/euclidean/threed/EmbeddingPlane.java | 16 +-
.../commons/geometry/euclidean/threed/Plane.java | 6 +-
.../geometry/euclidean/threed/Vector3D.java | 198 ++++++++++-----------
.../geometry/euclidean/threed/line/Line3D.java | 8 +-
.../threed/rotation/QuaternionRotation.java | 19 +-
.../euclidean/twod/AffineTransformMatrix2D.java | 17 +-
.../commons/geometry/euclidean/twod/Line.java | 14 +-
.../commons/geometry/euclidean/twod/Vector2D.java | 180 +++++++++----------
.../geometry/euclidean/oned/Vector1DTest.java | 64 ++++---
.../euclidean/threed/EmbeddingPlaneTest.java | 8 +-
.../geometry/euclidean/threed/PlaneTest.java | 10 +-
.../euclidean/threed/RegionBSPTree3DTest.java | 8 +-
.../geometry/euclidean/threed/Vector3DTest.java | 64 ++++---
.../geometry/euclidean/threed/line/Line3DTest.java | 6 +-
.../geometry/euclidean/twod/Vector2DTest.java | 56 +++---
.../twod/ConvexHullGenerator2DAbstractTest.java | 6 +-
.../geometry/spherical/twod/ConvexArea2S.java | 21 +--
.../geometry/spherical/twod/GreatCircle.java | 4 +-
.../geometry/spherical/twod/RegionBSPTree2S.java | 25 +--
28 files changed, 535 insertions(+), 485 deletions(-)
diff --git a/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/enclosing/euclidean/threed/SphereGenerator.java b/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/enclosing/euclidean/threed/SphereGenerator.java
index 0581d95..6fd1068 100644
--- a/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/enclosing/euclidean/threed/SphereGenerator.java
+++ b/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/enclosing/euclidean/threed/SphereGenerator.java
@@ -56,7 +56,7 @@ public class SphereGenerator implements SupportBallGenerator<Vector3D> {
}
final Vector3D vB = support.get(1);
if (support.size() < 3) {
- return new EnclosingBall<>(Vector3D.linearCombination(0.5, vA, 0.5, vB),
+ return new EnclosingBall<>(vA.lerp(vB, 0.5),
0.5 * vA.distance(vB),
Arrays.asList(vA, vB));
}
diff --git a/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/enclosing/euclidean/twod/DiskGenerator.java b/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/enclosing/euclidean/twod/DiskGenerator.java
index 7006b29..77eb5d1 100644
--- a/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/enclosing/euclidean/twod/DiskGenerator.java
+++ b/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/enclosing/euclidean/twod/DiskGenerator.java
@@ -41,7 +41,7 @@ public class DiskGenerator implements SupportBallGenerator<Vector2D> {
}
final Vector2D vB = support.get(1);
if (support.size() < 3) {
- return new EnclosingBall<>(Vector2D.linearCombination(0.5, vA, 0.5, vB),
+ return new EnclosingBall<>(vA.lerp(vB, 0.5),
0.5 * vA.distance(vB),
Arrays.asList(vA, vB));
}
diff --git a/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/euclidean/threed/SphereGeneratorTest.java b/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/euclidean/threed/SphereGeneratorTest.java
index 28fe2a5..df8fb86 100644
--- a/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/euclidean/threed/SphereGeneratorTest.java
+++ b/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/euclidean/threed/SphereGeneratorTest.java
@@ -184,10 +184,10 @@ class SphereGeneratorTest {
for (int i = 0; i < 100; ++i) {
final double d = 25 * random.nextDouble();
final double refRadius = 10 * random.nextDouble();
- final Vector3D refCenter = Vector3D.linearCombination(d, Vector3D.of(sr.nextVector()));
+ final Vector3D refCenter = Vector3D.of(sr.nextVector()).multiply(d);
final List<Vector3D> support = new ArrayList<>();
for (int j = 0; j < 5; ++j) {
- support.add(Vector3D.linearCombination(1.0, refCenter, refRadius, Vector3D.of(sr.nextVector())));
+ support.add(Vector3D.Sum.of(refCenter).addScaled(refRadius, Vector3D.of(sr.nextVector())).get());
}
// act
diff --git a/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/euclidean/threed/WelzlEncloser3DTest.java b/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/euclidean/threed/WelzlEncloser3DTest.java
index a7a580b..9561982 100644
--- a/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/euclidean/threed/WelzlEncloser3DTest.java
+++ b/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/euclidean/threed/WelzlEncloser3DTest.java
@@ -119,14 +119,14 @@ class WelzlEncloser3DTest {
// define the reference sphere we want to compute
final double d = 25 * random.nextDouble();
final double refRadius = 10 * random.nextDouble();
- final Vector3D refCenter = Vector3D.linearCombination(d, Vector3D.of(sr.nextVector()));
+ final Vector3D refCenter = Vector3D.of(sr.nextVector()).multiply(d);
// set up a large sample inside the reference sphere
final int nbPoints = random.nextInt(1000);
final List<Vector3D> points = new ArrayList<>();
for (int i = 0; i < nbPoints; ++i) {
final double r = refRadius * random.nextDouble();
- points.add(Vector3D.linearCombination(1.0, refCenter, r, Vector3D.of(sr.nextVector())));
+ points.add(Vector3D.Sum.of(refCenter).addScaled(r, Vector3D.of(sr.nextVector())).get());
}
// act/assert
diff --git a/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/euclidean/twod/DiskGeneratorTest.java b/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/euclidean/twod/DiskGeneratorTest.java
index e108d81..c3428d9 100644
--- a/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/euclidean/twod/DiskGeneratorTest.java
+++ b/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/euclidean/twod/DiskGeneratorTest.java
@@ -138,10 +138,10 @@ class DiskGeneratorTest {
for (int i = 0; i < 500; ++i) {
final double d = 25 * random.nextDouble();
final double refRadius = 10 * random.nextDouble();
- final Vector2D refCenter = Vector2D.linearCombination(d, Vector2D.of(sr.nextVector()));
+ final Vector2D refCenter = Vector2D.of(sr.nextVector()).multiply(d);
final List<Vector2D> support = new ArrayList<>();
for (int j = 0; j < 3; ++j) {
- support.add(Vector2D.linearCombination(1.0, refCenter, refRadius, Vector2D.of(sr.nextVector())));
+ support.add(Vector2D.Sum.of(refCenter).addScaled(refRadius, Vector2D.of(sr.nextVector())).get());
}
// act
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/EuclideanVectorSum.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/EuclideanVectorSum.java
new file mode 100644
index 0000000..5c537f5
--- /dev/null
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/EuclideanVectorSum.java
@@ -0,0 +1,51 @@
+/*
+ * 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.commons.geometry.euclidean;
+
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/** Class representing a sum of Euclidean vectors.
+ * @param <V> Vector implementation type
+ */
+public abstract class EuclideanVectorSum<V extends EuclideanVector<V>>
+ implements Supplier<V>, Consumer<V> {
+
+ /** Add a vector to this instance. This method is an alias for {@link #add(EuclideanVector)}.
+ * @param vec vector to add
+ */
+ @Override
+ public void accept(final V vec) {
+ add(vec);
+ }
+
+ /** Add a vector to this instance.
+ * @param vec vector to add
+ * @return this instance
+ */
+ public abstract EuclideanVectorSum<V> add(V vec);
+
+ /** Add a scaled vector to this instance. In general, the result produced by this method
+ * will be more accurate than if the vector was scaled first and then added directly. In other
+ * words, {@code sum.addScale(scale, vec)} will generally produce a better result than
+ * {@code sum.add(vec.multiply(scale))}.
+ * @param scale scale factor
+ * @param vec vector to scale and add
+ * @return this instance
+ */
+ public abstract EuclideanVectorSum<V> addScaled(double scale, V vec);
+}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/internal/Vectors.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/internal/Vectors.java
index 817e0b0..bd77d57 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/internal/Vectors.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/internal/Vectors.java
@@ -18,6 +18,7 @@ package org.apache.commons.geometry.euclidean.internal;
import org.apache.commons.geometry.core.Vector;
import org.apache.commons.numbers.core.Norm;
+import org.apache.commons.numbers.core.Sum;
/** This class consists exclusively of static vector utility methods.
*/
@@ -142,4 +143,38 @@ public final class Vectors {
public static double normSq(final double x1, final double x2, final double x3) {
return (x1 * x1) + (x2 * x2) + (x3 * x3);
}
+
+ /** Compute the linear combination \(a_1 b_1 + a_2 b_2 \) with high accuracy.
+ * @param a1 first factor of the first term
+ * @param b1 second factor of the first term
+ * @param a2 first factor of the second term
+ * @param b2 second factor of the seconf term
+ * @return linear combination.
+ * @see Sum
+ */
+ public static double linearCombination(final double a1, final double b1,
+ final double a2, final double b2) {
+ return Sum.create()
+ .addProduct(a1, b1)
+ .addProduct(a2, b2).getAsDouble();
+ }
+
+ /** Compute the linear combination \(a_1 b_1 + a_2 b_2 + a_3 b_3 \) with high accuracy.
+ * @param a1 first factor of the first term
+ * @param b1 second factor of the first term
+ * @param a2 first factor of the second term
+ * @param b2 second factor of the seconf term
+ * @param a3 first factor of the third term
+ * @param b3 second factor of the third term
+ * @return linear combination.
+ * @see Sum
+ */
+ public static double linearCombination(final double a1, final double b1,
+ final double a2, final double b2,
+ final double a3, final double b3) {
+ return Sum.create()
+ .addProduct(a1, b1)
+ .addProduct(a2, b2)
+ .addProduct(a3, b3).getAsDouble();
+ }
}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java
index cd6506d..56cec14 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java
@@ -21,8 +21,8 @@ import java.util.function.UnaryOperator;
import org.apache.commons.geometry.core.internal.SimpleTupleFormat;
import org.apache.commons.geometry.euclidean.EuclideanVector;
+import org.apache.commons.geometry.euclidean.EuclideanVectorSum;
import org.apache.commons.geometry.euclidean.internal.Vectors;
-import org.apache.commons.numbers.core.LinearCombination;
import org.apache.commons.numbers.core.Precision;
/** This class represents vectors and points in one-dimensional Euclidean space.
@@ -121,7 +121,9 @@ public class Vector1D extends EuclideanVector<Vector1D> {
/** {@inheritDoc} */
@Override
public Vector1D lerp(final Vector1D p, final double t) {
- return linearCombination(1.0 - t, this, t, p);
+ return Sum.create()
+ .addScaled(1.0 - t, this)
+ .addScaled(t, p).get();
}
/** {@inheritDoc} */
@@ -320,86 +322,6 @@ public class Vector1D extends EuclideanVector<Vector1D> {
return SimpleTupleFormat.getDefault().parse(str, Vector1D::new);
}
- /** Returns a vector consisting of the linear combination of the inputs.
- * <p>
- * A linear combination is the sum of all of the inputs multiplied by their
- * corresponding scale factors.
- * </p>
- *
- * @param a scale factor for first vector
- * @param c first vector
- * @return vector calculated by {@code a * c}
- */
- public static Vector1D linearCombination(final double a, final Vector1D c) {
- return new Vector1D(a * c.x);
- }
-
- /** Returns a vector consisting of the linear combination of the inputs.
- * <p>
- * A linear combination is the sum of all of the inputs multiplied by their
- * corresponding scale factors.
- * </p>
- *
- * @param a1 scale factor for first vector
- * @param v1 first vector
- * @param a2 scale factor for second vector
- * @param v2 second vector
- * @return vector calculated by {@code (a1 * v1) + (a2 * v2)}
- */
- public static Vector1D linearCombination(final double a1, final Vector1D v1,
- final double a2, final Vector1D v2) {
-
- return new Vector1D(
- LinearCombination.value(a1, v1.x, a2, v2.x));
- }
-
- /** Returns a vector consisting of the linear combination of the inputs.
- * <p>
- * A linear combination is the sum of all of the inputs multiplied by their
- * corresponding scale factors.
- * </p>
- *
- * @param a1 scale factor for first vector
- * @param v1 first vector
- * @param a2 scale factor for second vector
- * @param v2 second vector
- * @param a3 scale factor for third vector
- * @param v3 third vector
- * @return vector calculated by {@code (a1 * v1) + (a2 * v2) + (a3 * v3)}
- */
- public static Vector1D linearCombination(final double a1, final Vector1D v1,
- final double a2, final Vector1D v2,
- final double a3, final Vector1D v3) {
-
- return new Vector1D(
- LinearCombination.value(a1, v1.x, a2, v2.x, a3, v3.x));
- }
-
- /** Returns a vector consisting of the linear combination of the inputs.
- * <p>
- * A linear combination is the sum of all of the inputs multiplied by their
- * corresponding scale factors.
- * </p>
- *
- * @param a1 scale factor for first vector
- * @param v1 first vector
- * @param a2 scale factor for second vector
- * @param v2 second vector
- * @param a3 scale factor for third vector
- * @param v3 third vector
- * @param a4 scale factor for fourth vector
- * @param v4 fourth vector
- * @return vector calculated by {@code (a1 * v1) + (a2 * v2) + (a3 * v3) + (a4 * v4)}
- */
- public static Vector1D linearCombination(final double a1, final Vector1D v1,
- final double a2, final Vector1D v2,
- final double a3, final Vector1D v3,
- final double a4, final Vector1D v4) {
-
- return new Vector1D(
- LinearCombination.value(a1, v1.x, a2, v2.x, a3, v3.x, a4, v4.x));
- }
-
/**
* Represent unit vectors.
* This allows optimizations to be performed for certain operations.
@@ -494,4 +416,71 @@ public class Vector1D extends EuclideanVector<Vector1D> {
return null;
}
}
+
+ /** Class used to create high-accuracy sums of vectors. Each vector component is
+ * summed using an instance of {@link org.apache.commons.numbers.core.Sum}.
+ *
+ * <p>This class is mutable and not thread-safe.
+ * @see org.apache.commons.numbers.core.Sum
+ */
+ public static final class Sum extends EuclideanVectorSum<Vector1D> {
+
+ /** X component sum. */
+ private final org.apache.commons.numbers.core.Sum xsum;
+
+ /** Construct a new instance with the given initial value.
+ * @param initial initial value
+ */
+ Sum(final Vector1D initial) {
+ this.xsum = org.apache.commons.numbers.core.Sum.of(initial.x);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Sum add(final Vector1D vec) {
+ xsum.add(vec.x);
+ return this;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Sum addScaled(final double scale, final Vector1D vec) {
+ xsum.addProduct(scale, vec.x);
+ return this;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Vector1D get() {
+ return Vector1D.of(xsum.getAsDouble());
+ }
+
+ /** Create a new instance with an initial value set to the {@link Vector1D#ZERO zero vector}.
+ * @return new instance set to zero
+ */
+ public static Sum create() {
+ return new Sum(Vector1D.ZERO);
+ }
+
+ /** Construct a new instance with an initial value set to the argument.
+ * @param initial initial sum value
+ * @return new instance
+ */
+ public static Sum of(final Vector1D initial) {
+ return new Sum(initial);
+ }
+
+ /** Construct a new instance from multiple values.
+ * @param first first vector
+ * @param more additional vectors
+ * @return new instance
+ */
+ public static Sum of(final Vector1D first, final Vector1D... more) {
+ final Sum s = new Sum(first);
+ for (final Vector1D v : more) {
+ s.add(v);
+ }
+ return s;
+ }
+ }
}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/AffineTransformMatrix3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/AffineTransformMatrix3D.java
index d400728..a02ca3b 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/AffineTransformMatrix3D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/AffineTransformMatrix3D.java
@@ -23,7 +23,6 @@ import org.apache.commons.geometry.euclidean.AbstractAffineTransformMatrix;
import org.apache.commons.geometry.euclidean.internal.Matrices;
import org.apache.commons.geometry.euclidean.internal.Vectors;
import org.apache.commons.geometry.euclidean.threed.rotation.QuaternionRotation;
-import org.apache.commons.numbers.core.LinearCombination;
/** Class using a matrix to represent affine transformations in 3 dimensional Euclidean space.
*
@@ -235,7 +234,7 @@ public final class AffineTransformMatrix3D extends AbstractAffineTransformMatrix
* @see #applyVector(Vector3D)
*/
public double applyVectorX(final double x, final double y, final double z) {
- return LinearCombination.value(m00, x, m01, y, m02, z);
+ return Vectors.linearCombination(m00, x, m01, y, m02, z);
}
/** Apply this transform to the given vector coordinates, ignoring translations, and
@@ -248,7 +247,7 @@ public final class AffineTransformMatrix3D extends AbstractAffineTransformMatrix
* @see #applyVector(Vector3D)
*/
public double applyVectorY(final double x, final double y, final double z) {
- return LinearCombination.value(m10, x, m11, y, m12, z);
+ return Vectors.linearCombination(m10, x, m11, y, m12, z);
}
/** Apply this transform to the given vector coordinates, ignoring translations, and
@@ -261,7 +260,7 @@ public final class AffineTransformMatrix3D extends AbstractAffineTransformMatrix
* @see #applyVector(Vector3D)
*/
public double applyVectorZ(final double x, final double y, final double z) {
- return LinearCombination.value(m20, x, m21, y, m22, z);
+ return Vectors.linearCombination(m20, x, m21, y, m22, z);
}
/** {@inheritDoc}
@@ -753,20 +752,20 @@ public final class AffineTransformMatrix3D extends AbstractAffineTransformMatrix
final AffineTransformMatrix3D b) {
// calculate the matrix elements
- final double c00 = LinearCombination.value(a.m00, b.m00, a.m01, b.m10, a.m02, b.m20);
- final double c01 = LinearCombination.value(a.m00, b.m01, a.m01, b.m11, a.m02, b.m21);
- final double c02 = LinearCombination.value(a.m00, b.m02, a.m01, b.m12, a.m02, b.m22);
- final double c03 = LinearCombination.value(a.m00, b.m03, a.m01, b.m13, a.m02, b.m23) + a.m03;
-
- final double c10 = LinearCombination.value(a.m10, b.m00, a.m11, b.m10, a.m12, b.m20);
- final double c11 = LinearCombination.value(a.m10, b.m01, a.m11, b.m11, a.m12, b.m21);
- final double c12 = LinearCombination.value(a.m10, b.m02, a.m11, b.m12, a.m12, b.m22);
- final double c13 = LinearCombination.value(a.m10, b.m03, a.m11, b.m13, a.m12, b.m23) + a.m13;
-
- final double c20 = LinearCombination.value(a.m20, b.m00, a.m21, b.m10, a.m22, b.m20);
- final double c21 = LinearCombination.value(a.m20, b.m01, a.m21, b.m11, a.m22, b.m21);
- final double c22 = LinearCombination.value(a.m20, b.m02, a.m21, b.m12, a.m22, b.m22);
- final double c23 = LinearCombination.value(a.m20, b.m03, a.m21, b.m13, a.m22, b.m23) + a.m23;
+ final double c00 = Vectors.linearCombination(a.m00, b.m00, a.m01, b.m10, a.m02, b.m20);
+ final double c01 = Vectors.linearCombination(a.m00, b.m01, a.m01, b.m11, a.m02, b.m21);
+ final double c02 = Vectors.linearCombination(a.m00, b.m02, a.m01, b.m12, a.m02, b.m22);
+ final double c03 = Vectors.linearCombination(a.m00, b.m03, a.m01, b.m13, a.m02, b.m23) + a.m03;
+
+ final double c10 = Vectors.linearCombination(a.m10, b.m00, a.m11, b.m10, a.m12, b.m20);
+ final double c11 = Vectors.linearCombination(a.m10, b.m01, a.m11, b.m11, a.m12, b.m21);
+ final double c12 = Vectors.linearCombination(a.m10, b.m02, a.m11, b.m12, a.m12, b.m22);
+ final double c13 = Vectors.linearCombination(a.m10, b.m03, a.m11, b.m13, a.m12, b.m23) + a.m13;
+
+ final double c20 = Vectors.linearCombination(a.m20, b.m00, a.m21, b.m10, a.m22, b.m20);
+ final double c21 = Vectors.linearCombination(a.m20, b.m01, a.m21, b.m11, a.m22, b.m21);
+ final double c22 = Vectors.linearCombination(a.m20, b.m02, a.m21, b.m12, a.m22, b.m22);
+ final double c23 = Vectors.linearCombination(a.m20, b.m03, a.m21, b.m13, a.m22, b.m23) + a.m23;
return new AffineTransformMatrix3D(
c00, c01, c02, c03,
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/EmbeddingPlane.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/EmbeddingPlane.java
index a39c0d3..a31456c 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/EmbeddingPlane.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/EmbeddingPlane.java
@@ -127,10 +127,10 @@ public final class EmbeddingPlane extends Plane implements EmbeddingHyperplane<V
*/
@Override
public Vector3D toSpace(final Vector2D point) {
- return Vector3D.linearCombination(
- point.getX(), u,
- point.getY(), v,
- -getOriginOffset(), getNormal());
+ return Vector3D.Sum.create()
+ .addScaled(point.getX(), u)
+ .addScaled(point.getY(), v)
+ .addScaled(-getOriginOffset(), getNormal()).get();
}
/** Get one point from the 3D-space.
@@ -140,10 +140,10 @@ public final class EmbeddingPlane extends Plane implements EmbeddingHyperplane<V
* to the plane
*/
public Vector3D pointAt(final Vector2D inPlane, final double offset) {
- return Vector3D.linearCombination(
- inPlane.getX(), u,
- inPlane.getY(), v,
- offset - getOriginOffset(), getNormal());
+ return Vector3D.Sum.create()
+ .addScaled(inPlane.getX(), u)
+ .addScaled(inPlane.getY(), v)
+ .addScaled(offset - getOriginOffset(), getNormal()).get();
}
/** Build a new reversed version of this plane, with opposite orientation.
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Plane.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Plane.java
index 1556b07..6c63b75 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Plane.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Plane.java
@@ -227,9 +227,9 @@ public class Plane extends AbstractHyperplane<Vector3D> {
final Vector3D point = line.pointAt(0);
final double k = -(originOffset + normal.dot(point)) / dot;
- return Vector3D.linearCombination(
- 1.0, point,
- k, direction);
+ return Vector3D.Sum.of(point)
+ .addScaled(k, direction)
+ .get();
}
/** Get the line formed by the intersection of this instance with the given plane.
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java
index 9d7f4ce..ed389f0 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java
@@ -23,9 +23,9 @@ import java.util.function.UnaryOperator;
import org.apache.commons.geometry.core.internal.DoubleFunction3N;
import org.apache.commons.geometry.core.internal.SimpleTupleFormat;
+import org.apache.commons.geometry.euclidean.EuclideanVectorSum;
import org.apache.commons.geometry.euclidean.MultiDimensionalEuclideanVector;
import org.apache.commons.geometry.euclidean.internal.Vectors;
-import org.apache.commons.numbers.core.LinearCombination;
import org.apache.commons.numbers.core.Precision;
/** This class represents vectors and points in three-dimensional Euclidean space.
@@ -167,7 +167,9 @@ public class Vector3D extends MultiDimensionalEuclideanVector<Vector3D> {
/** {@inheritDoc} */
@Override
public Vector3D lerp(final Vector3D p, final double t) {
- return linearCombination(1.0 - t, this, t, p);
+ return Sum.create()
+ .addScaled(1.0 - t, this)
+ .addScaled(t, p).get();
}
/** {@inheritDoc} */
@@ -284,11 +286,14 @@ public class Vector3D extends MultiDimensionalEuclideanVector<Vector3D> {
* algorithms to preserve accuracy and reduce cancellation effects.
* It should be very accurate even for nearly orthogonal vectors.
* </p>
- * @see LinearCombination#value(double, double, double, double, double, double)
+ * @see org.apache.commons.numbers.core.Sum
*/
@Override
public double dot(final Vector3D v) {
- return LinearCombination.value(x, v.x, y, v.y, z, v.z);
+ return Vectors.linearCombination(
+ x, v.x,
+ y, v.y,
+ z, v.z);
}
/** {@inheritDoc}
@@ -372,9 +377,9 @@ public class Vector3D extends MultiDimensionalEuclideanVector<Vector3D> {
* @return the cross product this ^ v as a new Vector3D
*/
public Vector3D cross(final Vector3D v) {
- return new Vector3D(LinearCombination.value(y, v.z, -z, v.y),
- LinearCombination.value(z, v.x, -x, v.z),
- LinearCombination.value(x, v.y, -y, v.x));
+ return new Vector3D(Vectors.linearCombination(y, v.z, -z, v.y),
+ Vectors.linearCombination(z, v.x, -x, v.z),
+ Vectors.linearCombination(x, v.y, -y, v.x));
}
/** Convenience method to apply a function to this vector. This
@@ -643,109 +648,15 @@ public class Vector3D extends MultiDimensionalEuclideanVector<Vector3D> {
* @return the centroid of the point set
*/
private static Vector3D computeCentroid(final Vector3D first, final Iterator<? extends Vector3D> more) {
- double x = first.getX();
- double y = first.getY();
- double z = first.getZ();
-
+ final Sum sum = Sum.of(first);
int count = 1;
- Vector3D pt;
while (more.hasNext()) {
- pt = more.next();
-
- x += pt.getX();
- y += pt.getY();
- z += pt.getZ();
-
+ sum.add(more.next());
++count;
}
- final double invCount = 1.0 / count;
-
- return new Vector3D(invCount * x, invCount * y, invCount * z);
- }
-
- /** Returns a vector consisting of the linear combination of the inputs.
- * <p>
- * A linear combination is the sum of all of the inputs multiplied by their
- * corresponding scale factors.
- * </p>
- *
- * @param a scale factor for first vector
- * @param c first vector
- * @return vector calculated by {@code a * c}
- */
- public static Vector3D linearCombination(final double a, final Vector3D c) {
- return c.multiply(a);
- }
-
- /** Returns a vector consisting of the linear combination of the inputs.
- * <p>
- * A linear combination is the sum of all of the inputs multiplied by their
- * corresponding scale factors.
- * </p>
- *
- * @param a1 scale factor for first vector
- * @param v1 first vector
- * @param a2 scale factor for second vector
- * @param v2 second vector
- * @return vector calculated by {@code (a1 * v1) + (a2 * v2)}
- */
- public static Vector3D linearCombination(final double a1, final Vector3D v1,
- final double a2, final Vector3D v2) {
- return new Vector3D(
- LinearCombination.value(a1, v1.x, a2, v2.x),
- LinearCombination.value(a1, v1.y, a2, v2.y),
- LinearCombination.value(a1, v1.z, a2, v2.z));
- }
-
- /** Returns a vector consisting of the linear combination of the inputs.
- * <p>
- * A linear combination is the sum of all of the inputs multiplied by their
- * corresponding scale factors.
- * </p>
- *
- * @param a1 scale factor for first vector
- * @param v1 first vector
- * @param a2 scale factor for second vector
- * @param v2 second vector
- * @param a3 scale factor for third vector
- * @param v3 third vector
- * @return vector calculated by {@code (a1 * v1) + (a2 * v2) + (a3 * v3)}
- */
- public static Vector3D linearCombination(final double a1, final Vector3D v1,
- final double a2, final Vector3D v2,
- final double a3, final Vector3D v3) {
- return new Vector3D(
- LinearCombination.value(a1, v1.x, a2, v2.x, a3, v3.x),
- LinearCombination.value(a1, v1.y, a2, v2.y, a3, v3.y),
- LinearCombination.value(a1, v1.z, a2, v2.z, a3, v3.z));
- }
-
- /** Returns a vector consisting of the linear combination of the inputs.
- * <p>
- * A linear combination is the sum of all of the inputs multiplied by their
- * corresponding scale factors.
- * </p>
- *
- * @param a1 scale factor for first vector
- * @param v1 first vector
- * @param a2 scale factor for second vector
- * @param v2 second vector
- * @param a3 scale factor for third vector
- * @param v3 third vector
- * @param a4 scale factor for fourth vector
- * @param v4 fourth vector
- * @return vector calculated by {@code (a1 * v1) + (a2 * v2) + (a3 * v3) + (a4 * v4)}
- */
- public static Vector3D linearCombination(final double a1, final Vector3D v1,
- final double a2, final Vector3D v2,
- final double a3, final Vector3D v3,
- final double a4, final Vector3D v4) {
- return new Vector3D(
- LinearCombination.value(a1, v1.x, a2, v2.x, a3, v3.x, a4, v4.x),
- LinearCombination.value(a1, v1.y, a2, v2.y, a3, v3.y, a4, v4.y),
- LinearCombination.value(a1, v1.z, a2, v2.z, a3, v3.z, a4, v4.z));
+ return sum.get().multiply(1.0 / count);
}
/**
@@ -910,4 +821,83 @@ public class Vector3D extends MultiDimensionalEuclideanVector<Vector3D> {
return null;
}
}
+
+ /** Class used to create high-accuracy sums of vectors. Each vector component is
+ * summed using an instance of {@link org.apache.commons.numbers.core.Sum}.
+ *
+ * <p>This class is mutable and not thread-safe.
+ * @see org.apache.commons.numbers.core.Sum
+ */
+ public static final class Sum extends EuclideanVectorSum<Vector3D> {
+ /** X component sum. */
+ private final org.apache.commons.numbers.core.Sum xsum;
+ /** Y component sum. */
+ private final org.apache.commons.numbers.core.Sum ysum;
+ /** Z component sum. */
+ private final org.apache.commons.numbers.core.Sum zsum;
+
+ /** Construct a new instance with the given initial value.
+ * @param initial initial value
+ */
+ Sum(final Vector3D initial) {
+ this.xsum = org.apache.commons.numbers.core.Sum.of(initial.x);
+ this.ysum = org.apache.commons.numbers.core.Sum.of(initial.y);
+ this.zsum = org.apache.commons.numbers.core.Sum.of(initial.z);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Sum add(final Vector3D vec) {
+ xsum.add(vec.x);
+ ysum.add(vec.y);
+ zsum.add(vec.z);
+ return this;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Sum addScaled(final double scale, final Vector3D vec) {
+ xsum.addProduct(scale, vec.x);
+ ysum.addProduct(scale, vec.y);
+ zsum.addProduct(scale, vec.z);
+ return this;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Vector3D get() {
+ return Vector3D.of(
+ xsum.getAsDouble(),
+ ysum.getAsDouble(),
+ zsum.getAsDouble());
+ }
+
+ /** Create a new instance with an initial value set to the {@link Vector3D#ZERO zero vector}.
+ * @return new instance set to zero
+ */
+ public static Sum create() {
+ return new Sum(Vector3D.ZERO);
+ }
+
+ /** Construct a new instance with an initial value set to the argument.
+ * @param initial initial sum value
+ * @return new instance
+ */
+ public static Sum of(final Vector3D initial) {
+ return new Sum(initial);
+ }
+
+ /** Construct a new instance from multiple values.
+ * @param first first vector
+ * @param more additional vectors
+ * @return new instance
+ */
+ public static Sum of(final Vector3D first, final Vector3D... more) {
+ final Sum s = new Sum(first);
+ for (final Vector3D v : more) {
+ s.add(v);
+ }
+ return s;
+ }
+ }
}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/Line3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/Line3D.java
index 7d334ca..033a286 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/Line3D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/Line3D.java
@@ -156,7 +156,9 @@ public final class Line3D implements Embedding<Vector3D, Vector1D> {
* @return one point belonging to the line, at specified abscissa
*/
public Vector3D pointAt(final double abscissa) {
- return Vector3D.linearCombination(1.0, origin, abscissa, direction);
+ return Vector3D.Sum.of(origin)
+ .addScaled(abscissa, direction)
+ .get();
}
/** {@inheritDoc} */
@@ -251,7 +253,9 @@ public final class Line3D implements Embedding<Vector3D, Vector1D> {
final double a = delta.dot(direction);
final double b = delta.dot(line.direction);
- return Vector3D.linearCombination(1, origin, (a - (b * cos)) / n, direction);
+ return Vector3D.Sum.of(origin)
+ .addScaled((a - (b * cos)) / n, direction)
+ .get();
}
/** Get the intersection point of the instance and another line.
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/rotation/QuaternionRotation.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/rotation/QuaternionRotation.java
index f00aa65..4317bd8 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/rotation/QuaternionRotation.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/rotation/QuaternionRotation.java
@@ -24,7 +24,6 @@ import org.apache.commons.geometry.euclidean.internal.Vectors;
import org.apache.commons.geometry.euclidean.threed.AffineTransformMatrix3D;
import org.apache.commons.geometry.euclidean.threed.Vector3D;
import org.apache.commons.numbers.angle.Angle;
-import org.apache.commons.numbers.core.LinearCombination;
import org.apache.commons.numbers.quaternion.Quaternion;
import org.apache.commons.numbers.quaternion.Slerp;
@@ -698,17 +697,17 @@ public final class QuaternionRotation implements Rotation3D {
// be the multiplication of the matrix composed of the column vectors d, e, f and the
// inverse of the matrix composed of the column vectors a, b, c (which is simply the transpose since
// it's orthogonal).
- final double m00 = LinearCombination.value(d.getX(), a.getX(), e.getX(), b.getX(), f.getX(), c.getX());
- final double m01 = LinearCombination.value(d.getX(), a.getY(), e.getX(), b.getY(), f.getX(), c.getY());
- final double m02 = LinearCombination.value(d.getX(), a.getZ(), e.getX(), b.getZ(), f.getX(), c.getZ());
+ final double m00 = Vectors.linearCombination(d.getX(), a.getX(), e.getX(), b.getX(), f.getX(), c.getX());
+ final double m01 = Vectors.linearCombination(d.getX(), a.getY(), e.getX(), b.getY(), f.getX(), c.getY());
+ final double m02 = Vectors.linearCombination(d.getX(), a.getZ(), e.getX(), b.getZ(), f.getX(), c.getZ());
- final double m10 = LinearCombination.value(d.getY(), a.getX(), e.getY(), b.getX(), f.getY(), c.getX());
- final double m11 = LinearCombination.value(d.getY(), a.getY(), e.getY(), b.getY(), f.getY(), c.getY());
- final double m12 = LinearCombination.value(d.getY(), a.getZ(), e.getY(), b.getZ(), f.getY(), c.getZ());
+ final double m10 = Vectors.linearCombination(d.getY(), a.getX(), e.getY(), b.getX(), f.getY(), c.getX());
+ final double m11 = Vectors.linearCombination(d.getY(), a.getY(), e.getY(), b.getY(), f.getY(), c.getY());
+ final double m12 = Vectors.linearCombination(d.getY(), a.getZ(), e.getY(), b.getZ(), f.getY(), c.getZ());
- final double m20 = LinearCombination.value(d.getZ(), a.getX(), e.getZ(), b.getX(), f.getZ(), c.getX());
- final double m21 = LinearCombination.value(d.getZ(), a.getY(), e.getZ(), b.getY(), f.getZ(), c.getY());
- final double m22 = LinearCombination.value(d.getZ(), a.getZ(), e.getZ(), b.getZ(), f.getZ(), c.getZ());
+ final double m20 = Vectors.linearCombination(d.getZ(), a.getX(), e.getZ(), b.getX(), f.getZ(), c.getX());
+ final double m21 = Vectors.linearCombination(d.getZ(), a.getY(), e.getZ(), b.getY(), f.getZ(), c.getY());
+ final double m22 = Vectors.linearCombination(d.getZ(), a.getZ(), e.getZ(), b.getZ(), f.getZ(), c.getZ());
return orthogonalRotationMatrixToQuaternion(
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/AffineTransformMatrix2D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/AffineTransformMatrix2D.java
index 08d1f1a..f7428d5 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/AffineTransformMatrix2D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/AffineTransformMatrix2D.java
@@ -23,7 +23,6 @@ import org.apache.commons.geometry.euclidean.AbstractAffineTransformMatrix;
import org.apache.commons.geometry.euclidean.internal.Matrices;
import org.apache.commons.geometry.euclidean.internal.Vectors;
import org.apache.commons.geometry.euclidean.twod.rotation.Rotation2D;
-import org.apache.commons.numbers.core.LinearCombination;
/** Class using a matrix to represent affine transformations in 2 dimensional Euclidean space.
*
@@ -185,7 +184,7 @@ public final class AffineTransformMatrix2D extends AbstractAffineTransformMatrix
* @see #applyVector(Vector2D)
*/
public double applyVectorX(final double x, final double y) {
- return LinearCombination.value(m00, x, m01, y);
+ return Vectors.linearCombination(m00, x, m01, y);
}
/** Apply this transform to the given vector coordinates, ignoring translations, and
@@ -197,7 +196,7 @@ public final class AffineTransformMatrix2D extends AbstractAffineTransformMatrix
* @see #applyVector(Vector2D)
*/
public double applyVectorY(final double x, final double y) {
- return LinearCombination.value(m10, x, m11, y);
+ return Vectors.linearCombination(m10, x, m11, y);
}
/** {@inheritDoc}
@@ -702,13 +701,13 @@ public final class AffineTransformMatrix2D extends AbstractAffineTransformMatrix
private static AffineTransformMatrix2D multiply(final AffineTransformMatrix2D a,
final AffineTransformMatrix2D b) {
- final double c00 = LinearCombination.value(a.m00, b.m00, a.m01, b.m10);
- final double c01 = LinearCombination.value(a.m00, b.m01, a.m01, b.m11);
- final double c02 = LinearCombination.value(a.m00, b.m02, a.m01, b.m12) + a.m02;
+ final double c00 = Vectors.linearCombination(a.m00, b.m00, a.m01, b.m10);
+ final double c01 = Vectors.linearCombination(a.m00, b.m01, a.m01, b.m11);
+ final double c02 = Vectors.linearCombination(a.m00, b.m02, a.m01, b.m12) + a.m02;
- final double c10 = LinearCombination.value(a.m10, b.m00, a.m11, b.m10);
- final double c11 = LinearCombination.value(a.m10, b.m01, a.m11, b.m11);
- final double c12 = LinearCombination.value(a.m10, b.m02, a.m11, b.m12) + a.m12;
+ final double c10 = Vectors.linearCombination(a.m10, b.m00, a.m11, b.m10);
+ final double c11 = Vectors.linearCombination(a.m10, b.m01, a.m11, b.m11);
+ final double c12 = Vectors.linearCombination(a.m10, b.m02, a.m11, b.m12) + a.m12;
return new AffineTransformMatrix2D(
c00, c01, c02,
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Line.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Line.java
index 0398d39..43deba2 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Line.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Line.java
@@ -23,10 +23,10 @@ import org.apache.commons.geometry.core.Transform;
import org.apache.commons.geometry.core.partitioning.AbstractHyperplane;
import org.apache.commons.geometry.core.partitioning.EmbeddingHyperplane;
import org.apache.commons.geometry.core.partitioning.Hyperplane;
+import org.apache.commons.geometry.euclidean.internal.Vectors;
import org.apache.commons.geometry.euclidean.oned.AffineTransformMatrix1D;
import org.apache.commons.geometry.euclidean.oned.Vector1D;
import org.apache.commons.numbers.angle.Angle;
-import org.apache.commons.numbers.core.LinearCombination;
import org.apache.commons.numbers.core.Precision;
/** This class represents an oriented line in the 2D plane.
@@ -298,8 +298,8 @@ public final class Line extends AbstractHyperplane<Vector2D>
// step below given that the origin location is equal to
// (-direction.y * originOffset, direction.x * originOffset).
return Vector2D.of(
- LinearCombination.value(abscissa, direction.getX(), -originOffset, direction.getY()),
- LinearCombination.value(abscissa, direction.getY(), originOffset, direction.getX())
+ Vectors.linearCombination(abscissa, direction.getX(), -originOffset, direction.getY()),
+ Vectors.linearCombination(abscissa, direction.getY(), originOffset, direction.getX())
);
}
@@ -316,11 +316,11 @@ public final class Line extends AbstractHyperplane<Vector2D>
return null;
}
- final double x = LinearCombination.value(
+ final double x = Vectors.linearCombination(
other.direction.getX(), originOffset,
-direction.getX(), other.originOffset) / area;
- final double y = LinearCombination.value(
+ final double y = Vectors.linearCombination(
other.direction.getY(), originOffset,
-direction.getY(), other.originOffset) / area;
@@ -400,8 +400,8 @@ public final class Line extends AbstractHyperplane<Vector2D>
*/
public Vector2D pointAt(final double abscissa, final double offset) {
final double pointOffset = offset - originOffset;
- return Vector2D.of(LinearCombination.value(abscissa, direction.getX(), pointOffset, direction.getY()),
- LinearCombination.value(abscissa, direction.getY(), -pointOffset, direction.getX()));
+ return Vector2D.of(Vectors.linearCombination(abscissa, direction.getX(), pointOffset, direction.getY()),
+ Vectors.linearCombination(abscissa, direction.getY(), -pointOffset, direction.getX()));
}
/** Check if the line contains a point.
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java
index ab32f9b..10b0ff8 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java
@@ -23,9 +23,9 @@ import java.util.function.UnaryOperator;
import org.apache.commons.geometry.core.internal.DoubleFunction2N;
import org.apache.commons.geometry.core.internal.SimpleTupleFormat;
+import org.apache.commons.geometry.euclidean.EuclideanVectorSum;
import org.apache.commons.geometry.euclidean.MultiDimensionalEuclideanVector;
import org.apache.commons.geometry.euclidean.internal.Vectors;
-import org.apache.commons.numbers.core.LinearCombination;
import org.apache.commons.numbers.core.Precision;
/** This class represents vectors and points in two-dimensional Euclidean space.
@@ -145,7 +145,9 @@ public class Vector2D extends MultiDimensionalEuclideanVector<Vector2D> {
/** {@inheritDoc} */
@Override
public Vector2D lerp(final Vector2D p, final double t) {
- return linearCombination(1.0 - t, this, t, p);
+ return Sum.create()
+ .addScaled(1.0 - t, this)
+ .addScaled(t, p).get();
}
/** {@inheritDoc} */
@@ -240,7 +242,7 @@ public class Vector2D extends MultiDimensionalEuclideanVector<Vector2D> {
/** {@inheritDoc} */
@Override
public double dot(final Vector2D v) {
- return LinearCombination.value(x, v.x, y, v.y);
+ return Vectors.linearCombination(x, v.x, y, v.y);
}
/** {@inheritDoc}
@@ -258,7 +260,7 @@ public class Vector2D extends MultiDimensionalEuclideanVector<Vector2D> {
final double threshold = normProduct * 0.9999;
if ((dot < -threshold) || (dot > threshold)) {
// the vectors are almost aligned, compute using the sine
- final double n = Math.abs(LinearCombination.value(x, v.y, -y, v.x));
+ final double n = Math.abs(Vectors.linearCombination(x, v.y, -y, v.x));
if (dot >= 0) {
return Math.asin(n / normProduct);
}
@@ -315,7 +317,7 @@ public class Vector2D extends MultiDimensionalEuclideanVector<Vector2D> {
* @return the signed area of the parallelogram formed by this instance and the given vector
*/
public double signedArea(final Vector2D v) {
- return LinearCombination.value(
+ return Vectors.linearCombination(
x, v.y,
-y, v.x);
}
@@ -578,104 +580,15 @@ public class Vector2D extends MultiDimensionalEuclideanVector<Vector2D> {
* @return the centroid of the point set
*/
private static Vector2D computeCentroid(final Vector2D first, final Iterator<? extends Vector2D> more) {
- double x = first.getX();
- double y = first.getY();
-
+ final Sum sum = Sum.of(first);
int count = 1;
- Vector2D pt;
while (more.hasNext()) {
- pt = more.next();
-
- x += pt.getX();
- y += pt.getY();
-
+ sum.add(more.next());
++count;
}
- final double invCount = 1.0 / count;
-
- return new Vector2D(invCount * x, invCount * y);
- }
-
- /** Returns a vector consisting of the linear combination of the inputs.
- * <p>
- * A linear combination is the sum of all of the inputs multiplied by their
- * corresponding scale factors.
- * </p>
- *
- * @param a scale factor for first vector
- * @param c first vector
- * @return vector calculated by {@code a * c}
- */
- public static Vector2D linearCombination(final double a, final Vector2D c) {
- return new Vector2D(a * c.x, a * c.y);
- }
-
- /** Returns a vector consisting of the linear combination of the inputs.
- * <p>
- * A linear combination is the sum of all of the inputs multiplied by their
- * corresponding scale factors.
- * </p>
- *
- * @param a1 scale factor for first vector
- * @param v1 first vector
- * @param a2 scale factor for second vector
- * @param v2 second vector
- * @return vector calculated by {@code (a1 * v1) + (a2 * v2)}
- */
- public static Vector2D linearCombination(final double a1, final Vector2D v1,
- final double a2, final Vector2D v2) {
- return new Vector2D(
- LinearCombination.value(a1, v1.x, a2, v2.x),
- LinearCombination.value(a1, v1.y, a2, v2.y));
- }
-
- /** Returns a vector consisting of the linear combination of the inputs.
- * <p>
- * A linear combination is the sum of all of the inputs multiplied by their
- * corresponding scale factors.
- * </p>
- *
- * @param a1 scale factor for first vector
- * @param v1 first vector
- * @param a2 scale factor for second vector
- * @param v2 second vector
- * @param a3 scale factor for third vector
- * @param v3 third vector
- * @return vector calculated by {@code (a1 * v1) + (a2 * v2) + (a3 * v3)}
- */
- public static Vector2D linearCombination(final double a1, final Vector2D v1,
- final double a2, final Vector2D v2,
- final double a3, final Vector2D v3) {
- return new Vector2D(
- LinearCombination.value(a1, v1.x, a2, v2.x, a3, v3.x),
- LinearCombination.value(a1, v1.y, a2, v2.y, a3, v3.y));
- }
-
- /** Returns a vector consisting of the linear combination of the inputs.
- * <p>
- * A linear combination is the sum of all of the inputs multiplied by their
- * corresponding scale factors.
- * </p>
- *
- * @param a1 scale factor for first vector
- * @param v1 first vector
- * @param a2 scale factor for second vector
- * @param v2 second vector
- * @param a3 scale factor for third vector
- * @param v3 third vector
- * @param a4 scale factor for fourth vector
- * @param v4 fourth vector
- * @return vector calculated by {@code (a1 * v1) + (a2 * v2) + (a3 * v3) + (a4 * v4)}
- */
- public static Vector2D linearCombination(final double a1, final Vector2D v1,
- final double a2, final Vector2D v2,
- final double a3, final Vector2D v3,
- final double a4, final Vector2D v4) {
- return new Vector2D(
- LinearCombination.value(a1, v1.x, a2, v2.x, a3, v3.x, a4, v4.x),
- LinearCombination.value(a1, v1.y, a2, v2.y, a3, v3.y, a4, v4.y));
+ return sum.get().multiply(1.0 / count);
}
/**
@@ -830,4 +743,77 @@ public class Vector2D extends MultiDimensionalEuclideanVector<Vector2D> {
return null;
}
}
+
+ /** Class used to create high-accuracy sums of vectors. Each vector component is
+ * summed using an instance of {@link org.apache.commons.numbers.core.Sum}.
+ *
+ * <p>This class is mutable and not thread-safe.
+ * @see org.apache.commons.numbers.core.Sum
+ */
+ public static final class Sum extends EuclideanVectorSum<Vector2D> {
+ /** X component sum. */
+ private final org.apache.commons.numbers.core.Sum xsum;
+ /** Y component sum. */
+ private final org.apache.commons.numbers.core.Sum ysum;
+
+ /** Construct a new instance with the given initial value.
+ * @param initial initial value
+ */
+ Sum(final Vector2D initial) {
+ this.xsum = org.apache.commons.numbers.core.Sum.of(initial.x);
+ this.ysum = org.apache.commons.numbers.core.Sum.of(initial.y);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Sum add(final Vector2D vec) {
+ xsum.add(vec.x);
+ ysum.add(vec.y);
+ return this;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Sum addScaled(final double scale, final Vector2D vec) {
+ xsum.addProduct(scale, vec.x);
+ ysum.addProduct(scale, vec.y);
+ return this;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Vector2D get() {
+ return Vector2D.of(
+ xsum.getAsDouble(),
+ ysum.getAsDouble());
+ }
+
+ /** Create a new instance with an initial value set to the {@link Vector2D#ZERO zero vector}.
+ * @return new instance set to zero
+ */
+ public static Sum create() {
+ return new Sum(Vector2D.ZERO);
+ }
+
+ /** Construct a new instance with an initial value set to the argument.
+ * @param initial initial sum value
+ * @return new instance
+ */
+ public static Sum of(final Vector2D initial) {
+ return new Sum(initial);
+ }
+
+ /** Construct a new instance from multiple values.
+ * @param first first vector
+ * @param more additional vectors
+ * @return new instance
+ */
+ public static Sum of(final Vector2D first, final Vector2D... more) {
+ final Sum s = new Sum(first);
+ for (final Vector2D v : more) {
+ s.add(v);
+ }
+ return s;
+ }
+ }
}
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Vector1DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Vector1DTest.java
index ced992f..4bd8e61 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Vector1DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/Vector1DTest.java
@@ -16,7 +16,9 @@
*/
package org.apache.commons.geometry.euclidean.oned;
+import java.util.Arrays;
import java.util.Comparator;
+import java.util.List;
import java.util.regex.Pattern;
import org.apache.commons.geometry.core.GeometryTestUtils;
@@ -706,49 +708,45 @@ class Vector1DTest {
}
@Test
- void testLinearCombination() {
+ void testSum_factoryMethods() {
// act/assert
- checkVector(Vector1D.linearCombination(2, Vector1D.of(3)), 6);
- checkVector(Vector1D.linearCombination(-2, Vector1D.of(3)), -6);
+ checkVector(Vector1D.Sum.create().get(), 0);
+ checkVector(Vector1D.Sum.of(Vector1D.of(2)).get(), 2);
+ checkVector(Vector1D.Sum.of(
+ Vector1D.of(-2),
+ Vector1D.Unit.PLUS).get(), -1);
}
@Test
- void testLinearCombination2() {
- // act/assert
- checkVector(Vector1D.linearCombination(
- 2, Vector1D.of(3),
- 5, Vector1D.of(7)), 41);
- checkVector(Vector1D.linearCombination(
- 2, Vector1D.of(3),
- -5, Vector1D.of(7)), -29);
- }
+ void testSum_instanceMethods() {
+ // arrange
+ final Vector1D p1 = Vector1D.of(-1);
+ final Vector1D p2 = Vector1D.of(4);
- @Test
- void testLinearCombination3() {
// act/assert
- checkVector(Vector1D.linearCombination(
- 2, Vector1D.of(3),
- 5, Vector1D.of(7),
- 11, Vector1D.of(13)), 184);
- checkVector(Vector1D.linearCombination(
- 2, Vector1D.of(3),
- 5, Vector1D.of(7),
- -11, Vector1D.of(13)), -102);
+ checkVector(Vector1D.Sum.create()
+ .add(p1)
+ .addScaled(0.5, p2)
+ .get(), 1);
}
@Test
- void testLinearCombination4() {
+ void testSum_accept() {
+ // arrange
+ final Vector1D p1 = Vector1D.of(2);
+ final Vector1D p2 = Vector1D.of(-3);
+
+ final List<Vector1D.Unit> units = Arrays.asList(
+ Vector1D.Unit.MINUS);
+
+ final Vector1D.Sum s = Vector1D.Sum.create();
+
// act/assert
- checkVector(Vector1D.linearCombination(
- 2, Vector1D.of(3),
- 5, Vector1D.of(7),
- 11, Vector1D.of(13),
- 17, Vector1D.of(19)), 507);
- checkVector(Vector1D.linearCombination(
- 2, Vector1D.of(3),
- 5, Vector1D.of(7),
- 11, Vector1D.of(13),
- -17, Vector1D.of(19)), -139);
+ Arrays.asList(p1, Vector1D.ZERO, p2).forEach(s);
+ units.forEach(s);
+
+ // assert
+ checkVector(s.get(), -2);
}
@Test
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/EmbeddingPlaneTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/EmbeddingPlaneTest.java
index 7f01fb7..6f35074 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/EmbeddingPlaneTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/EmbeddingPlaneTest.java
@@ -280,17 +280,19 @@ class EmbeddingPlaneTest {
EmbeddingPlane plane = Planes.fromPoints(p1, p2, p3, TEST_PRECISION).getEmbedding();
// act/assert
- plane = plane.translate(Vector3D.linearCombination(2.0, plane.getU(), -1.5, plane.getV()));
+ plane = plane.translate(Vector3D.Sum.create()
+ .addScaled(2.0, plane.getU())
+ .addScaled(-1.5, plane.getV()).get());
Assertions.assertTrue(plane.contains(p1));
Assertions.assertTrue(plane.contains(p2));
Assertions.assertTrue(plane.contains(p3));
- plane = plane.translate(Vector3D.linearCombination(-1.2, plane.getNormal()));
+ plane = plane.translate(plane.getNormal().multiply(-1.2));
Assertions.assertFalse(plane.contains(p1));
Assertions.assertFalse(plane.contains(p2));
Assertions.assertFalse(plane.contains(p3));
- plane = plane.translate(Vector3D.linearCombination(+1.2, plane.getNormal()));
+ plane = plane.translate(plane.getNormal().multiply(+1.2));
Assertions.assertTrue(plane.contains(p1));
Assertions.assertTrue(plane.contains(p2));
Assertions.assertTrue(plane.contains(p3));
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PlaneTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PlaneTest.java
index 17d7a8b..b9393ba 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PlaneTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PlaneTest.java
@@ -490,10 +490,10 @@ class PlaneTest {
Assertions.assertEquals(-5.0, plane.offset(Vector3D.of(-4, 0, 0)), TEST_EPS);
Assertions.assertEquals(+5.0, plane.offset(Vector3D.of(6, 10, -12)), TEST_EPS);
Assertions.assertEquals(0.3,
- plane.offset(Vector3D.linearCombination(1.0, p1, 0.3, plane.getNormal())),
+ plane.offset(Vector3D.Sum.of(p1).addScaled(0.3, plane.getNormal()).get()),
TEST_EPS);
Assertions.assertEquals(-0.3,
- plane.offset(Vector3D.linearCombination(1.0, p1, -0.3, plane.getNormal())),
+ plane.offset(Vector3D.Sum.of(p1).addScaled(-0.3, plane.getNormal()).get()),
TEST_EPS);
}
@@ -701,17 +701,17 @@ class PlaneTest {
Plane plane = Planes.fromPoints(p1, p2, p3, TEST_PRECISION);
// act/assert
- plane = plane.translate(Vector3D.linearCombination(2.0, plane.getNormal().orthogonal()));
+ plane = plane.translate(plane.getNormal().orthogonal().multiply(2.0));
Assertions.assertTrue(plane.contains(p1));
Assertions.assertTrue(plane.contains(p2));
Assertions.assertTrue(plane.contains(p3));
- plane = plane.translate(Vector3D.linearCombination(-1.2, plane.getNormal()));
+ plane = plane.translate(plane.getNormal().multiply(-1.2));
Assertions.assertFalse(plane.contains(p1));
Assertions.assertFalse(plane.contains(p2));
Assertions.assertFalse(plane.contains(p3));
- plane = plane.translate(Vector3D.linearCombination(+1.2, plane.getNormal()));
+ plane = plane.translate(plane.getNormal().multiply(+1.2));
Assertions.assertTrue(plane.contains(p1));
Assertions.assertTrue(plane.contains(p2));
Assertions.assertTrue(plane.contains(p3));
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/RegionBSPTree3DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/RegionBSPTree3DTest.java
index 7364465..2f6f0b8 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/RegionBSPTree3DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/RegionBSPTree3DTest.java
@@ -1246,10 +1246,10 @@ class RegionBSPTree3DTest {
final double third = 1.0 / 3.0;
EuclideanTestUtils.assertRegionLocation(tree, RegionLocation.BOUNDARY,
vertex1, vertex2, vertex3, vertex4,
- Vector3D.linearCombination(third, vertex1, third, vertex2, third, vertex3),
- Vector3D.linearCombination(third, vertex2, third, vertex3, third, vertex4),
- Vector3D.linearCombination(third, vertex3, third, vertex4, third, vertex1),
- Vector3D.linearCombination(third, vertex4, third, vertex1, third, vertex2)
+ Vector3D.Sum.create().addScaled(third, vertex1).addScaled(third, vertex2).addScaled(third, vertex3).get(),
+ Vector3D.Sum.create().addScaled(third, vertex2).addScaled(third, vertex3).addScaled(third, vertex4).get(),
+ Vector3D.Sum.create().addScaled(third, vertex3).addScaled(third, vertex4).addScaled(third, vertex1).get(),
+ Vector3D.Sum.create().addScaled(third, vertex4).addScaled(third, vertex1).addScaled(third, vertex2).get()
);
EuclideanTestUtils.assertRegionLocation(tree, RegionLocation.OUTSIDE,
Vector3D.of(1, 2, 4),
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Vector3DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Vector3DTest.java
index b1446e6..02e5642 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Vector3DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/Vector3DTest.java
@@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
+import java.util.List;
import java.util.regex.Pattern;
import org.apache.commons.geometry.core.GeometryTestUtils;
@@ -670,8 +671,8 @@ class Vector3DTest {
checkVector(v1.cross(v2), -1, 2, 1);
final double scale = Math.scalb(1.0, 100);
- final Vector3D big1 = Vector3D.linearCombination(scale, v1);
- final Vector3D small2 = Vector3D.linearCombination(1 / scale, v2);
+ final Vector3D big1 = v1.multiply(scale);
+ final Vector3D small2 = v2.multiply(1 / scale);
checkVector(big1.cross(small2), -1, 2, 1);
}
@@ -1315,54 +1316,49 @@ class Vector3DTest {
}
@Test
- void testLinearCombination1() {
- // arrange
- final Vector3D p1 = Vector3D.of(1, 2, 3);
-
+ void testSum_factoryMethods() {
// act/assert
- checkVector(Vector3D.linearCombination(0, p1), 0, 0, 0);
-
- checkVector(Vector3D.linearCombination(1, p1), 1, 2, 3);
- checkVector(Vector3D.linearCombination(-1, p1), -1, -2, -3);
-
- checkVector(Vector3D.linearCombination(0.5, p1), 0.5, 1, 1.5);
- checkVector(Vector3D.linearCombination(-0.5, p1), -0.5, -1, -1.5);
+ checkVector(Vector3D.Sum.create().get(), 0, 0, 0);
+ checkVector(Vector3D.Sum.of(Vector3D.of(1, 2, 3)).get(), 1, 2, 3);
+ checkVector(Vector3D.Sum.of(
+ Vector3D.of(1, 2, 3),
+ Vector3D.Unit.PLUS_X,
+ Vector3D.Unit.PLUS_Y,
+ Vector3D.Unit.PLUS_Z).get(), 2, 3, 4);
}
@Test
- void testLinearCombination2() {
+ void testSum_instanceMethods() {
// arrange
final Vector3D p1 = Vector3D.of(1, 2, 3);
- final Vector3D p2 = Vector3D.of(-3, -4, -5);
+ final Vector3D p2 = Vector3D.of(4, 6, 8);
// act/assert
- checkVector(Vector3D.linearCombination(2, p1, -3, p2), 11, 16, 21);
- checkVector(Vector3D.linearCombination(-3, p1, 2, p2), -9, -14, -19);
+ checkVector(Vector3D.Sum.create()
+ .add(p1)
+ .addScaled(0.5, p2)
+ .get(), 3, 5, 7);
}
@Test
- void testLinearCombination3() {
+ void testSum_accept() {
// arrange
- final Vector3D p1 = Vector3D.of(1, 2, 3);
- final Vector3D p2 = Vector3D.of(-3, -4, -5);
- final Vector3D p3 = Vector3D.of(5, 6, 7);
+ final Vector3D p1 = Vector3D.of(1, 2, -3);
+ final Vector3D p2 = Vector3D.of(3, -6, 8);
- // act/assert
- checkVector(Vector3D.linearCombination(2, p1, -3, p2, 4, p3), 31, 40, 49);
- checkVector(Vector3D.linearCombination(-3, p1, 2, p2, -4, p3), -29, -38, -47);
- }
+ final List<Vector3D.Unit> units = Arrays.asList(
+ Vector3D.Unit.PLUS_X,
+ Vector3D.Unit.PLUS_Y,
+ Vector3D.Unit.PLUS_Z);
- @Test
- void testLinearCombination4() {
- // arrange
- final Vector3D p1 = Vector3D.of(1, 2, 3);
- final Vector3D p2 = Vector3D.of(-3, -4, -5);
- final Vector3D p3 = Vector3D.of(5, 6, 7);
- final Vector3D p4 = Vector3D.of(-7, -8, 9);
+ final Vector3D.Sum s = Vector3D.Sum.create();
// act/assert
- checkVector(Vector3D.linearCombination(2, p1, -3, p2, 4, p3, -5, p4), 66, 80, 4);
- checkVector(Vector3D.linearCombination(-3, p1, 2, p2, -4, p3, 5, p4), -64, -78, -2);
+ Arrays.asList(p1, Vector3D.ZERO, p2).forEach(s);
+ units.forEach(s);
+
+ // assert
+ checkVector(s.get(), 5, -3, 6);
}
@Test
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/line/Line3DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/line/Line3DTest.java
index 71fa6f9..684d3d0 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/line/Line3DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/line/Line3DTest.java
@@ -232,12 +232,12 @@ class Line3DTest {
final Vector3D p1 = Vector3D.of(0, 0, 1);
final Line3D l = Lines3D.fromPoints(p1, Vector3D.of(0, 0, 2), TEST_PRECISION);
Assertions.assertTrue(l.contains(p1));
- Assertions.assertTrue(l.contains(Vector3D.linearCombination(1.0, p1, 0.3, l.getDirection())));
+ Assertions.assertTrue(l.contains(Vector3D.Sum.of(p1).addScaled(0.3, l.getDirection()).get()));
final Vector3D u = l.getDirection().orthogonal();
final Vector3D v = l.getDirection().cross(u);
for (double alpha = 0; alpha < 2 * Math.PI; alpha += 0.3) {
- Assertions.assertFalse(l.contains(p1.add(Vector3D.linearCombination(Math.cos(alpha), u,
- Math.sin(alpha), v))));
+ Assertions.assertFalse(l.contains(p1.add(Vector3D.Sum.create().addScaled(Math.cos(alpha), u).addScaled(
+ Math.sin(alpha), v).get())));
}
}
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Vector2DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Vector2DTest.java
index 90d2f1c..72eb3ae 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Vector2DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/Vector2DTest.java
@@ -20,6 +20,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
+import java.util.List;
import java.util.regex.Pattern;
import org.apache.commons.geometry.core.GeometryTestUtils;
@@ -1118,54 +1119,47 @@ class Vector2DTest {
}
@Test
- void testLinearCombination1() {
- // arrange
- final Vector2D p1 = Vector2D.of(1, 2);
-
+ void testSum_factoryMethods() {
// act/assert
- checkVector(Vector2D.linearCombination(0, p1), 0, 0);
-
- checkVector(Vector2D.linearCombination(1, p1), 1, 2);
- checkVector(Vector2D.linearCombination(-1, p1), -1, -2);
-
- checkVector(Vector2D.linearCombination(0.5, p1), 0.5, 1);
- checkVector(Vector2D.linearCombination(-0.5, p1), -0.5, -1);
+ checkVector(Vector2D.Sum.create().get(), 0, 0);
+ checkVector(Vector2D.Sum.of(Vector2D.of(1, 2)).get(), 1, 2);
+ checkVector(Vector2D.Sum.of(
+ Vector2D.of(1, 2),
+ Vector2D.Unit.PLUS_X,
+ Vector2D.Unit.PLUS_Y).get(), 2, 3);
}
@Test
- void testLinearCombination2() {
+ void testSum_instanceMethods() {
// arrange
final Vector2D p1 = Vector2D.of(1, 2);
- final Vector2D p2 = Vector2D.of(-3, -4);
+ final Vector2D p2 = Vector2D.of(4, 6);
// act/assert
- checkVector(Vector2D.linearCombination(2, p1, -3, p2), 11, 16);
- checkVector(Vector2D.linearCombination(-3, p1, 2, p2), -9, -14);
+ checkVector(Vector2D.Sum.create()
+ .add(p1)
+ .addScaled(0.5, p2)
+ .get(), 3, 5);
}
@Test
- void testLinearCombination3() {
+ void testSum_accept() {
// arrange
final Vector2D p1 = Vector2D.of(1, 2);
- final Vector2D p2 = Vector2D.of(-3, -4);
- final Vector2D p3 = Vector2D.of(5, 6);
+ final Vector2D p2 = Vector2D.of(3, -6);
- // act/assert
- checkVector(Vector2D.linearCombination(2, p1, -3, p2, 4, p3), 31, 40);
- checkVector(Vector2D.linearCombination(-3, p1, 2, p2, -4, p3), -29, -38);
- }
+ final List<Vector2D.Unit> units = Arrays.asList(
+ Vector2D.Unit.PLUS_X,
+ Vector2D.Unit.PLUS_Y);
- @Test
- void testLinearCombination4() {
- // arrange
- final Vector2D p1 = Vector2D.of(1, 2);
- final Vector2D p2 = Vector2D.of(-3, -4);
- final Vector2D p3 = Vector2D.of(5, 6);
- final Vector2D p4 = Vector2D.of(-7, -8);
+ final Vector2D.Sum s = Vector2D.Sum.create();
// act/assert
- checkVector(Vector2D.linearCombination(2, p1, -3, p2, 4, p3, -5, p4), 66, 80);
- checkVector(Vector2D.linearCombination(-3, p1, 2, p2, -4, p3, 5, p4), -64, -78);
+ Arrays.asList(p1, Vector2D.ZERO, p2).forEach(s);
+ units.forEach(s);
+
+ // assert
+ checkVector(s.get(), 5, -3);
}
@Test
diff --git a/commons-geometry-hull/src/test/java/org/apache/commons/geometry/hull/euclidean/twod/ConvexHullGenerator2DAbstractTest.java b/commons-geometry-hull/src/test/java/org/apache/commons/geometry/hull/euclidean/twod/ConvexHullGenerator2DAbstractTest.java
index 6488d6b..e30d5cc 100644
--- a/commons-geometry-hull/src/test/java/org/apache/commons/geometry/hull/euclidean/twod/ConvexHullGenerator2DAbstractTest.java
+++ b/commons-geometry-hull/src/test/java/org/apache/commons/geometry/hull/euclidean/twod/ConvexHullGenerator2DAbstractTest.java
@@ -25,8 +25,8 @@ import org.apache.commons.geometry.core.Region;
import org.apache.commons.geometry.core.RegionLocation;
import org.apache.commons.geometry.euclidean.twod.ConvexArea;
import org.apache.commons.geometry.euclidean.twod.Vector2D;
-import org.apache.commons.numbers.core.LinearCombination;
import org.apache.commons.numbers.core.Precision;
+import org.apache.commons.numbers.core.Sum;
import org.apache.commons.rng.UniformRandomProvider;
import org.apache.commons.rng.simple.RandomSource;
import org.junit.jupiter.api.Assertions;
@@ -468,7 +468,9 @@ public abstract class ConvexHullGenerator2DAbstractTest {
Assertions.assertTrue(d1.norm() > 1e-10);
Assertions.assertTrue(d2.norm() > 1e-10);
- final double cross = LinearCombination.value(d1.getX(), d2.getY(), -d1.getY(), d2.getX());
+ final double cross = Sum.create()
+ .addProduct(d1.getX(), d2.getY())
+ .addProduct(-d1.getY(), d2.getX()).getAsDouble();
final int cmp = Precision.compareTo(cross, 0.0, TEST_EPS);
if (sign != 0 && cmp != sign) {
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/ConvexArea2S.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/ConvexArea2S.java
index e0bc3ee..170d39f 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/ConvexArea2S.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/ConvexArea2S.java
@@ -367,16 +367,13 @@ public final class ConvexArea2S extends AbstractConvexHyperplaneBoundedRegion<Po
* @see #computeTriangleFanWeightedCentroidVector(List)
*/
private static Vector3D computeArcPoleWeightedCentroidVector(final List<GreatArc> arcs) {
- Vector3D centroid = Vector3D.ZERO;
+ final Vector3D.Sum centroid = Vector3D.Sum.create();
- Vector3D arcContribution;
for (final GreatArc arc : arcs) {
- arcContribution = arc.getCircle().getPole().withNorm(arc.getSize());
-
- centroid = centroid.add(arcContribution);
+ centroid.addScaled(arc.getSize(), arc.getCircle().getPole());
}
- return centroid;
+ return centroid.get();
}
/** Compute the weighted centroid vector for the triangle or polygon formed by the given arcs
@@ -403,7 +400,7 @@ public final class ConvexArea2S extends AbstractConvexHyperplaneBoundedRegion<Po
final Point2S p0 = arcIt.next().getStartPoint();
final Vector3D.Unit v0 = p0.getVector();
- Vector3D areaCentroid = Vector3D.ZERO;
+ final Vector3D.Sum areaCentroid = Vector3D.Sum.create();
GreatArc arc;
Point2S p1;
@@ -422,17 +419,21 @@ public final class ConvexArea2S extends AbstractConvexHyperplaneBoundedRegion<Po
v1 = p1.getVector();
v2 = p2.getVector();
- triangleCentroid = v0.add(v1).add(v2).normalize();
+ triangleCentroid = Vector3D.Sum.create()
+ .add(v0)
+ .add(v1)
+ .add(v2)
+ .get().normalize();
triangleCentroidLen =
computeArcCentroidContribution(v0, v1, triangleCentroid) +
computeArcCentroidContribution(v1, v2, triangleCentroid) +
computeArcCentroidContribution(v2, v0, triangleCentroid);
- areaCentroid = areaCentroid.add(triangleCentroid.withNorm(triangleCentroidLen));
+ areaCentroid.addScaled(triangleCentroidLen, triangleCentroid);
}
}
- return areaCentroid;
+ return areaCentroid.get();
}
/** Compute the contribution made by a single arc to a weighted centroid vector.
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/GreatCircle.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/GreatCircle.java
index 6bd7a5b..e858558 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/GreatCircle.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/GreatCircle.java
@@ -169,7 +169,9 @@ public final class GreatCircle extends AbstractHyperplane<Point2S>
* @return the point on the great circle with the given phase angle
*/
public Vector3D vectorAt(final double azimuth) {
- return Vector3D.linearCombination(Math.cos(azimuth), u, Math.sin(azimuth), v);
+ return Vector3D.Sum.create()
+ .addScaled(Math.cos(azimuth), u)
+ .addScaled(Math.sin(azimuth), v).get();
}
/** {@inheritDoc} */
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/RegionBSPTree2S.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/RegionBSPTree2S.java
index 906c5ab..026cd9f 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/RegionBSPTree2S.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/RegionBSPTree2S.java
@@ -28,6 +28,7 @@ import org.apache.commons.geometry.core.partitioning.bsp.AbstractBSPTree;
import org.apache.commons.geometry.core.partitioning.bsp.AbstractRegionBSPTree;
import org.apache.commons.geometry.euclidean.threed.Vector3D;
import org.apache.commons.numbers.core.Precision;
+import org.apache.commons.numbers.core.Sum;
/** BSP tree representing regions in 2D spherical space.
*/
@@ -169,35 +170,37 @@ public class RegionBSPTree2S extends AbstractRegionBSPTree<Point2S, RegionBSPTre
final List<ConvexArea2S> areas = toConvex();
final Precision.DoubleEquivalence precision = ((GreatArc) getRoot().getCut()).getPrecision();
- double sizeSum = 0;
- Vector3D centroidVectorSum = Vector3D.ZERO;
+ final Sum sizeSum = Sum.create();
+ final Vector3D.Sum centroidVectorSum = Vector3D.Sum.create();
- Vector3D centroidVector;
double maxCentroidVectorWeightSq = 0.0;
for (final ConvexArea2S area : areas) {
- sizeSum += area.getSize();
+ sizeSum.add(area.getSize());
- centroidVector = area.getWeightedCentroidVector();
- maxCentroidVectorWeightSq = Math.max(maxCentroidVectorWeightSq, centroidVector.normSq());
+ final Vector3D areaCentroidVector = area.getWeightedCentroidVector();
+ maxCentroidVectorWeightSq = Math.max(maxCentroidVectorWeightSq, areaCentroidVector.normSq());
- centroidVectorSum = centroidVectorSum.add(centroidVector);
+ centroidVectorSum.add(areaCentroidVector);
}
+ final double size = sizeSum.getAsDouble();
+ final Vector3D centroidVector = centroidVectorSum.get();
+
// Convert the weighted centroid vector to a point on the sphere surface. If the centroid vector
// length is less than the max length of the combined convex areas and the vector itself is
// equivalent to zero, then we know that there are opposing and approximately equal areas in the
// region, resulting in an indeterminate centroid. This would occur, for example, if there were
// equal areas around each pole.
final Point2S centroid;
- if (centroidVectorSum.normSq() < maxCentroidVectorWeightSq &&
- centroidVectorSum.eq(Vector3D.ZERO, precision)) {
+ if (centroidVector.normSq() < maxCentroidVectorWeightSq &&
+ centroidVector.eq(Vector3D.ZERO, precision)) {
centroid = null;
} else {
- centroid = Point2S.from(centroidVectorSum);
+ centroid = Point2S.from(centroidVector);
}
- return new RegionSizeProperties<>(sizeSum, centroid);
+ return new RegionSizeProperties<>(size, centroid);
}
/** {@inheritDoc} */