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/07/21 10:07:42 UTC

[commons-geometry] 04/15: GEOMETRY-7: adding basic SphericalCoordinates class

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 a1e38d23c9c7ae015cb81db48114e6bc48afc431
Author: Matt Juntunen <ma...@hotmail.com>
AuthorDate: Sat Jun 30 22:29:31 2018 -0400

    GEOMETRY-7: adding basic SphericalCoordinates class
---
 .../euclidean/threed/SphericalCoordinates.java     | 280 ++++++++++++++++
 .../euclidean/threed/SphericalCoordinates_OLD.java |  18 +-
 .../geometry/euclidean/threed/Vector3D.java        |  14 -
 .../geometry/euclidean/twod/PolarCoordinates.java  |  52 +--
 .../euclidean/threed/SphericalCoordinatesTest.java | 368 +++++++++++++++++++++
 .../threed/SphericalCoordinatesTest_OLD.java       |  33 +-
 .../geometry/euclidean/threed/Vector3DTest.java    |  14 -
 .../commons/geometry/spherical/package-info.java   |  23 --
 8 files changed, 700 insertions(+), 102 deletions(-)

diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SphericalCoordinates.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SphericalCoordinates.java
new file mode 100644
index 0000000..609e90b
--- /dev/null
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SphericalCoordinates.java
@@ -0,0 +1,280 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.geometry.euclidean.threed;
+
+import java.io.Serializable;
+
+import org.apache.commons.geometry.core.Geometry;
+import org.apache.commons.geometry.core.Spatial;
+import org.apache.commons.geometry.core.util.Coordinates;
+import org.apache.commons.geometry.core.util.SimpleCoordinateFormat;
+import org.apache.commons.numbers.angle.PlaneAngleRadians;
+
+/** Class representing a set of spherical coordinates in 3 dimensional Euclidean space.
+ */
+public class SphericalCoordinates implements Spatial, Serializable {
+
+    /** Serializable version identifier. */
+    private static final long serialVersionUID = 20180623L;
+
+    /** Factory object for delegating instance creation. */
+    private static final Coordinates.Factory3D<SphericalCoordinates> FACTORY = new Coordinates.Factory3D<SphericalCoordinates>() {
+
+        /** {@inheritDoc} */
+        @Override
+        public SphericalCoordinates create(double a1, double a2, double a3) {
+            return new SphericalCoordinates(a1, a2, a3);
+        }
+
+    };
+
+    /** Radius value. */
+    private final double radius;
+
+    /** Azimuth angle in radians. */
+    private final double azimuth;
+
+    /** Polar angle in radians. */
+    private final double polar;
+
+    /** Simple constructor. The given inputs are normalized.
+     * @param radius Radius value.
+     * @param azimuth Azimuth angle in radians.
+     * @param polar Polar angle in radians.
+     */
+    private SphericalCoordinates(double radius, double azimuth, double polar) {
+        if (radius < 0) {
+            // negative radius; flip the angles
+            radius = Math.abs(radius);
+            azimuth += Geometry.PI;
+            polar += Geometry.PI;
+        }
+
+        if (Double.isFinite(azimuth) && (azimuth <= Geometry.MINUS_PI || azimuth > Geometry.PI)) {
+            azimuth = PlaneAngleRadians.normalizeBetweenMinusPiAndPi(azimuth);
+
+            // azimuth is now in the range [-pi, pi] but we want it to be in the range
+            // (-pi, pi] in order to have completely unique coordinates
+            if (azimuth <= -Geometry.PI) {
+                azimuth += Geometry.TWO_PI;
+            }
+        }
+
+        // normalize the polar angle; this is the angle between the polar vector and the point ray
+        // so it is unsigned (unlike the azimuth) and should be in the range [0, pi]
+        if (Double.isFinite(polar)) {
+            polar = Math.abs(PlaneAngleRadians.normalizeBetweenMinusPiAndPi(polar));
+        }
+
+        this.radius = radius;
+        this.azimuth = azimuth;
+        this.polar = polar;
+    }
+
+    /** Return the radius value. The value is in the range {@code [0, +infinity)}.
+     * @return the radius value
+     */
+    public double getRadius() {
+        return radius;
+    }
+
+    /** Return the azimuth angle in radians. This is the angle in the x-y plane measured counter-clockwise from
+     * the positive x axis. The angle is in the range {@code (-pi, pi]}.
+     * @return the azimuth angle in radians
+     */
+    public double getAzimuth() {
+        return azimuth;
+    }
+
+    /** Return the polar angle in radians. This is the angle the coordinate ray makes with the positive z axis.
+     * The angle is in the range {@code [0, pi]}.
+     * @return the polar angle in radians
+     */
+    public double getPolar() {
+        return polar;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int getDimension() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isNaN() {
+        return Double.isNaN(radius) || Double.isNaN(azimuth) || Double.isNaN(polar);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isInfinite() {
+        return !isNaN() && (Double.isInfinite(radius) || Double.isInfinite(azimuth) || Double.isInfinite(polar));
+    }
+
+    /** Convert this set of spherical coordinates to Cartesian coordinates.
+     * The Cartesian coordinates are computed and passed to the given
+     * factory instance. The factory's return value is returned.
+     * @param factory Factory instance that will be passed the computed Cartesian coordinates
+     * @return the value returned by the factory when passed Cartesian
+     *      coordinates equivalent to this set of spherical coordinates.
+     */
+    public <T> T toCartesian(final Coordinates.Factory3D<T> factory) {
+        return toCartesian(radius, azimuth, polar, factory);
+    }
+
+    /** Convert this set of spherical coordinates to a 3 dimensional vector.
+     * @return A 3-dimensional vector with an equivalent set of
+     *      coordinates.
+     */
+    public Vector3D toVector() {
+        return toCartesian(Vector3D.getFactory());
+    }
+
+    /** Convert this set of spherical coordinates to a 3 dimensional point.
+    * @return A 3-dimensional point with an equivalent set of
+    *      coordinates.
+    */
+    public Point3D toPoint() {
+        return toCartesian(Point3D.getFactory());
+    }
+
+    /**
+     * Get a hashCode for this set of spherical coordinates.
+     * <p>All NaN values have the same hash code.</p>
+     *
+     * @return a hash code value for this object
+     */
+    @Override
+    public int hashCode() {
+        if (isNaN()) {
+            return 127;
+        }
+        return 449 * (79 * Double.hashCode(radius) + Double.hashCode(azimuth) + Double.hashCode(polar));
+    }
+
+    /** Test for the equality of two sets of spherical coordinates.
+     * <p>
+     * If all values of two sets of coordinates are exactly the same, and none are
+     * <code>Double.NaN</code>, the two sets are considered to be equal.
+     * </p>
+     * <p>
+     * <code>NaN</code> values are considered to globally affect the coordinates
+     * and be equal to each other - i.e, if either (or all) values of the
+     * coordinate set are equal to <code>Double.NaN</code>, the set is equal to
+     * {@link #NaN}.
+     * </p>
+     *
+     * @param other Object to test for equality to this
+     * @return true if two SphericalCoordinates objects are equal, false if
+     *         object is null, not an instance of SphericalCoordinates, or
+     *         not equal to this SphericalCoordinates instance
+     *
+     */
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+
+        if (other instanceof SphericalCoordinates) {
+            final SphericalCoordinates rhs = (SphericalCoordinates) other;
+            if (rhs.isNaN()) {
+                return this.isNaN();
+            }
+
+            return (radius == rhs.radius) && (azimuth == rhs.azimuth) && (polar == rhs.polar);
+        }
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return SimpleCoordinateFormat.getPointFormat().format(radius, azimuth, polar);
+    }
+
+    /** Create a {@link SphericalCoordinates} instance from the given values. The values are normalized
+     * so that {@code radius} lies in the range {@code [0, +infinity)}, {@code azimuth} lies in the range
+     * {@code (-pi, +pi]}, and {@code polar} lies in the range {@code [0, +pi]}.
+     * @param radius the length of the line segment from the origin to the coordinate point.
+     * @param azimuth the angle in the x-y plane, measured in radians counter-clockwise
+     *      from the positive x-axis.
+     * @param polar the angle in radians between the positive z-axis and the ray from the origin
+     *      to the coordinate point.
+     * @return a new {@link SphericalCoordinates} instance representing the same point as the given set of
+     *      spherical coordinates.
+     */
+    public static SphericalCoordinates of(final double radius, final double azimuth, final double polar) {
+        return new SphericalCoordinates(radius, azimuth, polar);
+    }
+
+    /** Convert the given set of Cartesian coordinates to spherical coordinates.
+     * @param x X coordinate value
+     * @param y Y coordinate value
+     * @param z Z coordinate value
+     * @return a set of spherical coordinates equivalent to the given Cartesian coordinates
+     */
+    public static SphericalCoordinates ofCartesian(final double x, final double y, final double z) {
+        final double radius = Math.sqrt((x*x) + (y*y) + (z*z));
+        final double azimuth = Math.atan2(y, x);
+
+        // default the polar angle to 0 when the radius is 0
+        final double polar = (radius > 0.0) ? Math.acos(z / radius) : 0.0;
+
+        return new SphericalCoordinates(radius, azimuth, polar);
+    }
+
+    /** Parse the given string and return a new {@link SphericalCoordinates} instance. The parsed
+     * coordinate values are normalized as in the {@link #of(double, double, double)} method.
+     * The expected string format is the same as that returned by {@link #toString()}.
+     * @param input the string to parse
+     * @return new {@link SphericalCoordinates} instance
+     * @throws IllegalArgumentException if the string format is invalid.
+     */
+    public static SphericalCoordinates parse(String input) {
+        return SimpleCoordinateFormat.getPointFormat().parse(input, FACTORY);
+    }
+
+    /** Convert the given set of spherical coordinates to Cartesian coordinates.
+     * The Cartesian coordinates are computed and passed to the given
+     * factory instance. The factory's return value is returned.
+     * @param radius The spherical radius value.
+     * @param azimuth The spherical azimuth angle in radians.
+     * @param polar The spherical polar angle in radians.
+     * @param factory Factory instance that will be passed the
+     * @return the value returned by the factory when passed Cartesian
+     *      coordinates equivalent to the given set of spherical coordinates.
+     */
+    public static <T> T toCartesian(final double radius, final double azimuth, final double polar,
+            Coordinates.Factory3D<T> factory) {
+        final double xyLength = radius * Math.sin(polar);
+
+        final double x = xyLength * Math.cos(azimuth);
+        final double y = xyLength * Math.sin(azimuth);
+        final double z = radius * Math.cos(polar);
+
+        return factory.create(x, y, z);
+    }
+
+    /** Return a factory object for generating new {@link SphericalCoordinates} instances.
+     * @return factory object for generating new instances.
+     */
+    public static Coordinates.Factory3D<SphericalCoordinates> getFactory() {
+        return FACTORY;
+    }
+}
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/SphericalCoordinates.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SphericalCoordinates_OLD.java
similarity index 96%
rename from commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/SphericalCoordinates.java
rename to commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SphericalCoordinates_OLD.java
index d9d959f..ac39a5e 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/SphericalCoordinates.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SphericalCoordinates_OLD.java
@@ -14,13 +14,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.commons.geometry.spherical;
+package org.apache.commons.geometry.euclidean.threed;
 
 
 import java.io.Serializable;
 
-import org.apache.commons.geometry.euclidean.threed.Vector3D;
-
 /** This class provides conversions related to <a
  * href="http://mathworld.wolfram.com/SphericalCoordinates.html">spherical coordinates</a>.
  * <p>
@@ -48,7 +46,7 @@ import org.apache.commons.geometry.euclidean.threed.Vector3D;
  * between spherical and Cartesian coordinates.
  * </p>
  */
-public class SphericalCoordinates implements Serializable {
+public class SphericalCoordinates_OLD implements Serializable {
 
     /** Serializable UID. */
     private static final long serialVersionUID = 20130206L;
@@ -80,14 +78,14 @@ public class SphericalCoordinates implements Serializable {
     /** Build a spherical coordinates transformer from Cartesian coordinates.
      * @param v Cartesian coordinates
      */
-    public SphericalCoordinates(final Vector3D v) {
+    public SphericalCoordinates_OLD(final Vector3D v) {
 
         // Cartesian coordinates
         this.v = v;
 
         // remaining spherical coordinates
         this.r     = v.getNorm();
-        this.theta = v.getAlpha();
+        this.theta = 0.0; //v.getAlpha();
         this.phi   = Math.acos(v.getZ() / r);
 
     }
@@ -97,7 +95,7 @@ public class SphericalCoordinates implements Serializable {
      * @param theta azimuthal angle in x-y plane
      * @param phi polar (co-latitude) angle
      */
-    public SphericalCoordinates(final double r, final double theta, final double phi) {
+    public SphericalCoordinates_OLD(final double r, final double theta, final double phi) {
 
         final double cosTheta = Math.cos(theta);
         final double sinTheta = Math.sin(theta);
@@ -382,11 +380,11 @@ public class SphericalCoordinates implements Serializable {
             this.z = z;
         }
 
-        /** Replace the deserialized data transfer object with a {@link SphericalCoordinates}.
-         * @return replacement {@link SphericalCoordinates}
+        /** Replace the deserialized data transfer object with a {@link SphericalCoordinates_OLD}.
+         * @return replacement {@link SphericalCoordinates_OLD}
          */
         private Object readResolve() {
-            return new SphericalCoordinates(Vector3D.of(x, y, z));
+            return new SphericalCoordinates_OLD(Vector3D.of(x, y, z));
         }
 
     }
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 2083fba..7d8c5e8 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
@@ -130,20 +130,6 @@ public final class Vector3D extends Cartesian3D implements EuclideanVector<Point
         return Math.max(Math.max(Math.abs(getX()), Math.abs(getY())), Math.abs(getZ()));
     }
 
-    /** Get the azimuth of the vector.
-     * @return azimuth (&alpha;) of the vector, between -&pi; and +&pi;
-     */
-    public double getAlpha() {
-        return Math.atan2(getY(), getX());
-    }
-
-    /** Get the elevation of the vector.
-     * @return elevation (&delta;) of the vector, between -&pi;/2 and +&pi;/2
-     */
-    public double getDelta() {
-        return Math.asin(getZ() / getNorm());
-    }
-
     /** {@inheritDoc} */
     @Override
     public Vector3D add(Vector3D v) {
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/PolarCoordinates.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/PolarCoordinates.java
index de3731c..681f646 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/PolarCoordinates.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/PolarCoordinates.java
@@ -26,13 +26,14 @@ import org.apache.commons.geometry.core.util.Coordinates;
 import org.apache.commons.numbers.angle.PlaneAngleRadians;
 
 /** Class representing a set of polar coordinates in 2 dimensional
- * Euclidean space. Coordinates are normalized so that {@code radius >= 0}
- * and {@code -pi < azimuth <= pi}.
+ * Euclidean space. Coordinates are normalized so that {@code radius}
+ * is in the range {@code [0, +infinity)} and {@code azimuth} is in the
+ * range {@code (-pi, pi]}.
  */
 public class PolarCoordinates implements Spatial, Serializable {
 
     /** Serializable version UID */
-    private static final long serialVersionUID = -3122872387910228544L;
+    private static final long serialVersionUID = 20180630L;
 
     /** Shared parser/formatter instance **/
     private static final PolarCoordinatesParser PARSER = new PolarCoordinatesParser();
@@ -43,11 +44,27 @@ public class PolarCoordinates implements Spatial, Serializable {
     /** Azimuth angle in radians. */
     private final double azimuth;
 
-    /** Simple constructor. Input values must already be normalized.
+    /** Simple constructor. Input values are normalized.
      * @param radius Radius value.
      * @param azimuth Azimuth angle in radians.
      */
-    private PolarCoordinates(final double radius, final double azimuth) {
+    private PolarCoordinates(double radius, double azimuth) {
+        if (radius < 0) {
+            // negative radius; flip the angles
+            radius = Math.abs(radius);
+            azimuth += Geometry.PI;
+        }
+
+        if (Double.isFinite(azimuth) && (azimuth <= Geometry.MINUS_PI || azimuth > Geometry.PI)) {
+            azimuth = PlaneAngleRadians.normalizeBetweenMinusPiAndPi(azimuth);
+
+            // azimuth is now in the range [-pi, pi] but we want it to be in the range
+            // (-pi, pi] in order to have completely unique coordinates
+            if (azimuth <= -Geometry.PI) {
+                azimuth += Geometry.TWO_PI;
+            }
+        }
+
         this.radius = radius;
         this.azimuth = azimuth;
     }
@@ -177,21 +194,6 @@ public class PolarCoordinates implements Spatial, Serializable {
      * @return
      */
     public static PolarCoordinates of(double radius, double azimuth) {
-        if (radius < 0) {
-            radius = Math.abs(radius);
-            azimuth += Geometry.PI;
-        }
-
-        if (Double.isFinite(azimuth)) {
-            azimuth = PlaneAngleRadians.normalizeBetweenMinusPiAndPi(azimuth);
-
-            // the above normalizes the azimuth to -pi <= azimuth <= pi
-            // but we want -pi < azimuth <= pi to have completely unique coordinates
-            if (azimuth <= -Geometry.PI) {
-                azimuth += Geometry.TWO_PI;
-            }
-        }
-
         return new PolarCoordinates(radius, azimuth);
     }
 
@@ -212,7 +214,8 @@ public class PolarCoordinates implements Spatial, Serializable {
      * and azimuth is within the range {@code (-pi, pi]}. The expected string
      * format is the same as that returned by {@link #toString()}.
      * @param input the string to parse
-     * @return
+     * @return new {@link PolarCoordinates} instance
+     * @throws IllegalArgumentException if the string format is invalid.
      */
     public static PolarCoordinates parse(String input) {
         return PARSER.parse(input);
@@ -225,8 +228,8 @@ public class PolarCoordinates implements Spatial, Serializable {
      * @param azimuth Azimuth value in radians
      * @param factory Factory instance that will be passed the computed Cartesian coordinates
      * @param <T> Type returned by the factory
-     * @return the value returned by the given factory when passed Cartesian
-     *      coordinates equivalent to given set of polar coordinates.
+     * @return the value returned by the factory when passed Cartesian
+     *      coordinates equivalent to the given set of polar coordinates.
      */
     public static <T> T toCartesian(final double radius, final double azimuth, final Coordinates.Factory2D<T> factory) {
         final double x = radius * Math.cos(azimuth);
@@ -293,8 +296,7 @@ public class PolarCoordinates implements Spatial, Serializable {
             readSuffix(str, pos);
             endParse(str, pos);
 
-            // use the factory method so that the values will be normalized
-            return PolarCoordinates.of(radius, azimuth);
+            return new PolarCoordinates(radius, azimuth);
         }
     }
 }
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SphericalCoordinatesTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SphericalCoordinatesTest.java
new file mode 100644
index 0000000..8b1f51a
--- /dev/null
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SphericalCoordinatesTest.java
@@ -0,0 +1,368 @@
+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.util.Coordinates;
+import org.apache.commons.geometry.euclidean.twod.PolarCoordinates;
+import org.junit.Assert;
+import org.junit.Test;
+
+
+public class SphericalCoordinatesTest {
+
+    private static final double EPS = 1e-10;
+
+    private static final double QUARTER_PI = 0.25 * Geometry.PI;
+    private static final double MINUS_QUARTER_PI = -0.25 * Geometry.PI;
+    private static final double THREE_QUARTER_PI = 0.75 * Geometry.PI;
+    private static final double MINUS_THREE_QUARTER_PI = -0.75 * Geometry.PI;
+
+    @Test
+    public void testOf() {
+        // act/assert
+        checkSpherical(SphericalCoordinates.of(0, 0, 0), 0, 0, 0);
+        checkSpherical(SphericalCoordinates.of(0.1, 0.2, 0.3), 0.1, 0.2, 0.3);
+
+        checkSpherical(SphericalCoordinates.of(1, Geometry.HALF_PI, Geometry.PI),
+                1, Geometry.HALF_PI, Geometry.PI);
+        checkSpherical(SphericalCoordinates.of(1, Geometry.MINUS_HALF_PI, Geometry.HALF_PI),
+                1, Geometry.MINUS_HALF_PI, Geometry.HALF_PI);
+    }
+
+    @Test
+    public void testOf_normalizesAzimuthAngle() {
+        // act/assert
+        checkSpherical(SphericalCoordinates.of(2, Geometry.TWO_PI, 0), 2, 0, 0);
+        checkSpherical(SphericalCoordinates.of(2, Geometry.HALF_PI + Geometry.TWO_PI, 0), 2, Geometry.HALF_PI, 0);
+        checkSpherical(SphericalCoordinates.of(2, -Geometry.PI, 0), 2, Geometry.PI, 0);
+        checkSpherical(SphericalCoordinates.of(2, Geometry.PI * 1.5, 0), 2, Geometry.MINUS_HALF_PI, 0);
+    }
+
+    @Test
+    public void testOf_normalizesPolarAngle() {
+        // act/assert
+        checkSpherical(SphericalCoordinates.of(1, 0, 0), 1, 0, 0);
+
+        checkSpherical(SphericalCoordinates.of(1, 0, QUARTER_PI), 1, 0, QUARTER_PI);
+        checkSpherical(SphericalCoordinates.of(1, 0, MINUS_QUARTER_PI), 1, 0, QUARTER_PI);
+
+        checkSpherical(SphericalCoordinates.of(1, 0, Geometry.HALF_PI), 1, 0, Geometry.HALF_PI);
+        checkSpherical(SphericalCoordinates.of(1, 0, Geometry.MINUS_HALF_PI), 1, 0, Geometry.HALF_PI);
+
+        checkSpherical(SphericalCoordinates.of(1, 0, THREE_QUARTER_PI), 1, 0, THREE_QUARTER_PI);
+        checkSpherical(SphericalCoordinates.of(1, 0, MINUS_THREE_QUARTER_PI), 1, 0, THREE_QUARTER_PI);
+
+        checkSpherical(SphericalCoordinates.of(1, 0, Geometry.TWO_PI), 1, 0, 0);
+        checkSpherical(SphericalCoordinates.of(1, 0, Geometry.MINUS_TWO_PI), 1, 0, 0);
+    }
+
+    @Test
+    public void testOf_angleWrapAround() {
+        // act/assert
+        checkOfWithAngleWrapAround(1, 0, 0);
+        checkOfWithAngleWrapAround(1, QUARTER_PI, QUARTER_PI);
+        checkOfWithAngleWrapAround(1, Geometry.HALF_PI, Geometry.HALF_PI);
+        checkOfWithAngleWrapAround(1, THREE_QUARTER_PI, THREE_QUARTER_PI);
+        checkOfWithAngleWrapAround(1, Geometry.PI, Geometry.PI);
+    }
+
+    private void checkOfWithAngleWrapAround(double radius, double azimuth, double polar) {
+        for (int i=-4; i<=4; ++i) {
+            checkSpherical(
+                    SphericalCoordinates.of(radius, azimuth + (i * Geometry.TWO_PI), polar + (-i * Geometry.TWO_PI)),
+                    radius, azimuth, polar);
+        }
+    }
+
+    @Test
+    public void testOf_negativeRadius() {
+        // act/assert
+        checkSpherical(SphericalCoordinates.of(-2, 0, 0), 2, Geometry.PI, Geometry.PI);
+        checkSpherical(SphericalCoordinates.of(-2, Geometry.PI, Geometry.PI), 2, 0, 0);
+
+        checkSpherical(SphericalCoordinates.of(-3, Geometry.HALF_PI, QUARTER_PI), 3, Geometry.MINUS_HALF_PI, THREE_QUARTER_PI);
+        checkSpherical(SphericalCoordinates.of(-3, Geometry.MINUS_HALF_PI, THREE_QUARTER_PI), 3, Geometry.HALF_PI, QUARTER_PI);
+
+        checkSpherical(SphericalCoordinates.of(-4, QUARTER_PI, Geometry.HALF_PI), 4, MINUS_THREE_QUARTER_PI, Geometry.HALF_PI);
+        checkSpherical(SphericalCoordinates.of(-4, MINUS_THREE_QUARTER_PI, Geometry.HALF_PI), 4, QUARTER_PI, Geometry.HALF_PI);
+    }
+
+    @Test
+    public void testOf_NaNAndInfinite() {
+        // act/assert
+        checkSpherical(SphericalCoordinates.of(Double.NaN, Double.NaN, Double.NaN),
+                Double.NaN, Double.NaN, Double.NaN);
+        checkSpherical(SphericalCoordinates.of(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY),
+                Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
+        checkSpherical(SphericalCoordinates.of(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY),
+                Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
+    }
+
+    @Test
+    public void testOfCartesian() {
+        // arrange
+        double sqrt3 = Math.sqrt(3);
+
+        // act/assert
+        checkSpherical(SphericalCoordinates.ofCartesian(0, 0, 0), 0, 0, 0);
+
+        checkSpherical(SphericalCoordinates.ofCartesian(0.1, 0, 0), 0.1, 0, Geometry.HALF_PI);
+        checkSpherical(SphericalCoordinates.ofCartesian(-0.1, 0, 0), 0.1, Geometry.PI, Geometry.HALF_PI);
+
+        checkSpherical(SphericalCoordinates.ofCartesian(0, 0.1, 0), 0.1, Geometry.HALF_PI, Geometry.HALF_PI);
+        checkSpherical(SphericalCoordinates.ofCartesian(0, -0.1, 0), 0.1, Geometry.MINUS_HALF_PI, Geometry.HALF_PI);
+
+        checkSpherical(SphericalCoordinates.ofCartesian(0, 0, 0.1), 0.1, 0, 0);
+        checkSpherical(SphericalCoordinates.ofCartesian(0, 0, -0.1), 0.1, 0, Geometry.PI);
+
+        checkSpherical(SphericalCoordinates.ofCartesian(1, 1, 1), sqrt3, QUARTER_PI, Math.acos(1 / sqrt3));
+        checkSpherical(SphericalCoordinates.ofCartesian(-1, -1, -1), sqrt3, MINUS_THREE_QUARTER_PI, Math.acos(-1 / sqrt3));
+    }
+
+    @Test
+    public void testToPoint() {
+        // arrange
+        double sqrt3 = Math.sqrt(3);
+
+        // act/assert
+        checkPoint(SphericalCoordinates.of(0, 0, 0).toPoint(), 0, 0, 0);
+
+        checkPoint(SphericalCoordinates.of(1, 0, Geometry.HALF_PI).toPoint(), 1, 0, 0);
+        checkPoint(SphericalCoordinates.of(1, Geometry.PI, Geometry.HALF_PI).toPoint(), -1, 0, 0);
+
+        checkPoint(SphericalCoordinates.of(2, Geometry.HALF_PI, Geometry.HALF_PI).toPoint(), 0, 2, 0);
+        checkPoint(SphericalCoordinates.of(2, Geometry.MINUS_HALF_PI, Geometry.HALF_PI).toPoint(), 0, -2, 0);
+
+        checkPoint(SphericalCoordinates.of(3, 0, 0).toPoint(), 0, 0, 3);
+        checkPoint(SphericalCoordinates.of(3, 0, Geometry.PI).toPoint(), 0, 0, -3);
+
+        checkPoint(SphericalCoordinates.of(Math.sqrt(3), QUARTER_PI, Math.acos(1 / sqrt3)).toPoint(), 1, 1, 1);
+        checkPoint(SphericalCoordinates.of(Math.sqrt(3), MINUS_THREE_QUARTER_PI, Math.acos(-1 / sqrt3)).toPoint(), -1, -1, -1);
+    }
+
+    @Test
+    public void testToVector() {
+        // arrange
+        double sqrt3 = Math.sqrt(3);
+
+        // act/assert
+        checkVector(SphericalCoordinates.of(0, 0, 0).toVector(), 0, 0, 0);
+
+        checkVector(SphericalCoordinates.of(1, 0, Geometry.HALF_PI).toVector(), 1, 0, 0);
+        checkVector(SphericalCoordinates.of(1, Geometry.PI, Geometry.HALF_PI).toVector(), -1, 0, 0);
+
+        checkVector(SphericalCoordinates.of(2, Geometry.HALF_PI, Geometry.HALF_PI).toVector(), 0, 2, 0);
+        checkVector(SphericalCoordinates.of(2, Geometry.MINUS_HALF_PI, Geometry.HALF_PI).toVector(), 0, -2, 0);
+
+        checkVector(SphericalCoordinates.of(3, 0, 0).toVector(), 0, 0, 3);
+        checkVector(SphericalCoordinates.of(3, 0, Geometry.PI).toVector(), 0, 0, -3);
+
+        checkVector(SphericalCoordinates.of(Math.sqrt(3), QUARTER_PI, Math.acos(1 / sqrt3)).toVector(), 1, 1, 1);
+        checkVector(SphericalCoordinates.of(Math.sqrt(3), MINUS_THREE_QUARTER_PI, Math.acos(-1 / sqrt3)).toVector(), -1, -1, -1);
+    }
+
+    @Test
+    public void testToCartesian_callback() {
+        // arrange
+        double sqrt3 = Math.sqrt(3);
+        Coordinates.Factory3D<Point3D> factory = Point3D.getFactory();
+
+        // act/assert
+        checkPoint(SphericalCoordinates.of(0, 0, 0).toCartesian(factory), 0, 0, 0);
+
+        checkPoint(SphericalCoordinates.of(1, 0, Geometry.HALF_PI).toCartesian(factory), 1, 0, 0);
+        checkPoint(SphericalCoordinates.of(1, Geometry.PI, Geometry.HALF_PI).toCartesian(factory), -1, 0, 0);
+
+        checkPoint(SphericalCoordinates.of(2, Geometry.HALF_PI, Geometry.HALF_PI).toCartesian(factory), 0, 2, 0);
+        checkPoint(SphericalCoordinates.of(2, Geometry.MINUS_HALF_PI, Geometry.HALF_PI).toCartesian(factory), 0, -2, 0);
+
+        checkPoint(SphericalCoordinates.of(3, 0, 0).toCartesian(factory), 0, 0, 3);
+        checkPoint(SphericalCoordinates.of(3, 0, Geometry.PI).toCartesian(factory), 0, 0, -3);
+
+        checkPoint(SphericalCoordinates.of(Math.sqrt(3), QUARTER_PI, Math.acos(1 / sqrt3)).toCartesian(factory), 1, 1, 1);
+        checkPoint(SphericalCoordinates.of(Math.sqrt(3), MINUS_THREE_QUARTER_PI, Math.acos(-1 / sqrt3)).toCartesian(factory), -1, -1, -1);
+    }
+
+    @Test
+    public void testToCartesian_static() {
+        // arrange
+        double sqrt3 = Math.sqrt(3);
+        Coordinates.Factory3D<Point3D> factory = Point3D.getFactory();
+
+        // act/assert
+        checkPoint(SphericalCoordinates.toCartesian(0, 0, 0, factory), 0, 0, 0);
+
+        checkPoint(SphericalCoordinates.toCartesian(1, 0, Geometry.HALF_PI, factory), 1, 0, 0);
+        checkPoint(SphericalCoordinates.toCartesian(1, Geometry.PI, Geometry.HALF_PI, factory), -1, 0, 0);
+
+        checkPoint(SphericalCoordinates.toCartesian(2, Geometry.HALF_PI, Geometry.HALF_PI, factory), 0, 2, 0);
+        checkPoint(SphericalCoordinates.toCartesian(2, Geometry.MINUS_HALF_PI, Geometry.HALF_PI, factory), 0, -2, 0);
+
+        checkPoint(SphericalCoordinates.toCartesian(3, 0, 0, factory), 0, 0, 3);
+        checkPoint(SphericalCoordinates.toCartesian(3, 0, Geometry.PI, factory), 0, 0, -3);
+
+        checkPoint(SphericalCoordinates.toCartesian(Math.sqrt(3), QUARTER_PI, Math.acos(1 / sqrt3), factory), 1, 1, 1);
+        checkPoint(SphericalCoordinates.toCartesian(Math.sqrt(3), MINUS_THREE_QUARTER_PI, Math.acos(-1 / sqrt3), factory), -1, -1, -1);
+    }
+
+    @Test
+    public void testGetDimension() {
+        // arrange
+        SphericalCoordinates s = SphericalCoordinates.of(0, 0, 0);
+
+        // act/assert
+        Assert.assertEquals(3, s.getDimension());
+    }
+
+    @Test
+    public void testNaN() {
+        // act/assert
+        Assert.assertTrue(SphericalCoordinates.of(0, 0, Double.NaN).isNaN());
+        Assert.assertTrue(SphericalCoordinates.of(0, Double.NaN, 0).isNaN());
+        Assert.assertTrue(SphericalCoordinates.of(Double.NaN, 0, 0).isNaN());
+
+        Assert.assertFalse(SphericalCoordinates.of(1, 1, 1).isNaN());
+        Assert.assertFalse(SphericalCoordinates.of(1, 1, Double.NEGATIVE_INFINITY).isNaN());
+        Assert.assertFalse(SphericalCoordinates.of(1, Double.POSITIVE_INFINITY, 1).isNaN());
+        Assert.assertFalse(SphericalCoordinates.of(Double.NEGATIVE_INFINITY, 1, 1).isNaN());
+    }
+
+    @Test
+    public void testInfinite() {
+        // act/assert
+        Assert.assertTrue(SphericalCoordinates.of(0, 0, Double.NEGATIVE_INFINITY).isInfinite());
+        Assert.assertTrue(SphericalCoordinates.of(0, Double.NEGATIVE_INFINITY, 0).isInfinite());
+        Assert.assertTrue(SphericalCoordinates.of(Double.NEGATIVE_INFINITY, 0, 0).isInfinite());
+        Assert.assertTrue(SphericalCoordinates.of(0, 0, Double.POSITIVE_INFINITY).isInfinite());
+        Assert.assertTrue(SphericalCoordinates.of(0, Double.POSITIVE_INFINITY, 0).isInfinite());
+        Assert.assertTrue(SphericalCoordinates.of(Double.POSITIVE_INFINITY, 0, 0).isInfinite());
+
+        Assert.assertFalse(SphericalCoordinates.of(1, 1, 1).isInfinite());
+        Assert.assertFalse(SphericalCoordinates.of(0, 0, Double.NaN).isInfinite());
+        Assert.assertFalse(SphericalCoordinates.of(0, Double.NEGATIVE_INFINITY, Double.NaN).isInfinite());
+        Assert.assertFalse(SphericalCoordinates.of(Double.NaN, 0, Double.NEGATIVE_INFINITY).isInfinite());
+        Assert.assertFalse(SphericalCoordinates.of(Double.POSITIVE_INFINITY, Double.NaN, 0).isInfinite());
+        Assert.assertFalse(SphericalCoordinates.of(0, Double.NaN, Double.POSITIVE_INFINITY).isInfinite());
+    }
+
+    @Test
+    public void testHashCode() {
+        // arrange
+        SphericalCoordinates a = SphericalCoordinates.of(1, 2, 3);
+        SphericalCoordinates b = SphericalCoordinates.of(10, 2, 3);
+        SphericalCoordinates c = SphericalCoordinates.of(1, 20, 3);
+        SphericalCoordinates d = SphericalCoordinates.of(1, 2, 30);
+
+        SphericalCoordinates e = SphericalCoordinates.of(1, 2, 3);
+
+        // act/assert
+        Assert.assertEquals(a.hashCode(), a.hashCode());
+        Assert.assertEquals(a.hashCode(), e.hashCode());
+
+        Assert.assertNotEquals(a.hashCode(), b.hashCode());
+        Assert.assertNotEquals(a.hashCode(), c.hashCode());
+        Assert.assertNotEquals(a.hashCode(), d.hashCode());
+    }
+
+    @Test
+    public void testHashCode_NaNInstancesHaveSameHashCode() {
+        // arrange
+        SphericalCoordinates a = SphericalCoordinates.of(1, 2, Double.NaN);
+        SphericalCoordinates b = SphericalCoordinates.of(1, Double.NaN, 3);
+        SphericalCoordinates c = SphericalCoordinates.of(Double.NaN, 2, 3);
+
+        // act/assert
+        Assert.assertEquals(a.hashCode(), b.hashCode());
+        Assert.assertEquals(b.hashCode(), c.hashCode());
+    }
+
+    @Test
+    public void testEquals() {
+        // arrange
+        SphericalCoordinates a = SphericalCoordinates.of(1, 2, 3);
+        SphericalCoordinates b = SphericalCoordinates.of(10, 2, 3);
+        SphericalCoordinates c = SphericalCoordinates.of(1, 20, 3);
+        SphericalCoordinates d = SphericalCoordinates.of(1, 2, 30);
+
+        SphericalCoordinates e = SphericalCoordinates.of(1, 2, 3);
+
+        // act/assert
+        Assert.assertFalse(a.equals(null));
+        Assert.assertFalse(a.equals(new Object()));
+
+        Assert.assertTrue(a.equals(a));
+        Assert.assertTrue(a.equals(e));
+
+        Assert.assertFalse(a.equals(b));
+        Assert.assertFalse(a.equals(c));
+        Assert.assertFalse(a.equals(d));
+    }
+
+    @Test
+    public void testEquals_NaNInstancesEqual() {
+        // arrange
+        SphericalCoordinates a = SphericalCoordinates.of(1, 2, Double.NaN);
+        SphericalCoordinates b = SphericalCoordinates.of(1, Double.NaN, 3);
+        SphericalCoordinates c = SphericalCoordinates.of(Double.NaN, 2, 3);
+
+        // act/assert
+        Assert.assertTrue(a.equals(b));
+        Assert.assertTrue(b.equals(c));
+    }
+
+    @Test
+    public void testToString() {
+        // arrange
+        SphericalCoordinates sph = SphericalCoordinates.of(1, 2, 3);
+        Pattern pattern = Pattern.compile("\\(1.{0,2}, 2.{0,2}, 3.{0,2}\\)");
+
+        // act
+        String str = sph.toString();;
+
+        // assert
+        Assert.assertTrue("Expected string " + str + " to match regex " + pattern,
+                    pattern.matcher(str).matches());
+    }
+
+    @Test
+    public void testParse() {
+        // act/assert
+        checkSpherical(SphericalCoordinates.parse("(1, 2, -3)"), 1, 2, 3);
+        checkSpherical(SphericalCoordinates.parse("(  2e0 , 5 , -0.000 )"), 2, 5 - Geometry.TWO_PI, 0);
+        checkSpherical(SphericalCoordinates.parse("(NaN,Infinity,-Infinity)"), Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParse_failure() {
+        // act/assert
+        SphericalCoordinates.parse("abc");
+    }
+
+    @Test
+    public void testGetFactory() {
+        // act
+        Coordinates.Factory3D<SphericalCoordinates> factory = SphericalCoordinates.getFactory();
+
+        // assert
+        checkSpherical(factory.create(2, 0.5 + Geometry.TWO_PI, 0.1 + Geometry.PI), 2, 0.5, Geometry.PI - 0.1);
+    }
+
+    private void checkSpherical(SphericalCoordinates c, double radius, double azimuth, double polar) {
+        Assert.assertEquals(radius, c.getRadius(), EPS);
+        Assert.assertEquals(azimuth, c.getAzimuth(), EPS);
+        Assert.assertEquals(polar, c.getPolar(), EPS);
+    }
+
+    private void checkPoint(Point3D p, double x, double y, double z) {
+        Assert.assertEquals(x, p.getX(), EPS);
+        Assert.assertEquals(y, p.getY(), EPS);
+        Assert.assertEquals(z, p.getZ(), EPS);
+    }
+
+    private void checkVector(Vector3D v, double x, double y, double z) {
+        Assert.assertEquals(x, v.getX(), EPS);
+        Assert.assertEquals(y, v.getY(), EPS);
+        Assert.assertEquals(z, v.getZ(), EPS);
+    }
+}
diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/SphericalCoordinatesTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SphericalCoordinatesTest_OLD.java
similarity index 69%
rename from commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/SphericalCoordinatesTest.java
rename to commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SphericalCoordinatesTest_OLD.java
index db3b76e..999111c 100644
--- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/SphericalCoordinatesTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SphericalCoordinatesTest_OLD.java
@@ -15,56 +15,57 @@
  * limitations under the License.
  */
 
-package org.apache.commons.geometry.spherical;
+package org.apache.commons.geometry.euclidean.threed;
 
+import org.apache.commons.geometry.euclidean.threed.SphericalCoordinates_OLD;
 import org.apache.commons.geometry.euclidean.threed.Vector3D;
 import org.apache.commons.geometry.core.GeometryTestUtils;
 import org.junit.Assert;
 import org.junit.Test;
 
-public class SphericalCoordinatesTest {
+public class SphericalCoordinatesTest_OLD {
 
     @Test
     public void testCoordinatesStoC() {
         double piO2 = 0.5 * Math.PI;
-        SphericalCoordinates sc1 = new SphericalCoordinates(2.0, 0, piO2);
+        SphericalCoordinates_OLD sc1 = new SphericalCoordinates_OLD(2.0, 0, piO2);
         Assert.assertEquals(0, sc1.getCartesian().distance(Vector3D.of(2, 0, 0)), 1.0e-10);
-        SphericalCoordinates sc2 = new SphericalCoordinates(2.0, piO2, piO2);
+        SphericalCoordinates_OLD sc2 = new SphericalCoordinates_OLD(2.0, piO2, piO2);
         Assert.assertEquals(0, sc2.getCartesian().distance(Vector3D.of(0, 2, 0)), 1.0e-10);
-        SphericalCoordinates sc3 = new SphericalCoordinates(2.0, Math.PI, piO2);
+        SphericalCoordinates_OLD sc3 = new SphericalCoordinates_OLD(2.0, Math.PI, piO2);
         Assert.assertEquals(0, sc3.getCartesian().distance(Vector3D.of(-2, 0, 0)), 1.0e-10);
-        SphericalCoordinates sc4 = new SphericalCoordinates(2.0, -piO2, piO2);
+        SphericalCoordinates_OLD sc4 = new SphericalCoordinates_OLD(2.0, -piO2, piO2);
         Assert.assertEquals(0, sc4.getCartesian().distance(Vector3D.of(0, -2, 0)), 1.0e-10);
-        SphericalCoordinates sc5 = new SphericalCoordinates(2.0, 1.23456, 0);
+        SphericalCoordinates_OLD sc5 = new SphericalCoordinates_OLD(2.0, 1.23456, 0);
         Assert.assertEquals(0, sc5.getCartesian().distance(Vector3D.of(0, 0, 2)), 1.0e-10);
-        SphericalCoordinates sc6 = new SphericalCoordinates(2.0, 6.54321, Math.PI);
+        SphericalCoordinates_OLD sc6 = new SphericalCoordinates_OLD(2.0, 6.54321, Math.PI);
         Assert.assertEquals(0, sc6.getCartesian().distance(Vector3D.of(0, 0, -2)), 1.0e-10);
     }
 
     @Test
     public void testCoordinatesCtoS() {
         double piO2 = 0.5 * Math.PI;
-        SphericalCoordinates sc1 = new SphericalCoordinates(Vector3D.of(2, 0, 0));
+        SphericalCoordinates_OLD sc1 = new SphericalCoordinates_OLD(Vector3D.of(2, 0, 0));
         Assert.assertEquals(2,           sc1.getR(),     1.0e-10);
         Assert.assertEquals(0,           sc1.getTheta(), 1.0e-10);
         Assert.assertEquals(piO2,        sc1.getPhi(),   1.0e-10);
-        SphericalCoordinates sc2 = new SphericalCoordinates(Vector3D.of(0, 2, 0));
+        SphericalCoordinates_OLD sc2 = new SphericalCoordinates_OLD(Vector3D.of(0, 2, 0));
         Assert.assertEquals(2,           sc2.getR(),     1.0e-10);
         Assert.assertEquals(piO2,        sc2.getTheta(), 1.0e-10);
         Assert.assertEquals(piO2,        sc2.getPhi(),   1.0e-10);
-        SphericalCoordinates sc3 = new SphericalCoordinates(Vector3D.of(-2, 0, 0));
+        SphericalCoordinates_OLD sc3 = new SphericalCoordinates_OLD(Vector3D.of(-2, 0, 0));
         Assert.assertEquals(2,           sc3.getR(),     1.0e-10);
         Assert.assertEquals(Math.PI, sc3.getTheta(), 1.0e-10);
         Assert.assertEquals(piO2,        sc3.getPhi(),   1.0e-10);
-        SphericalCoordinates sc4 = new SphericalCoordinates(Vector3D.of(0, -2, 0));
+        SphericalCoordinates_OLD sc4 = new SphericalCoordinates_OLD(Vector3D.of(0, -2, 0));
         Assert.assertEquals(2,           sc4.getR(),     1.0e-10);
         Assert.assertEquals(-piO2,       sc4.getTheta(), 1.0e-10);
         Assert.assertEquals(piO2,        sc4.getPhi(),   1.0e-10);
-        SphericalCoordinates sc5 = new SphericalCoordinates(Vector3D.of(0, 0, 2));
+        SphericalCoordinates_OLD sc5 = new SphericalCoordinates_OLD(Vector3D.of(0, 0, 2));
         Assert.assertEquals(2,           sc5.getR(),     1.0e-10);
         //  don't check theta on poles, as it is singular
         Assert.assertEquals(0,           sc5.getPhi(),   1.0e-10);
-        SphericalCoordinates sc6 = new SphericalCoordinates(Vector3D.of(0, 0, -2));
+        SphericalCoordinates_OLD sc6 = new SphericalCoordinates_OLD(Vector3D.of(0, 0, -2));
         Assert.assertEquals(2,           sc6.getR(),     1.0e-10);
         //  don't check theta on poles, as it is singular
         Assert.assertEquals(Math.PI, sc6.getPhi(),   1.0e-10);
@@ -72,8 +73,8 @@ public class SphericalCoordinatesTest {
 
     @Test
     public void testSerialization() {
-        SphericalCoordinates a = new SphericalCoordinates(3, 2, 1);
-        SphericalCoordinates b = (SphericalCoordinates) GeometryTestUtils.serializeAndRecover(a);
+        SphericalCoordinates_OLD a = new SphericalCoordinates_OLD(3, 2, 1);
+        SphericalCoordinates_OLD b = (SphericalCoordinates_OLD) GeometryTestUtils.serializeAndRecover(a);
         Assert.assertEquals(0, a.getCartesian().distance(b.getCartesian()), 1.0e-10);
         Assert.assertEquals(a.getR(),     b.getR(),     1.0e-10);
         Assert.assertEquals(a.getTheta(), b.getTheta(), 1.0e-10);
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 c9b3cf9..86bf0a3 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
@@ -770,20 +770,6 @@ public class Vector3DTest {
                     2, 5, -3);
     }
 
-    @Test
-    public void testAngular() {
-        Assert.assertEquals(0,           Vector3D.PLUS_X.getAlpha(), 1.0e-10);
-        Assert.assertEquals(0,           Vector3D.PLUS_X.getDelta(), 1.0e-10);
-        Assert.assertEquals(Math.PI / 2, Vector3D.PLUS_Y.getAlpha(), 1.0e-10);
-        Assert.assertEquals(0,           Vector3D.PLUS_Y.getDelta(), 1.0e-10);
-        Assert.assertEquals(0,           Vector3D.PLUS_Z.getAlpha(), 1.0e-10);
-        Assert.assertEquals(Math.PI / 2, Vector3D.PLUS_Z.getDelta(), 1.0e-10);
-
-        Vector3D u = Vector3D.of(-1, 1, -1);
-        Assert.assertEquals(3 * Math.PI /4, u.getAlpha(), 1.0e-10);
-        Assert.assertEquals(-1.0 / Math.sqrt(3), Math.sin(u.getDelta()), 1.0e-10);
-    }
-
     private void checkVector(Vector3D v, double x, double y, double z) {
         Assert.assertEquals(x, v.getX(), EPS);
         Assert.assertEquals(y, v.getY(), EPS);
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/package-info.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/package-info.java
deleted file mode 100644
index 020a968..0000000
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/package-info.java
+++ /dev/null
@@ -1,23 +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.
- */
-/**
- *
- * <p>
- * Base package for spherical geometry components.
- * </p>
- */
-package org.apache.commons.geometry.spherical;