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 <[email protected]> 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 (α) of the vector, between -π and +π - */ - public double getAlpha() { - return Math.atan2(getY(), getX()); - } - - /** Get the elevation of the vector. - * @return elevation (δ) of the vector, between -π/2 and +π/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;
