You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by er...@apache.org on 2018/09/14 14:25:06 UTC
[commons-geometry] 01/05: GEOMETRY-8: adding initial exception
hierarchy; using IllegalNormException in Vector classes
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 b7f391ac5c53503239b063f2d9066d5886880a89
Author: Matt Juntunen <ma...@hotmail.com>
AuthorDate: Mon Sep 10 22:21:05 2018 -0400
GEOMETRY-8: adding initial exception hierarchy; using IllegalNormException in Vector classes
---
.../org/apache/commons/geometry/core/Vector.java | 18 ++--
.../geometry/core/exception/GeometryException.java | 32 +++++++
.../core/exception/GeometryStateException.java | 30 +++++++
.../core/exception/GeometryValueException.java | 30 +++++++
.../core/exception/IllegalNormException.java | 34 ++++++++
.../geometry/core/exception/package-info.java | 23 +++++
.../commons/geometry/core/GeometryTestUtils.java | 32 +++++++
.../geometry/euclidean}/internal/Vectors.java | 21 ++++-
.../commons/geometry/euclidean/oned/Vector1D.java | 50 +++++------
.../commons/geometry/euclidean/threed/Point3D.java | 2 +-
.../geometry/euclidean/threed/Rotation.java | 85 +++++++++----------
.../geometry/euclidean/threed/Vector3D.java | 52 +++++-------
.../commons/geometry/euclidean/twod/Point2D.java | 2 +-
.../commons/geometry/euclidean/twod/Vector2D.java | 45 +++++-----
.../geometry/euclidean}/internal/VectorsTest.java | 26 +++++-
.../geometry/euclidean/oned/Vector1DTest.java | 89 +++++++++++++++-----
.../geometry/euclidean/threed/RotationTest.java | 3 +-
.../geometry/euclidean/threed/Vector3DTest.java | 98 ++++++++++++++++++----
.../geometry/euclidean/twod/Vector2DTest.java | 87 +++++++++++++++----
19 files changed, 558 insertions(+), 201 deletions(-)
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Vector.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Vector.java
index d4eb296..b04d644 100644
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Vector.java
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Vector.java
@@ -16,6 +16,8 @@
*/
package org.apache.commons.geometry.core;
+import org.apache.commons.geometry.core.exception.IllegalNormException;
+
/** Interface representing a vector in a vector space. The most common
* use of this interface is to represent displacement vectors in an affine
* space.
@@ -120,9 +122,9 @@ public interface Vector<V extends Vector<V>> extends Spatial {
/** Get a normalized vector aligned with the instance. The returned
* vector has a magnitude of 1.
* @return a new normalized vector
- * @exception IllegalStateException if the norm is zero
+ * @exception IllegalNormException if the norm is zero, NaN, or infinite
*/
- V normalize() throws IllegalStateException;
+ V normalize() throws IllegalNormException;
/** Multiply the instance by a scalar.
* @param a scalar
@@ -180,10 +182,10 @@ public interface Vector<V extends Vector<V>> extends Spatial {
* </code>
* @param base base vector
* @return the vector projection of the instance onto {@code base}
- * @exception IllegalStateException if the norm of the base vector is zero
+ * @exception IllegalNormException if the norm of the base vector is zero, NaN, or infinite
* @see #reject(Vector)
*/
- V project(V base) throws IllegalStateException;
+ V project(V base) throws IllegalNormException;
/** Get the rejection of the instance from the given base vector. The returned
* vector is orthogonal to {@code base}. This operation can be interpreted as
@@ -195,15 +197,15 @@ public interface Vector<V extends Vector<V>> extends Spatial {
* </code>
* @param base base vector
* @return the vector rejection of the instance from {@code base}
- * @exception IllegalStateException if the norm of the base vector is zero
+ * @exception IllegalNormException if the norm of the base vector is zero, NaN, or infinite
* @see #project(Vector)
*/
- V reject(V base) throws IllegalStateException;
+ V reject(V base) throws IllegalNormException;
/** Compute the angular separation between two vectors in radians.
* @param v other vector
* @return angular separation between this instance and v in radians
- * @exception IllegalStateException if either vector has a zero norm
+ * @exception IllegalNormException if either vector has a zero, NaN, or infinite norm
*/
- double angle(V v) throws IllegalStateException;
+ double angle(V v) throws IllegalNormException;
}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/exception/GeometryException.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/exception/GeometryException.java
new file mode 100644
index 0000000..48e4b2a
--- /dev/null
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/exception/GeometryException.java
@@ -0,0 +1,32 @@
+/*
+ * 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.core.exception;
+
+/** Base class for geometry exceptions.
+ */
+public class GeometryException extends RuntimeException {
+
+ /** Serializable version identifier */
+ private static final long serialVersionUID = 20180909L;
+
+ /** Simple constructor with error message.
+ * @param msg exception message string
+ */
+ public GeometryException(String msg) {
+ super(msg);
+ }
+}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/exception/GeometryStateException.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/exception/GeometryStateException.java
new file mode 100644
index 0000000..4a8080e
--- /dev/null
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/exception/GeometryStateException.java
@@ -0,0 +1,30 @@
+/*
+ * 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.core.exception;
+
+public class GeometryStateException extends GeometryException {
+
+ /** Serializable version identifier */
+ private static final long serialVersionUID = 20180909L;
+
+ /** Simple constructor with error message.
+ * @param msg exception message string
+ */
+ public GeometryStateException(String msg) {
+ super(msg);
+ }
+}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/exception/GeometryValueException.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/exception/GeometryValueException.java
new file mode 100644
index 0000000..5d7b0d6
--- /dev/null
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/exception/GeometryValueException.java
@@ -0,0 +1,30 @@
+/*
+ * 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.core.exception;
+
+public class GeometryValueException extends GeometryException {
+
+ /** Serializable version identifier */
+ private static final long serialVersionUID = 20180909L;
+
+ /** Simple constructor with error message.
+ * @param msg exception message string
+ */
+ public GeometryValueException(String msg) {
+ super(msg);
+ }
+}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/exception/IllegalNormException.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/exception/IllegalNormException.java
new file mode 100644
index 0000000..b0d80e8
--- /dev/null
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/exception/IllegalNormException.java
@@ -0,0 +1,34 @@
+/*
+ * 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.core.exception;
+
+/** Exception thrown when an illegal vector norm value is encountered
+ * in an operation.
+ */
+public class IllegalNormException extends GeometryValueException {
+
+ /** Serializable version identifier */
+ private static final long serialVersionUID = 20180909L;
+
+ /**
+ * Simple constructor accepting the illegal norm value.
+ * @param norm the illegal norm value
+ */
+ public IllegalNormException(double norm) {
+ super("Illegal norm: " + norm);
+ }
+}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/exception/package-info.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/exception/package-info.java
new file mode 100644
index 0000000..8180f81
--- /dev/null
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/exception/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+/**
+ *
+ * <p>
+ * This package contains exception types used by this library.
+ * </p>
+ */
+package org.apache.commons.geometry.core.exception;
diff --git a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/GeometryTestUtils.java b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/GeometryTestUtils.java
index 3dbf58a..60bdeea 100644
--- a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/GeometryTestUtils.java
+++ b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/GeometryTestUtils.java
@@ -45,6 +45,38 @@ public class GeometryTestUtils {
Assert.assertTrue(msg, value < 0);
}
+ /** Asserts that the given Runnable throws an exception of the given type.
+ * @param r the Runnable instance
+ * @param exceptionType the expected exception type
+ */
+ public static void assertThrows(Runnable r, Class<?> exceptionType) {
+ assertThrows(r, exceptionType, null);
+ }
+
+ /** Asserts that the given Runnable throws an exception of the given type. If
+ * {@code message} is not null, the exception message is asserted to equal the
+ * given value.
+ * @param r the Runnable instance
+ * @param exceptionType the expected exception type
+ * @param message the expected exception message; ignored if null
+ */
+ public static void assertThrows(Runnable r, Class<?> exceptionType, String message) {
+ try {
+ r.run();
+ Assert.fail("Operation should have thrown an exception");
+ }
+ catch (Exception exc) {
+ Class<?> actualType = exc.getClass();
+
+ Assert.assertTrue("Expected exception of type " + exceptionType.getName() + " but was " + actualType.getName(),
+ exceptionType.isAssignableFrom(actualType));
+
+ if (message != null) {
+ Assert.assertEquals(message, exc.getMessage());
+ }
+ }
+ }
+
/**
* Serializes and then recovers an object from a byte array. Returns the deserialized object.
*
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/internal/Vectors.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/internal/Vectors.java
similarity index 91%
rename from commons-geometry-core/src/main/java/org/apache/commons/geometry/core/internal/Vectors.java
rename to commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/internal/Vectors.java
index 673d53b..cbb19b2 100644
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/internal/Vectors.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/internal/Vectors.java
@@ -14,7 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.commons.geometry.core.internal;
+package org.apache.commons.geometry.euclidean.internal;
+
+import org.apache.commons.geometry.core.exception.IllegalNormException;
/** This class consists exclusively of static vector utility methods.
*/
@@ -23,6 +25,23 @@ public final class Vectors {
/** Private constructor. */
private Vectors() {}
+
+ /** Throws an {@link IllegalNormException} if the given norm value
+ * is not finite (ie, NaN or infinite) or zero. The argument is returned
+ * to allow this method to be called in-line.
+ * @param norm vector norm value
+ * @return the validated norm value
+ * @throws IllegalNormException if the given norm value is NaN, infinite,
+ * or zero
+ */
+ public static double checkFiniteNonZeroNorm(final double norm) throws IllegalNormException {
+ if (!Double.isFinite(norm) || norm == 0.0) {
+ throw new IllegalNormException(norm);
+ }
+
+ return norm;
+ }
+
/** Get the L<sub>1</sub> norm for the vector with the given components.
* This is defined as the sum of the absolute values of all vector components.
* @param x vector component
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 df40670..c5d455d 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
@@ -17,10 +17,10 @@
package org.apache.commons.geometry.euclidean.oned;
import org.apache.commons.geometry.core.Geometry;
+import org.apache.commons.geometry.core.exception.IllegalNormException;
import org.apache.commons.geometry.core.internal.SimpleTupleFormat;
-import org.apache.commons.geometry.core.internal.Vectors;
import org.apache.commons.geometry.euclidean.EuclideanVector;
-import org.apache.commons.geometry.euclidean.internal.ZeroNormException;
+import org.apache.commons.geometry.euclidean.internal.Vectors;
import org.apache.commons.numbers.arrays.LinearCombination;
/** This class represents a vector in one-dimensional Euclidean space.
@@ -117,14 +117,9 @@ public final class Vector1D extends Cartesian1D implements EuclideanVector<Point
/** {@inheritDoc} */
@Override
public Vector1D withMagnitude(double magnitude) {
- final double x = getX();
- if (x > 0.0) {
- return new Vector1D(magnitude);
- }
- else if (x < 0.0) {
- return new Vector1D(-magnitude);
- }
- throw new ZeroNormException();
+ Vectors.checkFiniteNonZeroNorm(getNorm());
+
+ return (getX() > 0.0)? new Vector1D(magnitude) : new Vector1D(-magnitude);
}
/** {@inheritDoc} */
@@ -159,15 +154,10 @@ public final class Vector1D extends Cartesian1D implements EuclideanVector<Point
/** {@inheritDoc} */
@Override
- public Vector1D normalize() throws IllegalStateException {
- final double x = getX();
- if (x > 0.0) {
- return ONE;
- }
- else if (x < 0.0) {
- return MINUS_ONE;
- }
- throw new ZeroNormException();
+ public Vector1D normalize() throws IllegalNormException {
+ Vectors.checkFiniteNonZeroNorm(getNorm());
+
+ return (getX() > 0.0) ? ONE : MINUS_ONE;
}
/** {@inheritDoc} */
@@ -210,10 +200,9 @@ public final class Vector1D extends Cartesian1D implements EuclideanVector<Point
* <p>For the one-dimensional case, this method simply returns the current instance.</p>
*/
@Override
- public Vector1D project(final Vector1D base) throws IllegalStateException {
- if (base.getX() == 0) {
- throw new ZeroNormException(ZeroNormException.INVALID_BASE);
- }
+ public Vector1D project(final Vector1D base) throws IllegalNormException {
+ Vectors.checkFiniteNonZeroNorm(base.getNorm());
+
return this;
}
@@ -221,10 +210,9 @@ public final class Vector1D extends Cartesian1D implements EuclideanVector<Point
* <p>For the one-dimensional case, this method simply returns the zero vector.</p>
*/
@Override
- public Vector1D reject(final Vector1D base) throws IllegalStateException {
- if (base.getX() == 0) {
- throw new ZeroNormException(ZeroNormException.INVALID_BASE);
- }
+ public Vector1D reject(final Vector1D base) throws IllegalNormException {
+ Vectors.checkFiniteNonZeroNorm(base.getNorm());
+
return Vector1D.ZERO;
}
@@ -233,13 +221,13 @@ public final class Vector1D extends Cartesian1D implements EuclideanVector<Point
* the same sign and {@code pi} if they are opposite.</p>
*/
@Override
- public double angle(final Vector1D v) throws IllegalStateException {
+ public double angle(final Vector1D v) throws IllegalNormException {
+ Vectors.checkFiniteNonZeroNorm(getNorm());
+ Vectors.checkFiniteNonZeroNorm(v.getNorm());
+
final double sig1 = Math.signum(getX());
final double sig2 = Math.signum(v.getX());
- if (sig1 == 0 || sig2 == 0) {
- throw new ZeroNormException();
- }
// the angle is 0 if the x value signs are the same and pi if not
return (sig1 == sig2) ? 0.0 : Geometry.PI;
}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java
index 8e15230..b9a4e3e 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Point3D.java
@@ -18,8 +18,8 @@
package org.apache.commons.geometry.euclidean.threed;
import org.apache.commons.geometry.core.internal.SimpleTupleFormat;
-import org.apache.commons.geometry.core.internal.Vectors;
import org.apache.commons.geometry.euclidean.EuclideanPoint;
+import org.apache.commons.geometry.euclidean.internal.Vectors;
import org.apache.commons.numbers.arrays.LinearCombination;
/** This class represents a point in three-dimensional Euclidean space.
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Rotation.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Rotation.java
index 272d5c0..7ab3ec3 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Rotation.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Rotation.java
@@ -19,6 +19,7 @@ package org.apache.commons.geometry.euclidean.threed;
import java.io.Serializable;
+import org.apache.commons.geometry.core.exception.IllegalNormException;
import org.apache.commons.numbers.arrays.LinearCombination;
/**
@@ -264,54 +265,48 @@ public class Rotation implements Serializable {
* @param u2 second vector of the origin pair
* @param v1 desired image of u1 by the rotation
* @param v2 desired image of u2 by the rotation
- * @exception IllegalArgumentException if the norm of one of the vectors is zero,
- * or if one of the pair is degenerated (i.e. the vectors of the pair are collinear)
+ * @exception IllegalNormException if the norm of one of the vectors is zero, NaN, infinite,
+ * or if one of the pair is degenerated (i.e. the vectors of the pair are collinear)
*/
public Rotation(Vector3D u1, Vector3D u2, Vector3D v1, Vector3D v2)
- throws IllegalArgumentException {
-
- try {
- // build orthonormalized base from u1, u2
- // this fails when vectors are null or collinear, which is forbidden to define a rotation
- final Vector3D u3 = u1.crossProduct(u2).normalize();
- u2 = u3.crossProduct(u1).normalize();
- u1 = u1.normalize();
-
- // build an orthonormalized base from v1, v2
- // this fails when vectors are null or collinear, which is forbidden to define a rotation
- final Vector3D v3 = v1.crossProduct(v2).normalize();
- v2 = v3.crossProduct(v1).normalize();
- v1 = v1.normalize();
-
- // buid a matrix transforming the first base into the second one
- final double[][] m = new double[][] {
- {
- LinearCombination.value(u1.getX(), v1.getX(), u2.getX(), v2.getX(), u3.getX(), v3.getX()),
- LinearCombination.value(u1.getY(), v1.getX(), u2.getY(), v2.getX(), u3.getY(), v3.getX()),
- LinearCombination.value(u1.getZ(), v1.getX(), u2.getZ(), v2.getX(), u3.getZ(), v3.getX())
- },
- {
- LinearCombination.value(u1.getX(), v1.getY(), u2.getX(), v2.getY(), u3.getX(), v3.getY()),
- LinearCombination.value(u1.getY(), v1.getY(), u2.getY(), v2.getY(), u3.getY(), v3.getY()),
- LinearCombination.value(u1.getZ(), v1.getY(), u2.getZ(), v2.getY(), u3.getZ(), v3.getY())
- },
- {
- LinearCombination.value(u1.getX(), v1.getZ(), u2.getX(), v2.getZ(), u3.getX(), v3.getZ()),
- LinearCombination.value(u1.getY(), v1.getZ(), u2.getY(), v2.getZ(), u3.getY(), v3.getZ()),
- LinearCombination.value(u1.getZ(), v1.getZ(), u2.getZ(), v2.getZ(), u3.getZ(), v3.getZ())
- }
- };
-
- double[] quat = mat2quat(m);
- q0 = quat[0];
- q1 = quat[1];
- q2 = quat[2];
- q3 = quat[3];
-
- } catch (IllegalStateException exc) {
- throw new IllegalArgumentException("Invalid rotation vector pairs", exc);
- }
+ throws IllegalNormException {
+
+ // build orthonormalized base from u1, u2
+ // this fails when vectors are null or collinear, which is forbidden to define a rotation
+ final Vector3D u3 = u1.crossProduct(u2).normalize();
+ u2 = u3.crossProduct(u1).normalize();
+ u1 = u1.normalize();
+
+ // build an orthonormalized base from v1, v2
+ // this fails when vectors are null or collinear, which is forbidden to define a rotation
+ final Vector3D v3 = v1.crossProduct(v2).normalize();
+ v2 = v3.crossProduct(v1).normalize();
+ v1 = v1.normalize();
+
+ // buid a matrix transforming the first base into the second one
+ final double[][] m = new double[][] {
+ {
+ LinearCombination.value(u1.getX(), v1.getX(), u2.getX(), v2.getX(), u3.getX(), v3.getX()),
+ LinearCombination.value(u1.getY(), v1.getX(), u2.getY(), v2.getX(), u3.getY(), v3.getX()),
+ LinearCombination.value(u1.getZ(), v1.getX(), u2.getZ(), v2.getX(), u3.getZ(), v3.getX())
+ },
+ {
+ LinearCombination.value(u1.getX(), v1.getY(), u2.getX(), v2.getY(), u3.getX(), v3.getY()),
+ LinearCombination.value(u1.getY(), v1.getY(), u2.getY(), v2.getY(), u3.getY(), v3.getY()),
+ LinearCombination.value(u1.getZ(), v1.getY(), u2.getZ(), v2.getY(), u3.getZ(), v3.getY())
+ },
+ {
+ LinearCombination.value(u1.getX(), v1.getZ(), u2.getX(), v2.getZ(), u3.getX(), v3.getZ()),
+ LinearCombination.value(u1.getY(), v1.getZ(), u2.getY(), v2.getZ(), u3.getY(), v3.getZ()),
+ LinearCombination.value(u1.getZ(), v1.getZ(), u2.getZ(), v2.getZ(), u3.getZ(), v3.getZ())
+ }
+ };
+ double[] quat = mat2quat(m);
+ q0 = quat[0];
+ q1 = quat[1];
+ q2 = quat[2];
+ q3 = quat[3];
}
/** Build one of the rotations that transform one vector into another one.
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 fd52558..d8de801 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
@@ -16,10 +16,10 @@
*/
package org.apache.commons.geometry.euclidean.threed;
+import org.apache.commons.geometry.core.exception.IllegalNormException;
import org.apache.commons.geometry.core.internal.SimpleTupleFormat;
-import org.apache.commons.geometry.core.internal.Vectors;
import org.apache.commons.geometry.euclidean.EuclideanVector;
-import org.apache.commons.geometry.euclidean.internal.ZeroNormException;
+import org.apache.commons.geometry.euclidean.internal.Vectors;
import org.apache.commons.numbers.arrays.LinearCombination;
/** This class represents a vector in three-dimensional Euclidean space.
@@ -131,7 +131,7 @@ public final class Vector3D extends Cartesian3D implements EuclideanVector<Point
/** {@inheritDoc} */
@Override
public Vector3D withMagnitude(double magnitude) {
- final double invNorm = 1.0 / getNonZeroNorm();
+ final double invNorm = 1.0 / getFiniteNonZeroNorm();
return new Vector3D(
magnitude * getX() * invNorm,
@@ -188,8 +188,8 @@ public final class Vector3D extends Cartesian3D implements EuclideanVector<Point
/** {@inheritDoc} */
@Override
- public Vector3D normalize() throws IllegalStateException {
- return scalarMultiply(1.0 / getNonZeroNorm());
+ public Vector3D normalize() throws IllegalNormException {
+ return scalarMultiply(1.0 / getFiniteNonZeroNorm());
}
/** Get a vector orthogonal to the instance.
@@ -205,10 +205,11 @@ public final class Vector3D extends Cartesian3D implements EuclideanVector<Point
* Vector3D j = Vector3D.crossProduct(k, i);
* </code></pre>
* @return a new normalized vector orthogonal to the instance
- * @exception IllegalStateException if the norm of the instance is zero
+ * @exception IllegalNormException if the norm of the instance is zero, NaN,
+ * or infinite
*/
- public Vector3D orthogonal() throws IllegalStateException {
- double threshold = 0.6 * getNonZeroNorm();
+ public Vector3D orthogonal() throws IllegalNormException {
+ double threshold = 0.6 * getFiniteNonZeroNorm();
final double x = getX();
final double y = getY();
@@ -233,8 +234,8 @@ public final class Vector3D extends Cartesian3D implements EuclideanVector<Point
* other.</p>
*/
@Override
- public double angle(Vector3D v) throws IllegalStateException {
- double normProduct = getNonZeroNorm() * v.getNonZeroNorm();
+ public double angle(Vector3D v) throws IllegalNormException {
+ double normProduct = getFiniteNonZeroNorm() * v.getFiniteNonZeroNorm();
double dot = dotProduct(v);
double threshold = normProduct * 0.9999;
@@ -322,13 +323,13 @@ public final class Vector3D extends Cartesian3D implements EuclideanVector<Point
/** {@inheritDoc} */
@Override
- public Vector3D project(Vector3D base) throws IllegalStateException {
+ public Vector3D project(Vector3D base) throws IllegalNormException {
return getComponent(base, false);
}
/** {@inheritDoc} */
@Override
- public Vector3D reject(Vector3D base) throws IllegalStateException {
+ public Vector3D reject(Vector3D base) throws IllegalNormException {
return getComponent(base, true);
}
@@ -382,17 +383,13 @@ public final class Vector3D extends Cartesian3D implements EuclideanVector<Point
return false;
}
- /** Returns the vector norm, throwing an IllegalStateException if the norm is zero.
- * @return the non-zero norm value
- * @throws IllegalStateException if the norm is zero
+ /** Returns the vector norm, throwing an IllegalNormException if the norm is zero,
+ * NaN, or infinite.
+ * @return the finite, non-zero norm value
+ * @throws IllegalNormException if the norm is zero, NaN, or infinite
*/
- private double getNonZeroNorm() throws IllegalStateException {
- final double n = getNorm();
- if (n == 0) {
- throw new ZeroNormException();
- }
-
- return n;
+ private double getFiniteNonZeroNorm() throws IllegalNormException {
+ return Vectors.checkFiniteNonZeroNorm(getNorm());
}
/** Returns a component of the current instance relative to the given base
@@ -404,17 +401,14 @@ public final class Vector3D extends Cartesian3D implements EuclideanVector<Point
* is returned.
* @return The projection or rejection of this instance relative to {@code base},
* depending on the value of {@code reject}.
- * @throws IllegalStateException if {@code base} has a zero norm
+ * @throws IllegalNormException if {@code base} has a zero, NaN, or infinite norm
*/
- private Vector3D getComponent(Vector3D base, boolean reject) throws IllegalStateException {
+ private Vector3D getComponent(Vector3D base, boolean reject) throws IllegalNormException {
final double aDotB = dotProduct(base);
- final double baseMagSq = base.getNormSq();
- if (baseMagSq == 0.0) {
- throw new ZeroNormException(ZeroNormException.INVALID_BASE);
- }
+ final double baseMag = Vectors.checkFiniteNonZeroNorm(base.getNorm());
- final double scale = aDotB / baseMagSq;
+ final double scale = aDotB / (baseMag * baseMag);
final double projX = scale * base.getX();
final double projY = scale * base.getY();
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java
index e7a89cb..323d8e6 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Point2D.java
@@ -17,8 +17,8 @@
package org.apache.commons.geometry.euclidean.twod;
import org.apache.commons.geometry.core.internal.SimpleTupleFormat;
-import org.apache.commons.geometry.core.internal.Vectors;
import org.apache.commons.geometry.euclidean.EuclideanPoint;
+import org.apache.commons.geometry.euclidean.internal.Vectors;
import org.apache.commons.numbers.arrays.LinearCombination;
/** This class represents a point in two-dimensional Euclidean space.
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 fec9764..298d052 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
@@ -16,10 +16,10 @@
*/
package org.apache.commons.geometry.euclidean.twod;
+import org.apache.commons.geometry.core.exception.IllegalNormException;
import org.apache.commons.geometry.core.internal.SimpleTupleFormat;
-import org.apache.commons.geometry.core.internal.Vectors;
import org.apache.commons.geometry.euclidean.EuclideanVector;
-import org.apache.commons.geometry.euclidean.internal.ZeroNormException;
+import org.apache.commons.geometry.euclidean.internal.Vectors;
import org.apache.commons.numbers.arrays.LinearCombination;
/** This class represents a vector in two-dimensional Euclidean space.
@@ -131,7 +131,7 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point
/** {@inheritDoc} */
@Override
public Vector2D withMagnitude(double magnitude) {
- final double invNorm = 1.0 / getNonZeroNorm();
+ final double invNorm = 1.0 / getFiniteNonZeroNorm();
return new Vector2D(
magnitude * getX() * invNorm,
@@ -171,8 +171,8 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point
/** {@inheritDoc} */
@Override
- public Vector2D normalize() throws IllegalStateException {
- return scalarMultiply(1.0 / getNonZeroNorm());
+ public Vector2D normalize() throws IllegalNormException {
+ return scalarMultiply(1.0 / getFiniteNonZeroNorm());
}
/** {@inheritDoc} */
@@ -213,13 +213,13 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point
/** {@inheritDoc} */
@Override
- public Vector2D project(Vector2D base) throws IllegalStateException {
+ public Vector2D project(Vector2D base) throws IllegalNormException {
return getComponent(base, false);
}
/** {@inheritDoc} */
@Override
- public Vector2D reject(Vector2D base) throws IllegalStateException {
+ public Vector2D reject(Vector2D base) throws IllegalNormException {
return getComponent(base, true);
}
@@ -231,8 +231,8 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point
* other.</p>
*/
@Override
- public double angle(Vector2D v) throws IllegalStateException {
- double normProduct = getNonZeroNorm() * v.getNonZeroNorm();
+ public double angle(Vector2D v) throws IllegalNormException {
+ double normProduct = getFiniteNonZeroNorm() * v.getFiniteNonZeroNorm();
double dot = dotProduct(v);
double threshold = normProduct * 0.9999;
@@ -328,17 +328,13 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point
return false;
}
- /** Returns the vector norm, throwing an IllegalStateException if the norm is zero.
- * @return the non-zero norm value
- * @throws IllegalStateException if the norm is zero
+ /** Returns the vector norm, throwing an IllegalNormException if the norm is zero,
+ * NaN, or infinite.
+ * @return the finite, non-zero norm value
+ * @throws IllegalNormException if the norm is zero, NaN, or infinite
*/
- private double getNonZeroNorm() throws IllegalStateException {
- final double n = getNorm();
- if (n == 0) {
- throw new ZeroNormException();
- }
-
- return n;
+ private double getFiniteNonZeroNorm() throws IllegalNormException {
+ return Vectors.checkFiniteNonZeroNorm(getNorm());
}
/** Returns a component of the current instance relative to the given base
@@ -350,17 +346,14 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point
* is returned.
* @return The projection or rejection of this instance relative to {@code base},
* depending on the value of {@code reject}.
- * @throws IllegalStateException if {@code base} has a zero norm
+ * @throws IllegalNormException if {@code base} has a zero, NaN, or infinite norm
*/
- private Vector2D getComponent(Vector2D base, boolean reject) throws IllegalStateException {
+ private Vector2D getComponent(Vector2D base, boolean reject) throws IllegalNormException {
final double aDotB = dotProduct(base);
- final double baseMagSq = base.getNormSq();
- if (baseMagSq == 0.0) {
- throw new ZeroNormException(ZeroNormException.INVALID_BASE);
- }
+ final double baseMag = Vectors.checkFiniteNonZeroNorm(base.getNorm());
- final double scale = aDotB / baseMagSq;
+ final double scale = aDotB / (baseMag * baseMag);
final double projX = scale * base.getX();
final double projY = scale * base.getY();
diff --git a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/internal/VectorsTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/internal/VectorsTest.java
similarity index 83%
rename from commons-geometry-core/src/test/java/org/apache/commons/geometry/core/internal/VectorsTest.java
rename to commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/internal/VectorsTest.java
index 9817b28..2d38904 100644
--- a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/internal/VectorsTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/internal/VectorsTest.java
@@ -14,9 +14,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.commons.geometry.core.internal;
+package org.apache.commons.geometry.euclidean.internal;
-import org.apache.commons.geometry.core.internal.Vectors;
+import org.apache.commons.geometry.core.GeometryTestUtils;
+import org.apache.commons.geometry.core.exception.IllegalNormException;
import org.junit.Assert;
import org.junit.Test;
@@ -26,6 +27,27 @@ public class VectorsTest {
private static final double EPS = Math.ulp(1d);
@Test
+ public void testCheckFiniteNonZeroNorm() {
+ // act/assert
+ Assert.assertEquals(1.0, Vectors.checkFiniteNonZeroNorm(1.0), EPS);
+ Assert.assertEquals(23.12, Vectors.checkFiniteNonZeroNorm(23.12), EPS);
+ Assert.assertEquals(2e-12, Vectors.checkFiniteNonZeroNorm(2e-12), EPS);
+
+ Assert.assertEquals(-1.0, Vectors.checkFiniteNonZeroNorm(-1.0), EPS);
+ Assert.assertEquals(-23.12, Vectors.checkFiniteNonZeroNorm(-23.12), EPS);
+ Assert.assertEquals(-2e-12, Vectors.checkFiniteNonZeroNorm(-2e-12), EPS);
+
+ GeometryTestUtils.assertThrows(() -> Vectors.checkFiniteNonZeroNorm(0.0),
+ IllegalNormException.class, "Illegal norm: 0.0");
+ GeometryTestUtils.assertThrows(() -> Vectors.checkFiniteNonZeroNorm(Double.NaN),
+ IllegalNormException.class, "Illegal norm: NaN");
+ GeometryTestUtils.assertThrows(() -> Vectors.checkFiniteNonZeroNorm(Double.POSITIVE_INFINITY),
+ IllegalNormException.class, "Illegal norm: Infinity");
+ GeometryTestUtils.assertThrows(() -> Vectors.checkFiniteNonZeroNorm(Double.NEGATIVE_INFINITY),
+ IllegalNormException.class, "Illegal norm: -Infinity");
+ }
+
+ @Test
public void testNorm1_oneD() {
// act/assert
Assert.assertEquals(0.0, Vectors.norm1(0.0), EPS);
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 e5b580a..ee817cc 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
@@ -19,6 +19,8 @@ package org.apache.commons.geometry.euclidean.oned;
import java.util.regex.Pattern;
import org.apache.commons.geometry.core.Geometry;
+import org.apache.commons.geometry.core.GeometryTestUtils;
+import org.apache.commons.geometry.core.exception.IllegalNormException;
import org.apache.commons.numbers.core.Precision;
import org.junit.Assert;
import org.junit.Test;
@@ -119,10 +121,17 @@ public class Vector1DTest {
checkVector(Vector1D.of(-5).withMagnitude(3.0), -3.0);
}
- @Test(expected = IllegalStateException.class)
- public void testWithMagnitude_zeroNorm() {
+ @Test
+ public void testWithMagnitude_illegalNorm() {
// act/assert
- Vector1D.ZERO.withMagnitude(1.0);
+ GeometryTestUtils.assertThrows(() -> Vector1D.ZERO.withMagnitude(2.0),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector1D.NaN.withMagnitude(2.0),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector1D.POSITIVE_INFINITY.withMagnitude(2.0),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector1D.NEGATIVE_INFINITY.withMagnitude(2.0),
+ IllegalNormException.class);
}
@Test
@@ -196,10 +205,17 @@ public class Vector1DTest {
checkVector(Vector1D.of(-5).normalize(), -1);
}
- @Test(expected = IllegalStateException.class)
- public void testNormalize_zeroNorm() {
- // act
- Vector1D.ZERO.normalize();
+ @Test
+ public void testNormalize_illegalNorm() {
+ // act/assert
+ GeometryTestUtils.assertThrows(() -> Vector1D.ZERO.normalize(),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector1D.NaN.normalize(),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector1D.POSITIVE_INFINITY.normalize(),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector1D.NEGATIVE_INFINITY.normalize(),
+ IllegalNormException.class);
}
@Test
@@ -317,10 +333,17 @@ public class Vector1DTest {
checkVector(v3.project(v3), 4);
}
- @Test(expected = IllegalStateException.class)
- public void testProject_baseHasZeroNorm() {
+ @Test
+ public void testProject_baseHasIllegalNorm() {
// act/assert
- Vector1D.of(2.0).project(Vector1D.ZERO);
+ GeometryTestUtils.assertThrows(() -> Vector1D.of(2.0).project(Vector1D.ZERO),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector1D.of(2.0).project(Vector1D.NaN),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector1D.of(2.0).project(Vector1D.POSITIVE_INFINITY),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector1D.of(2.0).project(Vector1D.NEGATIVE_INFINITY),
+ IllegalNormException.class);
}
@Test
@@ -340,10 +363,17 @@ public class Vector1DTest {
checkVector(v2.reject(v2), 0);
}
- @Test(expected = IllegalStateException.class)
- public void testReject_baseHasZeroNorm() {
+ @Test
+ public void testReject_baseHasIllegalNorm() {
// act/assert
- Vector1D.of(2.0).reject(Vector1D.ZERO);
+ GeometryTestUtils.assertThrows(() -> Vector1D.of(2.0).reject(Vector1D.ZERO),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector1D.of(2.0).reject(Vector1D.NaN),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector1D.of(2.0).reject(Vector1D.POSITIVE_INFINITY),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector1D.of(2.0).reject(Vector1D.NEGATIVE_INFINITY),
+ IllegalNormException.class);
}
@Test
@@ -376,16 +406,29 @@ public class Vector1DTest {
Assert.assertEquals(0.0, v4.angle(v4), TEST_TOLERANCE);
}
- @Test(expected = IllegalStateException.class)
- public void testAngle_firstVectorZero() {
- // act/assert
- Vector1D.ZERO.angle(Vector1D.of(1.0));
- }
-
- @Test(expected = IllegalStateException.class)
- public void testAngle_secondVectorZero() {
- // act/assert
- Vector1D.of(1.0).angle(Vector1D.ZERO);
+ @Test
+ public void testAngle_illegalNorm() {
+ // arrange
+ Vector1D v = Vector1D.of(1.0);
+
+ // act/assert
+ GeometryTestUtils.assertThrows(() -> Vector1D.ZERO.angle(v),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector1D.NaN.angle(v),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector1D.POSITIVE_INFINITY.angle(v),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector1D.NEGATIVE_INFINITY.angle(v),
+ IllegalNormException.class);
+
+ GeometryTestUtils.assertThrows(() -> v.angle(Vector1D.ZERO),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> v.angle(Vector1D.NaN),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> v.angle(Vector1D.POSITIVE_INFINITY),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> v.angle(Vector1D.NEGATIVE_INFINITY),
+ IllegalNormException.class);
}
@Test
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/RotationTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/RotationTest.java
index ca28f44..9e5bad0 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/RotationTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/RotationTest.java
@@ -17,6 +17,7 @@
package org.apache.commons.geometry.euclidean.threed;
+import org.apache.commons.geometry.core.exception.IllegalNormException;
import org.apache.commons.numbers.angle.PlaneAngleRadians;
import org.junit.Assert;
import org.junit.Test;
@@ -235,7 +236,7 @@ public class RotationTest {
try {
new Rotation(u1, u2, Vector3D.ZERO, v2);
Assert.fail("an exception should have been thrown");
- } catch (IllegalArgumentException e) {
+ } catch (IllegalNormException e) {
// expected behavior
}
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 3aa2dd7..4d34a91 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
@@ -20,6 +20,8 @@ package org.apache.commons.geometry.euclidean.threed;
import java.util.regex.Pattern;
import org.apache.commons.geometry.core.Geometry;
+import org.apache.commons.geometry.core.GeometryTestUtils;
+import org.apache.commons.geometry.core.exception.IllegalNormException;
import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
import org.apache.commons.numbers.core.Precision;
import org.apache.commons.rng.UniformRandomProvider;
@@ -144,10 +146,17 @@ public class Vector3DTest {
checkVector(Vector3D.of(x, y, z).withMagnitude(3), 3 * normX, 3 * normY, 3 * normZ);
}
- @Test(expected = IllegalStateException.class)
- public void testWithMagnitude_zeroNorm() {
+ @Test
+ public void testWithMagnitude_illegalNorm() {
// act/assert
- Vector3D.ZERO.withMagnitude(1.0);
+ GeometryTestUtils.assertThrows(() -> Vector3D.ZERO.withMagnitude(2.0),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector3D.NaN.withMagnitude(2.0),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector3D.POSITIVE_INFINITY.withMagnitude(2.0),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector3D.NEGATIVE_INFINITY.withMagnitude(2.0),
+ IllegalNormException.class);
}
@Test
@@ -250,10 +259,17 @@ public class Vector3DTest {
Assert.assertEquals(1.0, Vector3D.of(5, -4, 2).normalize().getNorm(), 1.0e-12);
}
- @Test(expected = IllegalStateException.class)
- public void testNormalize_zeroNorm() {
+ @Test
+ public void testNormalize_illegalNorm() {
// act/assert
- Vector3D.ZERO.normalize();
+ GeometryTestUtils.assertThrows(() -> Vector3D.ZERO.normalize(),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector3D.NaN.normalize(),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector3D.POSITIVE_INFINITY.normalize(),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector3D.NEGATIVE_INFINITY.normalize(),
+ IllegalNormException.class);
}
@Test
@@ -271,10 +287,17 @@ public class Vector3DTest {
Assert.assertEquals(0.0, v4.dotProduct(v4.orthogonal()), EPS);
}
- @Test(expected = IllegalStateException.class)
- public void testOrthogonal_zeroNorm() {
+ @Test
+ public void testOrthogonal_illegalNorm() {
// act/assert
- Vector3D.ZERO.orthogonal();
+ GeometryTestUtils.assertThrows(() -> Vector3D.ZERO.orthogonal(),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector3D.NaN.orthogonal(),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector3D.POSITIVE_INFINITY.orthogonal(),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector3D.NEGATIVE_INFINITY.orthogonal(),
+ IllegalNormException.class);
}
@Test
@@ -299,10 +322,29 @@ public class Vector3DTest {
Assert.assertEquals(Geometry.HALF_PI, Vector3D.PLUS_X.angle(Vector3D.MINUS_Z), tolerance);
}
- @Test(expected = IllegalStateException.class)
- public void testAngle_zeroNorm() {
+ @Test
+ public void testAngle_illegalNorm() {
+ // arrange
+ Vector3D v = Vector3D.of(1.0, 1.0, 1.0);
+
// act/assert
- Vector3D.ZERO.angle(Vector3D.PLUS_X);
+ GeometryTestUtils.assertThrows(() -> Vector3D.ZERO.angle(v),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector3D.NaN.angle(v),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector3D.POSITIVE_INFINITY.angle(v),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector3D.NEGATIVE_INFINITY.angle(v),
+ IllegalNormException.class);
+
+ GeometryTestUtils.assertThrows(() -> v.angle(Vector3D.ZERO),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> v.angle(Vector3D.NaN),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> v.angle(Vector3D.POSITIVE_INFINITY),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> v.angle(Vector3D.NEGATIVE_INFINITY),
+ IllegalNormException.class);
}
@Test
@@ -592,10 +634,20 @@ public class Vector3DTest {
checkVector(v2.project(Vector3D.of(-1.0, -1.0, -1.0)), -6.0, -6.0, -6.0);
}
- @Test(expected = IllegalStateException.class)
- public void testProject_baseHasZeroNorm() {
+ @Test
+ public void testProject_baseHasIllegalNorm() {
+ // arrange
+ Vector3D v = Vector3D.of(1.0, 1.0, 1.0);
+
// act/assert
- Vector3D.of(1.0, 1.0, 1.0).project(Vector3D.ZERO);
+ GeometryTestUtils.assertThrows(() -> v.project(Vector3D.ZERO),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> v.project(Vector3D.NaN),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> v.project(Vector3D.POSITIVE_INFINITY),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> v.project(Vector3D.NEGATIVE_INFINITY),
+ IllegalNormException.class);
}
@Test
@@ -628,10 +680,20 @@ public class Vector3DTest {
checkVector(v2.reject(Vector3D.of(-1.0, -1.0, -1.0)), 1.0, 0.0, -1.0);
}
- @Test(expected = IllegalStateException.class)
- public void testReject_baseHasZeroNorm() {
+ @Test
+ public void testReject_baseHasIllegalNorm() {
+ // arrange
+ Vector3D v = Vector3D.of(1.0, 1.0, 1.0);
+
// act/assert
- Vector3D.of(1.0, 1.0, 1.0).reject(Vector3D.ZERO);
+ GeometryTestUtils.assertThrows(() -> v.reject(Vector3D.ZERO),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> v.reject(Vector3D.NaN),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> v.reject(Vector3D.POSITIVE_INFINITY),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> v.reject(Vector3D.NEGATIVE_INFINITY),
+ IllegalNormException.class);
}
@Test
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 62e0c8e..791f1c6 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
@@ -19,6 +19,8 @@ package org.apache.commons.geometry.euclidean.twod;
import java.util.regex.Pattern;
import org.apache.commons.geometry.core.Geometry;
+import org.apache.commons.geometry.core.GeometryTestUtils;
+import org.apache.commons.geometry.core.exception.IllegalNormException;
import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
import org.apache.commons.numbers.core.Precision;
import org.junit.Assert;
@@ -159,10 +161,17 @@ public class Vector2DTest {
checkVector(Vector2D.of(0.5, 0.5).withMagnitude(2), Math.sqrt(2), Math.sqrt(2));
}
- @Test(expected = IllegalStateException.class)
- public void testWithMagnitude_zeroNorm() {
+ @Test
+ public void testWithMagnitude_illegalNorm() {
// act/assert
- Vector2D.ZERO.withMagnitude(1.0);
+ GeometryTestUtils.assertThrows(() -> Vector2D.ZERO.withMagnitude(2.0),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector2D.NaN.withMagnitude(2.0),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector2D.POSITIVE_INFINITY.withMagnitude(2.0),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector2D.NEGATIVE_INFINITY.withMagnitude(2.0),
+ IllegalNormException.class);
}
@Test
@@ -243,9 +252,17 @@ public class Vector2DTest {
checkVector(Vector2D.of(-1, 2).normalize(), -1.0/Math.sqrt(5), 2.0/Math.sqrt(5));
}
- @Test(expected = IllegalStateException.class)
- public void testNormalize_zeroNorm() {
- Vector2D.ZERO.normalize();
+ @Test
+ public void testNormalize_illegalNorm() {
+ // act/assert
+ GeometryTestUtils.assertThrows(() -> Vector2D.ZERO.normalize(),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector2D.NaN.normalize(),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector2D.POSITIVE_INFINITY.normalize(),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector2D.NEGATIVE_INFINITY.normalize(),
+ IllegalNormException.class);
}
@Test
@@ -376,9 +393,29 @@ public class Vector2DTest {
}
- @Test(expected = IllegalStateException.class)
- public void testAngle_zeroNorm() {
- Vector2D.of(1, 1).angle(Vector2D.ZERO);
+ @Test
+ public void testAngle_illegalNorm() {
+ // arrange
+ Vector2D v = Vector2D.of(1.0, 1.0);
+
+ // act/assert
+ GeometryTestUtils.assertThrows(() -> Vector2D.ZERO.angle(v),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector2D.NaN.angle(v),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector2D.POSITIVE_INFINITY.angle(v),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> Vector2D.NEGATIVE_INFINITY.angle(v),
+ IllegalNormException.class);
+
+ GeometryTestUtils.assertThrows(() -> v.angle(Vector2D.ZERO),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> v.angle(Vector2D.NaN),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> v.angle(Vector2D.POSITIVE_INFINITY),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> v.angle(Vector2D.NEGATIVE_INFINITY),
+ IllegalNormException.class);
}
@Test
@@ -418,10 +455,20 @@ public class Vector2DTest {
checkVector(v2.project(v1), (19.0 / 25.0) * 3.0, (19.0 / 25.0) * 4.0);
}
- @Test(expected = IllegalStateException.class)
- public void testProject_baseHasZeroNorm() {
+ @Test
+ public void testProject_baseHasIllegalNorm() {
+ // arrange
+ Vector2D v = Vector2D.of(1.0, 1.0);
+
// act/assert
- Vector2D.of(1.0, 1.0).project(Vector2D.ZERO);
+ GeometryTestUtils.assertThrows(() -> v.project(Vector2D.ZERO),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> v.project(Vector2D.NaN),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> v.project(Vector2D.POSITIVE_INFINITY),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> v.project(Vector2D.NEGATIVE_INFINITY),
+ IllegalNormException.class);
}
@Test
@@ -445,10 +492,20 @@ public class Vector2DTest {
checkVector(v2.reject(v1), (-32.0 / 25.0), (6.0 / 25.0) * 4.0);
}
- @Test(expected = IllegalStateException.class)
- public void testReject_baseHasZeroNorm() {
+ @Test
+ public void testReject_baseHasIllegalNorm() {
+ // arrange
+ Vector2D v = Vector2D.of(1.0, 1.0);
+
// act/assert
- Vector2D.of(1.0, 1.0).reject(Vector2D.ZERO);
+ GeometryTestUtils.assertThrows(() -> v.reject(Vector2D.ZERO),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> v.reject(Vector2D.NaN),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> v.reject(Vector2D.POSITIVE_INFINITY),
+ IllegalNormException.class);
+ GeometryTestUtils.assertThrows(() -> v.reject(Vector2D.NEGATIVE_INFINITY),
+ IllegalNormException.class);
}
@Test