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:05 UTC

[commons-geometry] branch master updated (adbdc69 -> 2e6fc6a)

This is an automated email from the ASF dual-hosted git repository.

erans pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/commons-geometry.git.


    from adbdc69  Merge branch 'GEOMETRY-9__matt'
     new b7f391a  GEOMETRY-8: adding initial exception hierarchy; using IllegalNormException in Vector classes
     new 3f7be19  merging with master
     new fc1af80  GEOMETRY-8: simplifying exception handling to use mix of JDK exceptions (for argument validation and illegal states) and GeometryException subclasses (for geometry-specific situations)
     new 1be42c8  Unchecked exceptions removed from "throws" clause.
     new 2e6fc6a  Merge branch 'GEOMETRY-8__matt'

The 5 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../org/apache/commons/geometry/core/Vector.java   |  18 +-
 .../geometry/core/exception/GeometryException.java |  25 +--
 .../core/exception/IllegalNormException.java       |  29 +--
 .../geometry/core/exception}/package-info.java     |   4 +-
 ...eFunction3N.java => GeometryInternalError.java} |  27 +--
 .../commons/geometry/core/GeometryTestUtils.java   |  32 ++++
 .../commons/geometry/enclosing/WelzlEncloser.java  |   3 +-
 .../geometry/euclidean}/internal/Vectors.java      |  31 ++-
 .../commons/geometry/euclidean/oned/Vector1D.java  |  41 ++--
 .../commons/geometry/euclidean/threed/Plane.java   |   7 +-
 .../commons/geometry/euclidean/threed/Point3D.java |   2 +-
 .../geometry/euclidean/threed/Rotation.java        | 209 ++++++++++++---------
 .../geometry/euclidean/threed/Vector3D.java        |  40 ++--
 .../commons/geometry/euclidean/twod/Point2D.java   |   2 +-
 .../commons/geometry/euclidean/twod/Vector2D.java  |  35 ++--
 .../geometry/euclidean}/internal/VectorsTest.java  |  40 +++-
 .../geometry/euclidean/oned/Vector1DTest.java      |  89 ++++++---
 .../geometry/euclidean/threed/RotationTest.java    |  17 +-
 .../geometry/euclidean/threed/Vector3DTest.java    |  98 ++++++++--
 .../geometry/euclidean/twod/Vector2DTest.java      |  87 +++++++--
 .../commons/geometry/spherical/oned/ArcsSet.java   |  52 ++---
 .../spherical/twod/PropertiesComputer.java         |   3 +-
 .../geometry/spherical/oned/ArcsSetTest.java       |   2 +-
 23 files changed, 576 insertions(+), 317 deletions(-)
 copy commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/enclosing/Encloser.java => commons-geometry-core/src/main/java/org/apache/commons/geometry/core/exception/GeometryException.java (60%)
 copy commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/enclosing/Encloser.java => commons-geometry-core/src/main/java/org/apache/commons/geometry/core/exception/IllegalNormException.java (55%)
 copy {commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean => commons-geometry-core/src/main/java/org/apache/commons/geometry/core/exception}/package-info.java (86%)
 copy commons-geometry-core/src/main/java/org/apache/commons/geometry/core/internal/{DoubleFunction3N.java => GeometryInternalError.java} (50%)
 rename {commons-geometry-core/src/main/java/org/apache/commons/geometry/core => commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean}/internal/Vectors.java (87%)
 rename {commons-geometry-core/src/test/java/org/apache/commons/geometry/core => commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean}/internal/VectorsTest.java (78%)


[commons-geometry] 02/05: merging with master

Posted by er...@apache.org.
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 3f7be19626e2a828ca4595deb6dac4f767f73ce4
Merge: b7f391a adbdc69
Author: Matt Juntunen <ma...@hotmail.com>
AuthorDate: Thu Sep 13 22:34:19 2018 -0400

    merging with master

 .../geometry/core/internal/SimpleTupleFormat.java    | 20 ++++++++++----------
 .../geometry/enclosing/WelzlEncloser3DTest.java      |  2 +-
 .../commons/geometry/euclidean/oned/Point1D.java     |  2 +-
 .../commons/geometry/euclidean/oned/Vector1D.java    | 11 +++++------
 .../commons/geometry/euclidean/threed/Line.java      |  2 +-
 .../commons/geometry/euclidean/threed/Plane.java     |  4 ++--
 .../commons/geometry/euclidean/threed/Point3D.java   |  2 +-
 .../commons/geometry/euclidean/threed/Rotation.java  |  4 ++--
 .../commons/geometry/euclidean/threed/SubLine.java   |  2 +-
 .../commons/geometry/euclidean/threed/Vector3D.java  | 16 ++++++++--------
 .../commons/geometry/euclidean/twod/NestedLoops.java |  4 ++--
 .../commons/geometry/euclidean/twod/Point2D.java     |  2 +-
 .../commons/geometry/euclidean/twod/Vector2D.java    | 14 +++++++-------
 .../geometry/euclidean/twod/hull/ConvexHull2D.java   |  2 +-
 .../commons/geometry/spherical/oned/S1Point.java     |  2 +-
 .../geometry/spherical/twod/EdgesBuilder.java        |  2 +-
 .../commons/geometry/spherical/twod/S2Point.java     |  2 +-
 .../spherical/twod/SphericalPolygonsSet.java         |  4 ++--
 18 files changed, 48 insertions(+), 49 deletions(-)

diff --cc commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Vector1D.java
index c5d455d,10fabed..26df5d1
--- 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 +17,9 @@@
  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.
@@@ -154,10 -159,15 +153,10 @@@ public final class Vector1D extends Car
  
      /** {@inheritDoc} */
      @Override
