This is an automated email from the ASF dual-hosted git repository. erans pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-geometry.git
commit a009c78f19acf0b6feb9473a2de3ec8513710bf7 Author: Gilles Sadowski <[email protected]> AuthorDate: Fri Sep 27 13:58:31 2019 +0200 GEOMETRY-61: Improvement of "normalize" functionality for class "Vector3D". "Unit" class defines factory methods "from" to create a normalized instance. --- .../euclidean/threed/AffineTransformMatrix3D.java | 2 +- .../geometry/euclidean/threed/Vector3D.java | 85 ++++++++++++++-------- .../threed/rotation/QuaternionRotation.java | 2 +- .../geometry/euclidean/threed/PlaneTest.java | 14 ++-- .../geometry/euclidean/threed/Vector3DTest.java | 12 +-- 5 files changed, 68 insertions(+), 47 deletions(-) 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 cd25f7b..92d2b2a 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 @@ -199,7 +199,7 @@ public final class AffineTransformMatrix3D implements AffineTransformMatrix<Vect */ @Override public Vector3D applyDirection(final Vector3D vec) { - return applyVector(vec, Vector3D::normalize); + return applyVector(vec, Vector3D.Unit::from); } /** Apply a translation to the current instance, returning the result as a new transform. 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 e0f86f3..5aa4610 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 @@ -34,22 +34,22 @@ public class Vector3D extends MultiDimensionalEuclideanVector<Vector3D> { public static final Vector3D ZERO = new Vector3D(0, 0, 0); /** First canonical vector (coordinates: 1, 0, 0). */ - public static final Vector3D PLUS_X = new UnitVector(1, 0, 0); + public static final Vector3D PLUS_X = Unit.PLUS_X; /** Opposite of the first canonical vector (coordinates: -1, 0, 0). */ - public static final Vector3D MINUS_X = new UnitVector(-1, 0, 0); + public static final Vector3D MINUS_X = Unit.MINUS_X; /** Second canonical vector (coordinates: 0, 1, 0). */ - public static final Vector3D PLUS_Y = new UnitVector(0, 1, 0); + public static final Vector3D PLUS_Y = Unit.PLUS_Y; /** Opposite of the second canonical vector (coordinates: 0, -1, 0). */ - public static final Vector3D MINUS_Y = new UnitVector(0, -1, 0); + public static final Vector3D MINUS_Y = Unit.MINUS_Y; /** Third canonical vector (coordinates: 0, 0, 1). */ - public static final Vector3D PLUS_Z = new UnitVector(0, 0, 1); + public static final Vector3D PLUS_Z = Unit.PLUS_Z; /** Opposite of the third canonical vector (coordinates: 0, 0, -1). */ - public static final Vector3D MINUS_Z = new UnitVector(0, 0, -1); + public static final Vector3D MINUS_Z = Unit.MINUS_Z; // CHECKSTYLE: stop ConstantName /** A vector with all coordinates set to NaN. */ @@ -149,10 +149,7 @@ public class Vector3D extends MultiDimensionalEuclideanVector<Vector3D> { /** {@inheritDoc} */ @Override public Vector3D directionTo(Vector3D v) { - return normalize( - v.x - x, - v.y - y, - v.z - z); + return vectorTo(v).normalize(); } /** {@inheritDoc} */ @@ -234,7 +231,7 @@ public class Vector3D extends MultiDimensionalEuclideanVector<Vector3D> { /** {@inheritDoc} */ @Override public Vector3D normalize() { - return normalize(x, y, z); + return Unit.from(x, y, z); } /** {@inheritDoc} */ @@ -348,7 +345,7 @@ public class Vector3D extends MultiDimensionalEuclideanVector<Vector3D> { /** {@inheritDoc} */ @Override public Vector3D orthogonal(Vector3D dir) { - return dir.getComponent(this, true, Vector3D::normalize); + return dir.getComponent(this, true, Vector3D.Unit::from); } /** Compute the cross-product of the instance with another vector. @@ -493,20 +490,6 @@ public class Vector3D extends MultiDimensionalEuclideanVector<Vector3D> { return new Vector3D(v[0], v[1], v[2]); } - /** Returns a normalized vector derived from the given values. - * @param x abscissa (first coordinate value) - * @param y ordinate (second coordinate value) - * @param z height (third coordinate value) - * @return normalized vector instance - * @throws IllegalNormException if the norm of the given values is zero, NaN, or infinite - */ - public static Vector3D normalize(final double x, final double y, final double z) { - final double norm = Vectors.checkedNorm(Vectors.norm(x, y, z)); - final double invNorm = 1.0 / norm; - - return new UnitVector(x * invNorm, y * invNorm, z * invNorm); - } - /** Parses the given string and returns a new vector instance. The expected string * format is the same as that returned by {@link #toString()}. * @param str the string to parse @@ -596,10 +579,23 @@ public class Vector3D extends MultiDimensionalEuclideanVector<Vector3D> { LinearCombination.value(a1, v1.z, a2, v2.z, a3, v3.z, a4, v4.z)); } - /** Private class used to represent unit vectors. This allows optimizations to be performed for certain - * operations. + /** + * Represents unit vectors. + * This allows optimizations to be performed for certain operations. */ - private static final class UnitVector extends Vector3D { + public static final class Unit extends Vector3D { + /** Unit vector (coordinates: 1, 0, 0). */ + static final Unit PLUS_X = new Unit(1d, 0d, 0d); + /** Negation of unit vector (coordinates: -1, 0, 0). */ + static final Unit MINUS_X = new Unit(-1d, 0d, 0d); + /** Unit vector (coordinates: 0, 1, 0). */ + static final Unit PLUS_Y = new Unit(0d, 1d, 0d); + /** Negation of unit vector (coordinates: 0, -1, 0). */ + static final Unit MINUS_Y = new Unit(0d, -1d, 0d); + /** Unit vector (coordinates: 0, 0, 1). */ + static final Unit PLUS_Z = new Unit(0d, 0d, 1d); + /** Negation of unit vector (coordinates: 0, 0, -1). */ + static final Unit MINUS_Z = new Unit(0d, 0d, -1d); /** Serializable version identifier */ private static final long serialVersionUID = 20180903L; @@ -610,10 +606,35 @@ public class Vector3D extends MultiDimensionalEuclideanVector<Vector3D> { * @param y ordinate (second coordinate value) * @param z height (third coordinate value) */ - private UnitVector(final double x, final double y, final double z) { + private Unit(final double x, final double y, final double z) { super(x, y, z); } + /** + * Creates a normalized vector. + * + * @param x Vector coordinate. + * @param y Vector coordinate. + * @param z Vector coordinate. + * @return a vector whose norm is 1. + * @throws IllegalNormException if the norm of the given value is zero, NaN, or infinite + */ + public static Unit from(double x, double y, double z) { + final double invNorm = 1 / Vectors.checkedNorm(Vectors.norm(x, y, z)); + return new Unit(x * invNorm, y * invNorm, z * invNorm); + } + + /** + * Creates a normalized vector. + * + * @param v Vector. + * @return a vector whose norm is 1. + * @throws IllegalNormException if the norm of the given value is zero, NaN, or infinite + */ + public static Unit from(Vector3D v) { + return from(v.getX(), v.getY(), v.getZ()); + } + /** {@inheritDoc} */ @Override public double norm() { @@ -640,8 +661,8 @@ public class Vector3D extends MultiDimensionalEuclideanVector<Vector3D> { /** {@inheritDoc} */ @Override - public UnitVector negate() { - return new UnitVector(-getX(), -getY(), -getZ()); + public Unit negate() { + return new Unit(-getX(), -getY(), -getZ()); } } } 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 957ff56..2e67ce5 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 @@ -91,7 +91,7 @@ public final class QuaternionRotation implements Rotation3D, Serializable { // the most straightforward way to check if we have a normalizable // vector is to just try to normalize it and see if we fail try { - return Vector3D.normalize(quat.getX(), quat.getY(), quat.getZ()); + return Vector3D.Unit.from(quat.getX(), quat.getY(), quat.getZ()); } catch (IllegalNormException exc) { return Vector3D.PLUS_X; 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 af76826..9757ce3 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 @@ -280,22 +280,22 @@ public class PlaneTest { origin, Vector3D.MINUS_Z, Vector3D.PLUS_Y); checkPlane(Plane.fromPoints(rotate(pts, 2), TEST_PRECISION), - origin, Vector3D.normalize(0, 1, -1), Vector3D.normalize(0, 1, 1)); + origin, Vector3D.Unit.from(0, 1, -1), Vector3D.Unit.from(0, 1, 1)); checkPlane(Plane.fromPoints(rotate(pts, 3), TEST_PRECISION), - origin, Vector3D.normalize(0, 1, 1), Vector3D.normalize(0, -1, 1)); + origin, Vector3D.Unit.from(0, 1, 1), Vector3D.Unit.from(0, -1, 1)); checkPlane(Plane.fromPoints(rotate(pts, 4), TEST_PRECISION), - origin, Vector3D.normalize(0, -1, -0.5), Vector3D.normalize(0, 0.5, -1)); + origin, Vector3D.Unit.from(0, -1, -0.5), Vector3D.Unit.from(0, 0.5, -1)); checkPlane(Plane.fromPoints(rotate(pts, 5), TEST_PRECISION), - origin, Vector3D.normalize(0, -1, -0.5), Vector3D.normalize(0, 0.5, -1)); + origin, Vector3D.Unit.from(0, -1, -0.5), Vector3D.Unit.from(0, 0.5, -1)); checkPlane(Plane.fromPoints(rotate(pts, 6), TEST_PRECISION), - origin, Vector3D.normalize(0, -1, 0.5), Vector3D.normalize(0, -0.5, -1)); + origin, Vector3D.Unit.from(0, -1, 0.5), Vector3D.Unit.from(0, -0.5, -1)); checkPlane(Plane.fromPoints(rotate(pts, 7), TEST_PRECISION), - origin, Vector3D.normalize(0, -1, 0.5), Vector3D.normalize(0, -0.5, -1)); + origin, Vector3D.Unit.from(0, -1, 0.5), Vector3D.Unit.from(0, -0.5, -1)); checkPlane(Plane.fromPoints(rotate(pts, 8), TEST_PRECISION), - origin, Vector3D.normalize(0, -1, 0.5), Vector3D.normalize(0, -0.5, -1)); + origin, Vector3D.Unit.from(0, -1, 0.5), Vector3D.Unit.from(0, -0.5, -1)); checkPlane(Plane.fromPoints(rotate(pts, 9), TEST_PRECISION), origin, Vector3D.PLUS_Z, Vector3D.MINUS_Y); 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 c4b5de3..f876dff 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 @@ -1140,19 +1140,19 @@ public class Vector3DTest { double invSqrt3 = 1.0 / Math.sqrt(3.0); // act/assert - checkVector(Vector3D.normalize(2.0, -2.0, 2.0), invSqrt3, -invSqrt3, invSqrt3); - checkVector(Vector3D.normalize(-4.0, 4.0, -4.0), -invSqrt3, invSqrt3, -invSqrt3); + checkVector(Vector3D.Unit.from(2.0, -2.0, 2.0), invSqrt3, -invSqrt3, invSqrt3); + checkVector(Vector3D.Unit.from(-4.0, 4.0, -4.0), -invSqrt3, invSqrt3, -invSqrt3); } @Test public void testNormalize_static_illegalNorm() { - GeometryTestUtils.assertThrows(() -> Vector3D.normalize(0.0, 0.0, 0.0), + GeometryTestUtils.assertThrows(() -> Vector3D.Unit.from(0.0, 0.0, 0.0), IllegalNormException.class); - GeometryTestUtils.assertThrows(() -> Vector3D.normalize(Double.NaN, 1.0, 1.0), + GeometryTestUtils.assertThrows(() -> Vector3D.Unit.from(Double.NaN, 1.0, 1.0), IllegalNormException.class); - GeometryTestUtils.assertThrows(() -> Vector3D.normalize(1.0, Double.NEGATIVE_INFINITY, 1.0), + GeometryTestUtils.assertThrows(() -> Vector3D.Unit.from(1.0, Double.NEGATIVE_INFINITY, 1.0), IllegalNormException.class); - GeometryTestUtils.assertThrows(() -> Vector3D.normalize(1.0, 1.0, Double.POSITIVE_INFINITY), + GeometryTestUtils.assertThrows(() -> Vector3D.Unit.from(1.0, 1.0, Double.POSITIVE_INFINITY), IllegalNormException.class); }
