S1Point.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      https://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. /*
  18.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */
  21. package org.hipparchus.geometry.spherical.oned;

  22. import org.hipparchus.geometry.Point;
  23. import org.hipparchus.geometry.Space;
  24. import org.hipparchus.geometry.euclidean.twod.Vector2D;
  25. import org.hipparchus.util.FastMath;
  26. import org.hipparchus.util.MathUtils;
  27. import org.hipparchus.util.SinCos;

  28. /** This class represents a point on the 1-sphere.
  29.  * <p>Instances of this class are guaranteed to be immutable.</p>
  30.  */
  31. public class S1Point implements Point<Sphere1D, S1Point> {

  32.    // CHECKSTYLE: stop ConstantName
  33.     /** A vector with all coordinates set to NaN. */
  34.     public static final S1Point NaN = new S1Point(Double.NaN, Vector2D.NaN);
  35.     // CHECKSTYLE: resume ConstantName

  36.     /** Serializable UID. */
  37.     private static final long serialVersionUID = 20131218L;

  38.     /** Azimuthal angle \( \alpha \). */
  39.     private final double alpha;

  40.     /** Corresponding 2D normalized vector. */
  41.     private final Vector2D vector;

  42.     /** Simple constructor.
  43.      * Build a vector from its coordinates
  44.      * @param alpha azimuthal angle \( \alpha \)
  45.      * @see #getAlpha()
  46.      */
  47.     public S1Point(final double alpha) {
  48.         this(MathUtils.normalizeAngle(alpha, FastMath.PI), buildVector(alpha));
  49.     }

  50.     /** Build a point from its internal components.
  51.      * @param alpha azimuthal angle \( \alpha \)
  52.      * @param vector corresponding vector
  53.      */
  54.     private S1Point(final double alpha, final Vector2D vector) {
  55.         this.alpha  = alpha;
  56.         this.vector = vector;
  57.     }

  58.     /** Get the azimuthal angle \( \alpha \).
  59.      * @return azimuthal angle \( \alpha \)
  60.      * @see #S1Point(double)
  61.      */
  62.     public double getAlpha() {
  63.         return alpha;
  64.     }

  65.     /** Get the corresponding normalized vector in the 2D euclidean space.
  66.      * @return normalized vector
  67.      */
  68.     public Vector2D getVector() {
  69.         return vector;
  70.     }

  71.     /** {@inheritDoc} */
  72.     @Override
  73.     public Space getSpace() {
  74.         return Sphere1D.getInstance();
  75.     }

  76.     /** {@inheritDoc} */
  77.     @Override
  78.     public boolean isNaN() {
  79.         return Double.isNaN(alpha);
  80.     }

  81.     /** {@inheritDoc} */
  82.     @Override
  83.     public double distance(final S1Point point) {
  84.         return distance(this, point);
  85.     }

  86.     /** Compute the distance (angular separation) between two points.
  87.      * @param p1 first vector
  88.      * @param p2 second vector
  89.      * @return the angular separation between p1 and p2
  90.      */
  91.     public static double distance(S1Point p1, S1Point p2) {
  92.         return Vector2D.angle(p1.vector, p2.vector);
  93.     }

  94.     /** {@inheritDoc} */
  95.     @Override
  96.     public S1Point moveTowards(final S1Point other, final double ratio) {
  97.         return new S1Point(alpha + ratio * (other.alpha - alpha));
  98.     }

  99.     /**
  100.      * Test for the equality of two points on the 1-sphere.
  101.      * <p>
  102.      * If all coordinates of two points are exactly the same, and none are
  103.      * {@code Double.NaN}, the two points are considered to be equal.
  104.      * </p>
  105.      * <p>
  106.      * {@code NaN} coordinates are considered to affect globally the point
  107.      * and be equals to each other - i.e, if either (or all) coordinates of the
  108.      * point are equal to {@code Double.NaN}, the point is equal to
  109.      * {@link #NaN}.
  110.      * </p>
  111.      *
  112.      * @param other Object to test for equality to this
  113.      * @return true if two points on the 1-sphere objects are equal, false if
  114.      *         object is null, not an instance of S1Point, or
  115.      *         not equal to this S1Point instance
  116.      *
  117.      */
  118.     @Override
  119.     public boolean equals(Object other) {

  120.         if (this == other) {
  121.             return true;
  122.         }

  123.         if (other instanceof S1Point) {
  124.             final S1Point rhs = (S1Point) other;
  125.             return alpha == rhs.alpha || isNaN() && rhs.isNaN();
  126.         }

  127.         return false;

  128.     }

  129.     /**
  130.      * Test for the equality of two points on the 1-sphere.
  131.      * <p>
  132.      * If all coordinates of two points are exactly the same, and none are
  133.      * {@code Double.NaN}, the two points are considered to be equal.
  134.      * </p>
  135.      * <p>
  136.      * In compliance with IEEE754 handling, if any coordinates of any of the
  137.      * two points are {@code NaN}, then the points are considered different.
  138.      * This implies that {@link #NaN S1Point.NaN}.equals({@link #NaN S1Point.NaN})
  139.      * returns {@code false} despite the instance is checked against itself.
  140.      * </p>
  141.      *
  142.      * @param other Object to test for equality to this
  143.      * @return true if two points objects are equal, false if
  144.      *         object is null, not an instance of S1Point, or
  145.      *         not equal to this S1Point instance
  146.      * @since 2.1
  147.      */
  148.     public boolean equalsIeee754(Object other) {

  149.         if (this == other && !isNaN()) {
  150.             return true;
  151.         }

  152.         if (other instanceof S1Point) {
  153.             final S1Point rhs = (S1Point) other;
  154.             return alpha == rhs.alpha;
  155.         }

  156.         return false;

  157.     }

  158.     /**
  159.      * Get a hashCode for the point.
  160.      * <p>
  161.      * All NaN values have the same hash code.</p>
  162.      *
  163.      * @return a hash code value for this object
  164.      */
  165.     @Override
  166.     public int hashCode() {
  167.         if (isNaN()) {
  168.             return 542;
  169.         }
  170.         return 1759 * MathUtils.hash(alpha);
  171.     }

  172.     /**
  173.      * Build the 2D vector corresponding to the given angle.
  174.      * @param alpha angle
  175.      * @return the corresponding 2D vector
  176.      */
  177.     private static Vector2D buildVector(final double alpha) {
  178.         final SinCos sc = FastMath.sinCos(alpha);
  179.         return new Vector2D(sc.cos(), sc.sin());
  180.     }

  181. }