-     public Vector1D normalize() throws IllegalNormException {
+     public Vector1D normalize() {
 -        final double x = getX();
 -        if (x > 0.0) {
 -            return ONE;
 -        }
 -        else if (x < 0.0) {
 -            return MINUS_ONE;
 -        }
 -        throw new ZeroNormException();
 +        Vectors.checkFiniteNonZeroNorm(getNorm());
 +
 +        return (getX() > 0.0) ? ONE : MINUS_ONE;
      }
  
      /** {@inheritDoc} */
@@@ -200,9 -210,10 +199,9 @@@
       * <p>For the one-dimensional case, this method simply returns the current instance.</p>
       */
      @Override
-     public Vector1D project(final Vector1D base) throws IllegalNormException {
+     public Vector1D project(final Vector1D base) {
 -        if (base.getX() == 0) {
 -            throw new ZeroNormException(ZeroNormException.INVALID_BASE);
 -        }
 +        Vectors.checkFiniteNonZeroNorm(base.getNorm());
 +
          return this;
      }
  
@@@ -210,9 -221,10 +209,9 @@@
       * <p>For the one-dimensional case, this method simply returns the zero vector.</p>
       */
      @Override
-     public Vector1D reject(final Vector1D base) throws IllegalNormException {
+     public Vector1D reject(final Vector1D base) {
 -        if (base.getX() == 0) {
 -            throw new ZeroNormException(ZeroNormException.INVALID_BASE);
 -        }
 +        Vectors.checkFiniteNonZeroNorm(base.getNorm());
 +
          return Vector1D.ZERO;
      }
  
@@@ -221,10 -233,7 +220,10 @@@
       * the same sign and {@code pi} if they are opposite.</p>
       */
      @Override
-     public double angle(final Vector1D v) throws IllegalNormException {
+     public double angle(final Vector1D v) {
 +        Vectors.checkFiniteNonZeroNorm(getNorm());
 +        Vectors.checkFiniteNonZeroNorm(v.getNorm());
 +
          final double sig1 = Math.signum(getX());
          final double sig2 = Math.signum(v.getX());
  
diff --cc commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Vector3D.java
index d8de801,75b797a..5c5317c
--- 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
@@@ -188,8 -188,8 +188,8 @@@ public final class Vector3D extends Car
  
      /** {@inheritDoc} */
      @Override
-     public Vector3D normalize() throws IllegalNormException {
+     public Vector3D normalize() {
 -        return scalarMultiply(1.0 / getNonZeroNorm());
 +        return scalarMultiply(1.0 / getFiniteNonZeroNorm());
      }
  
      /** Get a vector orthogonal to the instance.
@@@ -205,11 -205,10 +205,11 @@@
       *   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 IllegalNormException {
+     public Vector3D orthogonal() {
 -        double threshold = 0.6 * getNonZeroNorm();
 +        double threshold = 0.6 * getFiniteNonZeroNorm();
  
          final double x = getX();
          final double y = getY();
@@@ -234,8 -233,8 +234,8 @@@
       * other.</p>
       */
      @Override
-     public double angle(Vector3D v) throws IllegalNormException {
+     public double angle(Vector3D v) {
 -        double normProduct = getNonZeroNorm() * v.getNonZeroNorm();
 +        double normProduct = getFiniteNonZeroNorm() * v.getFiniteNonZeroNorm();
  
          double dot = dotProduct(v);
          double threshold = normProduct * 0.9999;
@@@ -383,13 -382,17 +383,13 @@@
          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 getFiniteNonZeroNorm() throws IllegalNormException {
 -    private double getNonZeroNorm() {
 -        final double n = getNorm();
 -        if (n == 0) {
 -            throw new ZeroNormException();
 -        }
 -
 -        return n;
++    private double getFiniteNonZeroNorm() {
 +        return Vectors.checkFiniteNonZeroNorm(getNorm());
      }
  
      /** Returns a component of the current instance relative to the given base
@@@ -401,14 -404,17 +401,14 @@@
       *      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 IllegalNormException {
+     private Vector3D getComponent(Vector3D base, boolean reject) {
          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 --cc commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Vector2D.java
index 298d052,95313ae..1d7be1c
--- 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
@@@ -171,8 -171,8 +171,8 @@@ public final class Vector2D extends Car
  
      /** {@inheritDoc} */
      @Override
-     public Vector2D normalize() throws IllegalNormException {
+     public Vector2D normalize() {
 -        return scalarMultiply(1.0 / getNonZeroNorm());
 +        return scalarMultiply(1.0 / getFiniteNonZeroNorm());
      }
  
      /** {@inheritDoc} */
@@@ -231,8 -231,8 +231,8 @@@
       * other.</p>
       */
      @Override
-     public double angle(Vector2D v) throws IllegalNormException {
+     public double angle(Vector2D v) {
 -        double normProduct = getNonZeroNorm() * v.getNonZeroNorm();
 +        double normProduct = getFiniteNonZeroNorm() * v.getFiniteNonZeroNorm();
  
          double dot = dotProduct(v);
          double threshold = normProduct * 0.9999;
@@@ -328,13 -328,17 +328,13 @@@
          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 getFiniteNonZeroNorm() throws IllegalNormException {
 -    private double getNonZeroNorm() {
 -        final double n = getNorm();
 -        if (n == 0) {
 -            throw new ZeroNormException();
 -        }
 -
 -        return n;
++    private double getFiniteNonZeroNorm() {
 +        return Vectors.checkFiniteNonZeroNorm(getNorm());
      }
  
      /** Returns a component of the current instance relative to the given base
@@@ -346,14 -350,17 +346,14 @@@
       *      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 IllegalNormException {
+     private Vector2D getComponent(Vector2D base, boolean reject) {
          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();


[commons-geometry] 03/05: GEOMETRY-8: simplifying exception handling to use mix of JDK exceptions (for argument validation and illegal states) and GeometryException subclasses (for geometry-specific situations)

Posted by er...@apache.org.
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 fc1af80256cb7b1f562aab0841267565695215fd
Author: Matt Juntunen <ma...@hotmail.com>
AuthorDate: Fri Sep 14 00:23:28 2018 -0400

    GEOMETRY-8: simplifying exception handling to use mix of JDK exceptions (for argument validation and illegal states) and GeometryException subclasses (for geometry-specific situations)
---
 .../geometry/core/exception/GeometryException.java |   4 +-
 .../core/exception/GeometryValueException.java     |  30 -----
 .../core/exception/IllegalNormException.java       |  12 +-
 .../geometry/core/exception/package-info.java      |   2 +-
 .../GeometryInternalError.java}                    |  22 ++--
 .../commons/geometry/enclosing/WelzlEncloser.java  |   3 +-
 .../geometry/euclidean/internal/Vectors.java       |  16 ++-
 .../commons/geometry/euclidean/oned/Vector1D.java  |  12 +-
 .../commons/geometry/euclidean/threed/Plane.java   |   7 +-
 .../geometry/euclidean/threed/Rotation.java        | 124 ++++++++++++++-------
 .../geometry/euclidean/threed/Vector3D.java        |   4 +-
 .../commons/geometry/euclidean/twod/Vector2D.java  |   4 +-
 .../geometry/euclidean/internal/VectorsTest.java   |  36 ++++--
 .../geometry/euclidean/threed/RotationTest.java    |  14 ++-
 .../commons/geometry/spherical/oned/ArcsSet.java   |  44 ++------
 .../spherical/twod/PropertiesComputer.java         |   3 +-
 .../geometry/spherical/oned/ArcsSetTest.java       |   2 +-
 17 files changed, 184 insertions(+), 155 deletions(-)

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
index 48e4b2a..57462be 100644
--- 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
@@ -16,7 +16,9 @@
  */
 package org.apache.commons.geometry.core.exception;
 
-/** Base class for geometry exceptions.
+/** Base class for geometry exceptions. The semantics of this class
+ * are intended to be similar to {@link java.lang.ArithmeticException}
+ * but for geometric operations.
  */
 public class GeometryException extends RuntimeException {
 
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
deleted file mode 100644
index 5d7b0d6..0000000
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/exception/GeometryValueException.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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
index b0d80e8..26fc11c 100644
--- 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
@@ -19,16 +19,22 @@ 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 {
+public class IllegalNormException extends GeometryException {
 
     /** Serializable version identifier */
     private static final long serialVersionUID = 20180909L;
 
-    /**
-     * Simple constructor accepting the illegal norm value.
+    /** Simple constructor accepting the illegal norm value.
      * @param norm the illegal norm value
      */
     public IllegalNormException(double norm) {
         super("Illegal norm: " + norm);
     }
+
+    /** Constructor accepting an error message.
+     * @param msg the error message
+     */
+    public IllegalNormException(String msg) {
+        super(msg);
+    }
 }
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
index 8180f81..2b7d21b 100644
--- 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
@@ -17,7 +17,7 @@
 /**
  *
  * <p>
- * This package contains exception types used by this library.
+ * This package contains specialized exception types used by this library.
  * </p>
  */
 package org.apache.commons.geometry.core.exception;
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/internal/GeometryInternalError.java
similarity index 50%
rename from commons-geometry-core/src/main/java/org/apache/commons/geometry/core/exception/GeometryStateException.java
rename to commons-geometry-core/src/main/java/org/apache/commons/geometry/core/internal/GeometryInternalError.java
index 4a8080e..219ccdb 100644
--- 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/internal/GeometryInternalError.java
@@ -14,17 +14,25 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.commons.geometry.core.exception;
+package org.apache.commons.geometry.core.internal;
 
-public class GeometryStateException extends GeometryException {
+/** Exception thrown when something that should not happen does happen.
+ * This class is not intended to be part of the public API and should
+ * never be seen by the user when algorithms are functioning correctly.
+ */
+public class GeometryInternalError extends IllegalStateException {
+
+    /** Error message used for exceptions of this type. */
+    private static final String ERROR_MSG = "An internal geometry error occurred. This most often indicates an " +
+            "error in the algorithm implementation than in the calling code or data. Please file a bug report " +
+            "with the developers.";
 
     /** Serializable version identifier */
-    private static final long serialVersionUID = 20180909L;
+    private static final long serialVersionUID = 20180913L;
 
-    /** Simple constructor with error message.
-     * @param msg exception message string
+    /** Simple constructor with a default error message.
      */
-    public GeometryStateException(String msg) {
-        super(msg);
+    public GeometryInternalError() {
+        super(ERROR_MSG);
     }
 }
diff --git a/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/enclosing/WelzlEncloser.java b/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/enclosing/WelzlEncloser.java
index 4ec5ad5..65dbc2a 100644
--- a/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/enclosing/WelzlEncloser.java
+++ b/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/enclosing/WelzlEncloser.java
@@ -20,6 +20,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.commons.geometry.core.Point;
+import org.apache.commons.geometry.core.internal.GeometryInternalError;
 
 /** Class implementing Emo Welzl algorithm to find the smallest enclosing ball in linear time.
  * <p>
@@ -98,7 +99,7 @@ public class WelzlEncloser<P extends Point<P>> implements Encloser<P> {
             ball = moveToFrontBall(extreme, extreme.size(), support);
             if (ball.getRadius() < savedBall.getRadius()) {
                 // this should never happen
-                throw new IllegalStateException("Please file a bug report");
+                throw new GeometryInternalError();
             }
 
             // it was an interesting point, move it to the front
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 cbb19b2..31ec162 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
@@ -25,17 +25,27 @@ public final class Vectors {
     /** Private constructor. */
     private Vectors() {}
 
+    /** Returns true if the given value is finite (ie, not NaN or inifinite)
+     * and not equal to zero.
+     * @param value the value to test
+     * @return true if {@code value} is not NaN, infinite, or zero; otherwise
+     *      false
+     */
+    public static boolean isFiniteNonZero(final double value) {
+        return Double.isFinite(value) && value != 0.0;
+    }
+
 
     /** 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.
+     * to allow this method to be called inline.
      * @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) {
+    public static double ensureFiniteNonZeroNorm(final double norm) throws IllegalNormException {
+        if (!isFiniteNonZero(norm)) {
             throw new IllegalNormException(norm);
         }
 
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 26df5d1..79a4d35 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
@@ -116,7 +116,7 @@ public final class Vector1D extends Cartesian1D implements EuclideanVector<Point
     /** {@inheritDoc} */
     @Override
     public Vector1D withMagnitude(double magnitude) {
-        Vectors.checkFiniteNonZeroNorm(getNorm());
+        Vectors.ensureFiniteNonZeroNorm(getNorm());
 
         return (getX() > 0.0)? new Vector1D(magnitude) : new Vector1D(-magnitude);
     }
@@ -154,7 +154,7 @@ public final class Vector1D extends Cartesian1D implements EuclideanVector<Point
     /** {@inheritDoc} */
     @Override
     public Vector1D normalize() {
-        Vectors.checkFiniteNonZeroNorm(getNorm());
+        Vectors.ensureFiniteNonZeroNorm(getNorm());
 
         return (getX() > 0.0) ? ONE : MINUS_ONE;
     }
@@ -200,7 +200,7 @@ public final class Vector1D extends Cartesian1D implements EuclideanVector<Point
      */
     @Override
     public Vector1D project(final Vector1D base) {
-        Vectors.checkFiniteNonZeroNorm(base.getNorm());
+        Vectors.ensureFiniteNonZeroNorm(base.getNorm());
 
         return this;
     }
@@ -210,7 +210,7 @@ public final class Vector1D extends Cartesian1D implements EuclideanVector<Point
      */
     @Override
     public Vector1D reject(final Vector1D base) {
-        Vectors.checkFiniteNonZeroNorm(base.getNorm());
+        Vectors.ensureFiniteNonZeroNorm(base.getNorm());
 
         return Vector1D.ZERO;
     }
@@ -221,8 +221,8 @@ public final class Vector1D extends Cartesian1D implements EuclideanVector<Point
      */
     @Override
     public double angle(final Vector1D v) {
-        Vectors.checkFiniteNonZeroNorm(getNorm());
-        Vectors.checkFiniteNonZeroNorm(v.getNorm());
+        Vectors.ensureFiniteNonZeroNorm(getNorm());
+        Vectors.ensureFiniteNonZeroNorm(v.getNorm());
 
         final double sig1 = Math.signum(getX());
         final double sig2 = Math.signum(v.getX());
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 bc3c040..424fbb3 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
@@ -18,6 +18,7 @@ package org.apache.commons.geometry.euclidean.threed;
 
 import org.apache.commons.geometry.core.partitioning.Embedding;
 import org.apache.commons.geometry.core.partitioning.Hyperplane;
+import org.apache.commons.geometry.euclidean.internal.Vectors;
 import org.apache.commons.geometry.euclidean.oned.Point1D;
 import org.apache.commons.geometry.euclidean.twod.Point2D;
 import org.apache.commons.geometry.euclidean.twod.PolygonsSet;
@@ -141,10 +142,8 @@ public class Plane implements Hyperplane<Point3D>, Embedding<Point3D, Point2D> {
      * @exception IllegalArgumentException if the normal norm is too close to zero
      */
     private void setNormal(final Vector3D normal) {
-        final double norm = normal.getNorm();
-        if (norm < 1.0e-10) {
-            throw new IllegalArgumentException("Norm is zero");
-        }
+        final double norm = Vectors.ensureFiniteNonZeroNorm(normal.getNorm());
+
         w = Vector3D.linearCombination(1.0 / norm, normal);
     }
 
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 2e9b63d..466aedc 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,7 +19,9 @@ package org.apache.commons.geometry.euclidean.threed;
 
 import java.io.Serializable;
 
+import org.apache.commons.geometry.core.exception.GeometryException;
 import org.apache.commons.geometry.core.exception.IllegalNormException;
+import org.apache.commons.geometry.euclidean.internal.Vectors;
 import org.apache.commons.numbers.arrays.LinearCombination;
 
 /**
@@ -97,12 +99,6 @@ public class Rotation implements Serializable {
   /** Serializable version identifier */
   private static final long serialVersionUID = 20180903L;
 
-  /** Error message for Cardan angle singularities */
-  private static final String CARDAN_SINGULARITY_MSG = "Cardan angles singularity";
-
-  /** Error message for Euler angle singularities */
-  private static final String EULER_SINGULARITY_MSG = "Euler angles singularity";
-
   /** Scalar coordinate of the quaternion. */
   private final double q0;
 
@@ -172,14 +168,14 @@ public class Rotation implements Serializable {
    * @param axis axis around which to rotate
    * @param angle rotation angle
    * @param convention convention to use for the semantics of the angle
-   * @exception IllegalArgumentException if the axis norm is zero
+   * @exception IllegalNormException if the axis norm is zero, NaN, or infinite
    */
   public Rotation(final Vector3D axis, final double angle, final RotationConvention convention)
-      throws IllegalArgumentException {
+      throws IllegalNormException {
 
     double norm = axis.getNorm();
-    if (norm == 0) {
-      throw new IllegalArgumentException("Zero norm for rotation axis");
+    if (!Vectors.isFiniteNonZero(norm)) {
+      throw new IllegalNormException("Illegal norm for rotation axis: " + norm);
     }
 
     double halfAngle = convention == RotationConvention.VECTOR_OPERATOR ? -0.5 * angle : +0.5 * angle;
@@ -320,13 +316,13 @@ public class Rotation implements Serializable {
 
    * @param u origin vector
    * @param v desired image of u by the rotation
-   * @exception IllegalArgumentException if the norm of one of the vectors is zero
+   * @exception IllegalNormException if the norm of one of the vectors is zero, NaN, or infinite
    */
   public Rotation(Vector3D u, Vector3D v) {
 
     double normProduct = u.getNorm() * v.getNorm();
-    if (normProduct == 0) {
-        throw new IllegalArgumentException("Zero norm for rotation defining vector");
+    if (!Vectors.isFiniteNonZero(normProduct)) {
+        throw new IllegalNormException("Illegal norm for rotation defining vector: " + normProduct);
     }
 
     double dot = u.dotProduct(v);
@@ -568,13 +564,13 @@ public class Rotation implements Serializable {
 
    * @param order rotation order to use
    * @return an array of three angles, in the order specified by the set
-   * @exception IllegalStateException if the rotation is
+   * @exception AngleSetSingularityException if the rotation is
    * singular with respect to the angles set specified
    * @deprecated as of 3.6, replaced with {@link #getAngles(RotationOrder, RotationConvention)}
    */
   @Deprecated
   public double[] getAngles(RotationOrder order)
-      throws IllegalStateException {
+      throws AngleSetSingularityException {
       return getAngles(order, RotationConvention.VECTOR_OPERATOR);
   }
 
@@ -611,11 +607,11 @@ public class Rotation implements Serializable {
    * @param order rotation order to use
    * @param convention convention to use for the semantics of the angle
    * @return an array of three angles, in the order specified by the set
-   * @exception IllegalStateException if the rotation is
-   * singular with respect to the angles set specified
+   * @exception AngleSetSingularityException if the rotation is
+   * singular with respect to the angle set specified
    */
   public double[] getAngles(RotationOrder order, RotationConvention convention)
-      throws IllegalStateException {
+      throws AngleSetSingularityException {
 
       if (convention == RotationConvention.VECTOR_OPERATOR) {
           if (order == RotationOrder.XYZ) {
@@ -628,7 +624,7 @@ public class Rotation implements Serializable {
               Vector3D v1 = applyTo(Vector3D.PLUS_Z);
               Vector3D v2 = applyInverseTo(Vector3D.PLUS_X);
               if  ((v2.getZ() < -0.9999999999) || (v2.getZ() > 0.9999999999)) {
-                  throw new IllegalStateException(CARDAN_SINGULARITY_MSG);
+                  throw new CardanSingularityException();
               }
               return new double[] {
                   Math.atan2(-(v1.getY()), v1.getZ()),
@@ -646,7 +642,7 @@ public class Rotation implements Serializable {
               Vector3D v1 = applyTo(Vector3D.PLUS_Y);
               Vector3D v2 = applyInverseTo(Vector3D.PLUS_X);
               if ((v2.getY() < -0.9999999999) || (v2.getY() > 0.9999999999)) {
-                  throw new IllegalStateException(CARDAN_SINGULARITY_MSG);
+                  throw new CardanSingularityException();
               }
               return new double[] {
                   Math.atan2(v1.getZ(), v1.getY()),
@@ -664,7 +660,7 @@ public class Rotation implements Serializable {
               Vector3D v1 = applyTo(Vector3D.PLUS_Z);
               Vector3D v2 = applyInverseTo(Vector3D.PLUS_Y);
               if ((v2.getZ() < -0.9999999999) || (v2.getZ() > 0.9999999999)) {
-                  throw new IllegalStateException(CARDAN_SINGULARITY_MSG);
+                  throw new CardanSingularityException();
               }
               return new double[] {
                   Math.atan2(v1.getX(), v1.getZ()),
@@ -682,7 +678,7 @@ public class Rotation implements Serializable {
               Vector3D v1 = applyTo(Vector3D.PLUS_X);
               Vector3D v2 = applyInverseTo(Vector3D.PLUS_Y);
               if ((v2.getX() < -0.9999999999) || (v2.getX() > 0.9999999999)) {
-                  throw new IllegalStateException(CARDAN_SINGULARITY_MSG);
+                  throw new CardanSingularityException();
               }
               return new double[] {
                   Math.atan2(-(v1.getZ()), v1.getX()),
@@ -700,7 +696,7 @@ public class Rotation implements Serializable {
               Vector3D v1 = applyTo(Vector3D.PLUS_Y);
               Vector3D v2 = applyInverseTo(Vector3D.PLUS_Z);
               if ((v2.getY() < -0.9999999999) || (v2.getY() > 0.9999999999)) {
-                  throw new IllegalStateException(CARDAN_SINGULARITY_MSG);
+                  throw new CardanSingularityException();
               }
               return new double[] {
                   Math.atan2(-(v1.getX()), v1.getY()),
@@ -718,7 +714,7 @@ public class Rotation implements Serializable {
               Vector3D v1 = applyTo(Vector3D.PLUS_X);
               Vector3D v2 = applyInverseTo(Vector3D.PLUS_Z);
               if ((v2.getX() < -0.9999999999) || (v2.getX() > 0.9999999999)) {
-                  throw new IllegalStateException(CARDAN_SINGULARITY_MSG);
+                  throw new CardanSingularityException();
               }
               return new double[] {
                   Math.atan2(v1.getY(), v1.getX()),
@@ -736,7 +732,7 @@ public class Rotation implements Serializable {
               Vector3D v1 = applyTo(Vector3D.PLUS_X);
               Vector3D v2 = applyInverseTo(Vector3D.PLUS_X);
               if ((v2.getX() < -0.9999999999) || (v2.getX() > 0.9999999999)) {
-                  throw new IllegalStateException(EULER_SINGULARITY_MSG);
+                  throw new EulerSingularityException();
               }
               return new double[] {
                   Math.atan2(v1.getY(), -v1.getZ()),
@@ -754,7 +750,7 @@ public class Rotation implements Serializable {
               Vector3D v1 = applyTo(Vector3D.PLUS_X);
               Vector3D v2 = applyInverseTo(Vector3D.PLUS_X);
               if ((v2.getX() < -0.9999999999) || (v2.getX() > 0.9999999999)) {
-                  throw new IllegalStateException(EULER_SINGULARITY_MSG);
+                  throw new EulerSingularityException();
               }
               return new double[] {
                   Math.atan2(v1.getZ(), v1.getY()),
@@ -772,7 +768,7 @@ public class Rotation implements Serializable {
               Vector3D v1 = applyTo(Vector3D.PLUS_Y);
               Vector3D v2 = applyInverseTo(Vector3D.PLUS_Y);
               if ((v2.getY() < -0.9999999999) || (v2.getY() > 0.9999999999)) {
-                  throw new IllegalStateException(EULER_SINGULARITY_MSG);
+                  throw new EulerSingularityException();
               }
               return new double[] {
                   Math.atan2(v1.getX(), v1.getZ()),
@@ -790,7 +786,7 @@ public class Rotation implements Serializable {
               Vector3D v1 = applyTo(Vector3D.PLUS_Y);
               Vector3D v2 = applyInverseTo(Vector3D.PLUS_Y);
               if ((v2.getY() < -0.9999999999) || (v2.getY() > 0.9999999999)) {
-                  throw new IllegalStateException(EULER_SINGULARITY_MSG);
+                  throw new EulerSingularityException();
               }
               return new double[] {
                   Math.atan2(v1.getZ(), -v1.getX()),
@@ -808,7 +804,7 @@ public class Rotation implements Serializable {
               Vector3D v1 = applyTo(Vector3D.PLUS_Z);
               Vector3D v2 = applyInverseTo(Vector3D.PLUS_Z);
               if ((v2.getZ() < -0.9999999999) || (v2.getZ() > 0.9999999999)) {
-                  throw new IllegalStateException(EULER_SINGULARITY_MSG);
+                  throw new EulerSingularityException();
               }
               return new double[] {
                   Math.atan2(v1.getX(), -v1.getY()),
@@ -826,7 +822,7 @@ public class Rotation implements Serializable {
               Vector3D v1 = applyTo(Vector3D.PLUS_Z);
               Vector3D v2 = applyInverseTo(Vector3D.PLUS_Z);
               if ((v2.getZ() < -0.9999999999) || (v2.getZ() > 0.9999999999)) {
-                  throw new IllegalStateException(EULER_SINGULARITY_MSG);
+                  throw new EulerSingularityException();
               }
               return new double[] {
                   Math.atan2(v1.getY(), v1.getX()),
@@ -846,7 +842,7 @@ public class Rotation implements Serializable {
               Vector3D v1 = applyTo(Vector3D.PLUS_X);
               Vector3D v2 = applyInverseTo(Vector3D.PLUS_Z);
               if ((v2.getX() < -0.9999999999) || (v2.getX() > 0.9999999999)) {
-                  throw new IllegalStateException(CARDAN_SINGULARITY_MSG);
+                  throw new CardanSingularityException();
               }
               return new double[] {
                   Math.atan2(-v2.getY(), v2.getZ()),
@@ -864,7 +860,7 @@ public class Rotation implements Serializable {
               Vector3D v1 = applyTo(Vector3D.PLUS_X);
               Vector3D v2 = applyInverseTo(Vector3D.PLUS_Y);
               if ((v2.getX() < -0.9999999999) || (v2.getX() > 0.9999999999)) {
-                  throw new IllegalStateException(CARDAN_SINGULARITY_MSG);
+                  throw new CardanSingularityException();
               }
               return new double[] {
                   Math.atan2(v2.getZ(), v2.getY()),
@@ -882,7 +878,7 @@ public class Rotation implements Serializable {
               Vector3D v1 = applyTo(Vector3D.PLUS_Y);
               Vector3D v2 = applyInverseTo(Vector3D.PLUS_Z);
               if ((v2.getY() < -0.9999999999) || (v2.getY() > 0.9999999999)) {
-                  throw new IllegalStateException(CARDAN_SINGULARITY_MSG);
+                  throw new CardanSingularityException();
               }
               return new double[] {
                   Math.atan2(v2.getX(), v2.getZ()),
@@ -900,7 +896,7 @@ public class Rotation implements Serializable {
               Vector3D v1 = applyTo(Vector3D.PLUS_Y);
               Vector3D v2 = applyInverseTo(Vector3D.PLUS_X);
               if ((v2.getY() < -0.9999999999) || (v2.getY() > 0.9999999999)) {
-                  throw new IllegalStateException(CARDAN_SINGULARITY_MSG);
+                  throw new CardanSingularityException();
               }
               return new double[] {
                   Math.atan2(-v2.getZ(), v2.getX()),
@@ -918,7 +914,7 @@ public class Rotation implements Serializable {
               Vector3D v1 = applyTo(Vector3D.PLUS_Z);
               Vector3D v2 = applyInverseTo(Vector3D.PLUS_Y);
               if ((v2.getZ() < -0.9999999999) || (v2.getZ() > 0.9999999999)) {
-                  throw new IllegalStateException(CARDAN_SINGULARITY_MSG);
+                  throw new CardanSingularityException();
               }
               return new double[] {
                   Math.atan2(-v2.getX(), v2.getY()),
@@ -936,7 +932,7 @@ public class Rotation implements Serializable {
               Vector3D v1 = applyTo(Vector3D.PLUS_Z);
               Vector3D v2 = applyInverseTo(Vector3D.PLUS_X);
               if  ((v2.getZ() < -0.9999999999) || (v2.getZ() > 0.9999999999)) {
-                  throw new IllegalStateException(CARDAN_SINGULARITY_MSG);
+                  throw new CardanSingularityException();
               }
               return new double[] {
                   Math.atan2(v2.getY(), v2.getX()),
@@ -954,7 +950,7 @@ public class Rotation implements Serializable {
               Vector3D v1 = applyTo(Vector3D.PLUS_X);
               Vector3D v2 = applyInverseTo(Vector3D.PLUS_X);
               if ((v2.getX() < -0.9999999999) || (v2.getX() > 0.9999999999)) {
-                  throw new IllegalStateException(EULER_SINGULARITY_MSG);
+                  throw new EulerSingularityException();
               }
               return new double[] {
                   Math.atan2(v2.getY(), -v2.getZ()),
@@ -972,7 +968,7 @@ public class Rotation implements Serializable {
               Vector3D v1 = applyTo(Vector3D.PLUS_X);
               Vector3D v2 = applyInverseTo(Vector3D.PLUS_X);
               if ((v2.getX() < -0.9999999999) || (v2.getX() > 0.9999999999)) {
-                  throw new IllegalStateException(EULER_SINGULARITY_MSG);
+                  throw new EulerSingularityException();
               }
               return new double[] {
                   Math.atan2(v2.getZ(), v2.getY()),
@@ -990,7 +986,7 @@ public class Rotation implements Serializable {
               Vector3D v1 = applyTo(Vector3D.PLUS_Y);
               Vector3D v2 = applyInverseTo(Vector3D.PLUS_Y);
               if ((v2.getY() < -0.9999999999) || (v2.getY() > 0.9999999999)) {
-                  throw new IllegalStateException(EULER_SINGULARITY_MSG);
+                  throw new EulerSingularityException();
               }
               return new double[] {
                   Math.atan2(v2.getX(), v2.getZ()),
@@ -1008,7 +1004,7 @@ public class Rotation implements Serializable {
               Vector3D v1 = applyTo(Vector3D.PLUS_Y);
               Vector3D v2 = applyInverseTo(Vector3D.PLUS_Y);
               if ((v2.getY() < -0.9999999999) || (v2.getY() > 0.9999999999)) {
-                  throw new IllegalStateException(EULER_SINGULARITY_MSG);
+                  throw new EulerSingularityException();
               }
               return new double[] {
                   Math.atan2(v2.getZ(), -v2.getX()),
@@ -1026,7 +1022,7 @@ public class Rotation implements Serializable {
               Vector3D v1 = applyTo(Vector3D.PLUS_Z);
               Vector3D v2 = applyInverseTo(Vector3D.PLUS_Z);
               if ((v2.getZ() < -0.9999999999) || (v2.getZ() > 0.9999999999)) {
-                  throw new IllegalStateException(EULER_SINGULARITY_MSG);
+                  throw new EulerSingularityException();
               }
               return new double[] {
                   Math.atan2(v2.getX(), -v2.getY()),
@@ -1044,7 +1040,7 @@ public class Rotation implements Serializable {
               Vector3D v1 = applyTo(Vector3D.PLUS_Z);
               Vector3D v2 = applyInverseTo(Vector3D.PLUS_Z);
               if ((v2.getZ() < -0.9999999999) || (v2.getZ() > 0.9999999999)) {
-                  throw new IllegalStateException(EULER_SINGULARITY_MSG);
+                  throw new EulerSingularityException();
               }
               return new double[] {
                   Math.atan2(v2.getY(), v2.getX()),
@@ -1411,4 +1407,48 @@ public class Rotation implements Serializable {
       return r1.composeInverseInternal(r2).getAngle();
   }
 
+  /** Exception thrown when an angle set encounters a singularity.
+   */
+  public static class AngleSetSingularityException extends GeometryException {
+
+    /** Serializable version identifier */
+    private static final long serialVersionUID = 20180913L;
+
+    /** Simple constructor with an error message.
+     * @param msg error message
+     */
+    public AngleSetSingularityException(String msg) {
+      super(msg);
+    }
+  }
+
+  /** Exception thrown when a Cardan angles singularity is encountered.
+   */
+  public static class CardanSingularityException extends AngleSetSingularityException {
+
+    /** Serializable version identifier */
+    private static final long serialVersionUID = 20180913L;
+
+    /**
+     * Simple constructor.
+     */
+    public CardanSingularityException() {
+      super("Cardan angles singularity");
+    }
+  }
+
+  /** Exception thrown when an Euler angles singularity is encountered.
+   */
+  public static class EulerSingularityException extends AngleSetSingularityException {
+
+    /** Serializable version identifier */
+    private static final long serialVersionUID = 20180913L;
+
+    /**
+     * Simple constructor.
+     */
+    public EulerSingularityException() {
+      super("Euler angles singularity");
+    }
+  }
 }
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 5c5317c..4b96f43 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
@@ -389,7 +389,7 @@ public final class Vector3D extends Cartesian3D implements EuclideanVector<Point
      * @throws IllegalNormException if the norm is zero, NaN, or infinite
      */
     private double getFiniteNonZeroNorm() {
-        return Vectors.checkFiniteNonZeroNorm(getNorm());
+        return Vectors.ensureFiniteNonZeroNorm(getNorm());
     }
 
     /** Returns a component of the current instance relative to the given base
@@ -406,7 +406,7 @@ public final class Vector3D extends Cartesian3D implements EuclideanVector<Point
     private Vector3D getComponent(Vector3D base, boolean reject) {
         final double aDotB = dotProduct(base);
 
-        final double baseMag = Vectors.checkFiniteNonZeroNorm(base.getNorm());
+        final double baseMag = Vectors.ensureFiniteNonZeroNorm(base.getNorm());
 
         final double scale = aDotB / (baseMag * baseMag);
 
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 1d7be1c..36338d0 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
@@ -334,7 +334,7 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point
      * @throws IllegalNormException if the norm is zero, NaN, or infinite
      */
     private double getFiniteNonZeroNorm() {
-        return Vectors.checkFiniteNonZeroNorm(getNorm());
+        return Vectors.ensureFiniteNonZeroNorm(getNorm());
     }
 
     /** Returns a component of the current instance relative to the given base
@@ -351,7 +351,7 @@ public final class Vector2D extends Cartesian2D implements EuclideanVector<Point
     private Vector2D getComponent(Vector2D base, boolean reject) {
         final double aDotB = dotProduct(base);
 
-        final double baseMag = Vectors.checkFiniteNonZeroNorm(base.getNorm());
+        final double baseMag = Vectors.ensureFiniteNonZeroNorm(base.getNorm());
 
         final double scale = aDotB / (baseMag * baseMag);
 
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/internal/VectorsTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/internal/VectorsTest.java
index 2d38904..2d38b03 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/internal/VectorsTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/internal/VectorsTest.java
@@ -27,23 +27,37 @@ public class VectorsTest {
     private static final double EPS = Math.ulp(1d);
 
     @Test
-    public void testCheckFiniteNonZeroNorm() {
+    public void testIsFiniteNonZero() {
         // 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.assertTrue(Vectors.isFiniteNonZero(1e-20));
+        Assert.assertTrue(Vectors.isFiniteNonZero(1e20));
+        Assert.assertTrue(Vectors.isFiniteNonZero(-1e-20));
+        Assert.assertTrue(Vectors.isFiniteNonZero(-1e20));
+
+        Assert.assertFalse(Vectors.isFiniteNonZero(0.0));
+        Assert.assertFalse(Vectors.isFiniteNonZero(Double.NaN));
+        Assert.assertFalse(Vectors.isFiniteNonZero(Double.POSITIVE_INFINITY));
+        Assert.assertFalse(Vectors.isFiniteNonZero(Double.NEGATIVE_INFINITY));
+    }
+
+    @Test
+    public void testEnsureFiniteNonZeroNorm() {
+        // act/assert
+        Assert.assertEquals(1.0, Vectors.ensureFiniteNonZeroNorm(1.0), EPS);
+        Assert.assertEquals(23.12, Vectors.ensureFiniteNonZeroNorm(23.12), EPS);
+        Assert.assertEquals(2e-12, Vectors.ensureFiniteNonZeroNorm(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);
+        Assert.assertEquals(-1.0, Vectors.ensureFiniteNonZeroNorm(-1.0), EPS);
+        Assert.assertEquals(-23.12, Vectors.ensureFiniteNonZeroNorm(-23.12), EPS);
+        Assert.assertEquals(-2e-12, Vectors.ensureFiniteNonZeroNorm(-2e-12), EPS);
 
-        GeometryTestUtils.assertThrows(() -> Vectors.checkFiniteNonZeroNorm(0.0),
+        GeometryTestUtils.assertThrows(() -> Vectors.ensureFiniteNonZeroNorm(0.0),
                 IllegalNormException.class, "Illegal norm: 0.0");
-        GeometryTestUtils.assertThrows(() -> Vectors.checkFiniteNonZeroNorm(Double.NaN),
+        GeometryTestUtils.assertThrows(() -> Vectors.ensureFiniteNonZeroNorm(Double.NaN),
                 IllegalNormException.class, "Illegal norm: NaN");
-        GeometryTestUtils.assertThrows(() -> Vectors.checkFiniteNonZeroNorm(Double.POSITIVE_INFINITY),
+        GeometryTestUtils.assertThrows(() -> Vectors.ensureFiniteNonZeroNorm(Double.POSITIVE_INFINITY),
                 IllegalNormException.class, "Illegal norm: Infinity");
-        GeometryTestUtils.assertThrows(() -> Vectors.checkFiniteNonZeroNorm(Double.NEGATIVE_INFINITY),
+        GeometryTestUtils.assertThrows(() -> Vectors.ensureFiniteNonZeroNorm(Double.NEGATIVE_INFINITY),
                 IllegalNormException.class, "Illegal norm: -Infinity");
     }
 
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 9e5bad0..136a4cb 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
@@ -18,6 +18,8 @@
 package org.apache.commons.geometry.euclidean.threed;
 
 import org.apache.commons.geometry.core.exception.IllegalNormException;
+import org.apache.commons.geometry.euclidean.threed.Rotation.CardanSingularityException;
+import org.apache.commons.geometry.euclidean.threed.Rotation.EulerSingularityException;
 import org.apache.commons.numbers.angle.PlaneAngleRadians;
 import org.junit.Assert;
 import org.junit.Test;
@@ -63,7 +65,7 @@ public class RotationTest {
     try {
       new Rotation(Vector3D.of(0, 0, 0), 2 * Math.PI / 3);
       Assert.fail("an exception should have been thrown");
-    } catch (IllegalArgumentException e) {
+    } catch (IllegalNormException e) {
     }
 
     r = new Rotation(Vector3D.PLUS_Z, 1.5 * Math.PI);
@@ -93,7 +95,7 @@ public class RotationTest {
     try {
       new Rotation(Vector3D.of(0, 0, 0), 2 * Math.PI / 3, RotationConvention.VECTOR_OPERATOR);
       Assert.fail("an exception should have been thrown");
-    } catch (IllegalArgumentException e) {
+    } catch (IllegalNormException e) {
     }
 
     r = new Rotation(Vector3D.PLUS_Z, 1.5 * Math.PI, RotationConvention.VECTOR_OPERATOR);
@@ -126,7 +128,7 @@ public class RotationTest {
     try {
       new Rotation(Vector3D.of(0, 0, 0), 2 * Math.PI / 3, RotationConvention.FRAME_TRANSFORM);
       Assert.fail("an exception should have been thrown");
-    } catch (IllegalArgumentException e) {
+    } catch (IllegalNormException e) {
     }
 
     r = new Rotation(Vector3D.PLUS_Z, 1.5 * Math.PI, RotationConvention.FRAME_TRANSFORM);
@@ -196,7 +198,7 @@ public class RotationTest {
     try {
         new Rotation(u, Vector3D.ZERO);
         Assert.fail("an exception should have been thrown");
-    } catch (IllegalArgumentException e) {
+    } catch (IllegalNormException e) {
         // expected behavior
     }
 
@@ -494,7 +496,7 @@ public class RotationTest {
                   try {
                       r.getAngles(CardanOrders[i], convention);
                       Assert.fail("an exception should have been caught");
-                  } catch (IllegalStateException cese) {
+                  } catch (CardanSingularityException cese) {
                       // expected behavior
                   }
               }
@@ -512,7 +514,7 @@ public class RotationTest {
                   try {
                       r.getAngles(EulerOrders[i], convention);
                       Assert.fail("an exception should have been caught");
-                  } catch (IllegalStateException cese) {
+                  } catch (EulerSingularityException cese) {
                       // expected behavior
                   }
               }
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/ArcsSet.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/ArcsSet.java
index 311950f..8ca86ce 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/ArcsSet.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/ArcsSet.java
@@ -23,6 +23,7 @@ import java.util.List;
 import java.util.NoSuchElementException;
 
 import org.apache.commons.geometry.core.Geometry;
+import org.apache.commons.geometry.core.internal.GeometryInternalError;
 import org.apache.commons.geometry.core.partitioning.AbstractRegion;
 import org.apache.commons.geometry.core.partitioning.BSPTree;
 import org.apache.commons.geometry.core.partitioning.BoundaryProjection;
@@ -42,9 +43,6 @@ import org.apache.commons.numbers.core.Precision;
  */
 public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterable<double[]> {
 
-    /** Message used for internal errors. */
-    private static final String INTERNAL_ERROR_MESSAGE = "Please file a bug report";
-
     /** Build an arcs set representing the whole circle.
      * @param tolerance tolerance below which close sub-arcs are merged together
      */
@@ -79,11 +77,11 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
      * {@code Boolean.TRUE} and {@code Boolean.FALSE}</p>
      * @param tree inside/outside BSP tree representing the arcs set
      * @param tolerance tolerance below which close sub-arcs are merged together
-     * @exception InconsistentStateAt2PiWrapping if the tree leaf nodes are not
+     * @exception IllegalArgumentException if the tree leaf nodes are not
      * consistent across the \( 0, 2 \pi \) crossing
      */
     public ArcsSet(final BSPTree<S1Point> tree, final double tolerance)
-        throws InconsistentStateAt2PiWrapping {
+        throws IllegalArgumentException {
         super(tree, tolerance);
         check2PiConsistency();
     }
@@ -107,11 +105,11 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
      * space.</p>
      * @param boundary collection of boundary elements
      * @param tolerance tolerance below which close sub-arcs are merged together
-     * @exception InconsistentStateAt2PiWrapping if the tree leaf nodes are not
+     * @exception IllegalArgumentException if the tree leaf nodes are not
      * consistent across the \( 0, 2 \pi \) crossing
      */
     public ArcsSet(final Collection<SubHyperplane<S1Point>> boundary, final double tolerance)
-        throws InconsistentStateAt2PiWrapping {
+        throws IllegalArgumentException {
         super(boundary, tolerance);
         check2PiConsistency();
     }
@@ -167,10 +165,10 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
     }
 
     /** Check consistency.
-    * @exception InconsistentStateAt2PiWrapping if the tree leaf nodes are not
+    * @exception IllegalArgumentException if the tree leaf nodes are not
     * consistent across the \( 0, 2 \pi \) crossing
     */
-    private void check2PiConsistency() throws InconsistentStateAt2PiWrapping {
+    private void check2PiConsistency() throws IllegalArgumentException {
 
         // start search at the tree root
         BSPTree<S1Point> root = getTree(false);
@@ -185,7 +183,7 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
         final Boolean stateAfter = (Boolean) getLastLeaf(root).getAttribute();
 
         if (stateBefore ^ stateAfter) {
-            throw new InconsistentStateAt2PiWrapping();
+            throw new IllegalArgumentException("Inconsistent state at 2\\u03c0 wrapping");
         }
 
     }
@@ -655,7 +653,7 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
                 }
                 if (end == null) {
                     // this should never happen
-                    throw new IllegalStateException(INTERNAL_ERROR_MESSAGE);
+                    throw new GeometryInternalError();
                 }
 
                 // we have identified the last arc
@@ -794,7 +792,7 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
         final BSPTree<S1Point> node = tree.getCell(limit.getLocation(), getTolerance());
         if (node.getCut() != null) {
             // this should never happen
-            throw new IllegalStateException(INTERNAL_ERROR_MESSAGE);
+            throw new GeometryInternalError();
         }
 
         node.insertCut(limit);
@@ -926,27 +924,5 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
                 return Side.HYPER;
             }
         }
-
-    }
-
-    /** Specialized exception for inconsistent BSP tree state inconsistency.
-     * <p>
-     * This exception is thrown at {@link ArcsSet} construction time when the
-     * {@link org.apache.commons.geometry.core.partitioning.Region.Location inside/outside}
-     * state is not consistent at the 0, \(2 \pi \) crossing.
-     * </p>
-     */
-    public static class InconsistentStateAt2PiWrapping extends IllegalArgumentException {
-
-        /** Serializable UID. */
-        private static final long serialVersionUID = 20140107L;
-
-        /** Simple constructor.
-         */
-        public InconsistentStateAt2PiWrapping() {
-            super("Inconsistent state at 2\\u03c0 wrapping");
-        }
-
     }
-
 }
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/PropertiesComputer.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/PropertiesComputer.java
index 3f6da88..536a2dd 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/PropertiesComputer.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/PropertiesComputer.java
@@ -20,6 +20,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.commons.geometry.core.Geometry;
+import org.apache.commons.geometry.core.internal.GeometryInternalError;
 import org.apache.commons.geometry.core.partitioning.BSPTree;
 import org.apache.commons.geometry.core.partitioning.BSPTreeVisitor;
 import org.apache.commons.geometry.euclidean.threed.Point3D;
@@ -79,7 +80,7 @@ class PropertiesComputer implements BSPTreeVisitor<S2Point> {
             final List<Vertex> boundary = convex.getBoundaryLoops();
             if (boundary.size() != 1) {
                 // this should never happen
-                throw new IllegalStateException("Please file a bug report");
+                throw new GeometryInternalError();
             }
 
             // compute the geometrical properties of the convex cell
diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/ArcsSetTest.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/ArcsSetTest.java
index a6bab1a..8d8c600 100644
--- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/ArcsSetTest.java
+++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/ArcsSetTest.java
@@ -358,7 +358,7 @@ public class ArcsSetTest {
 
     }
 
-    @Test(expected=ArcsSet.InconsistentStateAt2PiWrapping.class)
+    @Test(expected=IllegalArgumentException.class)
     public void testInconsistentState() {
         SubLimitAngle l1 = new LimitAngle(S1Point.of(1.0), false, 1.0e-10).wholeHyperplane();
         SubLimitAngle l2 = new LimitAngle(S1Point.of(2.0), true,  1.0e-10).wholeHyperplane();


[commons-geometry] 01/05: GEOMETRY-8: adding initial exception hierarchy; using IllegalNormException in Vector classes

Posted by er...@apache.org.
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


[commons-geometry] 04/05: Unchecked exceptions removed from "throws" clause.

Posted by er...@apache.org.
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 1be42c870e9a776a5c7887b83e9add276770f154
Author: Gilles Sadowski <gi...@harfang.homelinux.org>
AuthorDate: Fri Sep 14 16:23:15 2018 +0200

    Unchecked exceptions removed from "throws" clause.
---
 .../main/java/org/apache/commons/geometry/core/Vector.java |  8 ++++----
 .../apache/commons/geometry/spherical/oned/ArcsSet.java    | 14 +++++---------
 2 files changed, 9 insertions(+), 13 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 b04d644..4804a80 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
@@ -124,7 +124,7 @@ public interface Vector<V extends Vector<V>> extends Spatial {
      * @return a new normalized vector
      * @exception IllegalNormException if the norm is zero, NaN, or infinite
      */
-    V normalize() throws IllegalNormException;
+    V normalize();
 
     /** Multiply the instance by a scalar.
      * @param a scalar
@@ -185,7 +185,7 @@ public interface Vector<V extends Vector<V>> extends Spatial {
      * @exception IllegalNormException if the norm of the base vector is zero, NaN, or infinite
      * @see #reject(Vector)
      */
-    V project(V base) throws IllegalNormException;
+    V project(V base);
 
     /** 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
@@ -200,12 +200,12 @@ public interface Vector<V extends Vector<V>> extends Spatial {
      * @exception IllegalNormException if the norm of the base vector is zero, NaN, or infinite
      * @see #project(Vector)
      */
-    V reject(V base) throws IllegalNormException;
+    V reject(V base);
 
     /** Compute the angular separation between two vectors in radians.
      * @param v other vector
      * @return angular separation between this instance and v in radians
      * @exception IllegalNormException if either vector has a zero, NaN, or infinite norm
      */
-    double angle(V v) throws IllegalNormException;
+    double angle(V v);
 }
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/ArcsSet.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/ArcsSet.java
index 8ca86ce..3334aea 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/ArcsSet.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/ArcsSet.java
@@ -63,8 +63,7 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
      * @param tolerance tolerance below which close sub-arcs are merged together
      * @exception IllegalArgumentException if lower is greater than upper
      */
-    public ArcsSet(final double lower, final double upper, final double tolerance)
-        throws IllegalArgumentException {
+    public ArcsSet(final double lower, final double upper, final double tolerance) {
         super(buildTree(lower, upper, tolerance), tolerance);
     }
 
@@ -80,8 +79,7 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
      * @exception IllegalArgumentException if the tree leaf nodes are not
      * consistent across the \( 0, 2 \pi \) crossing
      */
-    public ArcsSet(final BSPTree<S1Point> tree, final double tolerance)
-        throws IllegalArgumentException {
+    public ArcsSet(final BSPTree<S1Point> tree, final double tolerance) {
         super(tree, tolerance);
         check2PiConsistency();
     }
@@ -108,8 +106,7 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
      * @exception IllegalArgumentException if the tree leaf nodes are not
      * consistent across the \( 0, 2 \pi \) crossing
      */
-    public ArcsSet(final Collection<SubHyperplane<S1Point>> boundary, final double tolerance)
-        throws IllegalArgumentException {
+    public ArcsSet(final Collection<SubHyperplane<S1Point>> boundary, final double tolerance) {
         super(boundary, tolerance);
         check2PiConsistency();
     }
@@ -122,8 +119,7 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
      * @exception IllegalArgumentException if lower is greater than upper
      */
     private static BSPTree<S1Point> buildTree(final double lower, final double upper,
-                                               final double tolerance)
-        throws IllegalArgumentException {
+                                               final double tolerance) {
 
         if (Precision.equals(lower, upper, 0) || (upper - lower) >= Geometry.TWO_PI) {
             // the tree must cover the whole circle
@@ -168,7 +164,7 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
     * @exception IllegalArgumentException if the tree leaf nodes are not
     * consistent across the \( 0, 2 \pi \) crossing
     */
-    private void check2PiConsistency() throws IllegalArgumentException {
+    private void check2PiConsistency() {
 
         // start search at the tree root
         BSPTree<S1Point> root = getTree(false);


[commons-geometry] 05/05: Merge branch 'GEOMETRY-8__matt'

Posted by er...@apache.org.
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 2e6fc6a1baaa5f71bd2385e2c6e20f0334b9f2bc
Merge: adbdc69 1be42c8
Author: Gilles Sadowski <gi...@harfang.homelinux.org>
AuthorDate: Fri Sep 14 16:24:27 2018 +0200

    Merge branch 'GEOMETRY-8__matt'
    
    Closes #9

 .../org/apache/commons/geometry/core/Vector.java   |  18 +-
 .../geometry/core/exception/GeometryException.java |  34 ++++
 .../core/exception/IllegalNormException.java       |  40 ++++
 .../geometry/core/exception/package-info.java      |  23 +++
 .../core/internal/GeometryInternalError.java       |  38 ++++
 .../commons/geometry/core/GeometryTestUtils.java   |  32 ++++
 .../commons/geometry/enclosing/WelzlEncloser.java  |   3 +-
 .../geometry/euclidean}/internal/Vectors.java      |  31 ++-
 .../commons/geometry/euclidean/oned/Vector1D.java  |  41 ++--
 .../commons/geometry/euclidean/threed/Plane.java   |   7 +-
 .../commons/geometry/euclidean/threed/Point3D.java |   2 +-
 .../geometry/euclidean/threed/Rotation.java        | 209 ++++++++++++---------
 .../geometry/euclidean/threed/Vector3D.java        |  40 ++--
 .../commons/geometry/euclidean/twod/Point2D.java   |   2 +-
 .../commons/geometry/euclidean/twod/Vector2D.java  |  35 ++--
 .../geometry/euclidean}/internal/VectorsTest.java  |  40 +++-
 .../geometry/euclidean/oned/Vector1DTest.java      |  89 ++++++---
 .../geometry/euclidean/threed/RotationTest.java    |  17 +-
 .../geometry/euclidean/threed/Vector3DTest.java    |  98 ++++++++--
 .../geometry/euclidean/twod/Vector2DTest.java      |  87 +++++++--
 .../commons/geometry/spherical/oned/ArcsSet.java   |  52 ++---
 .../spherical/twod/PropertiesComputer.java         |   3 +-
 .../geometry/spherical/oned/ArcsSetTest.java       |   2 +-
 23 files changed, 662 insertions(+), 281 deletions(-)