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 /* 19 * This is not the original file distributed by the Apache Software Foundation 20 * It has been modified by the Hipparchus project 21 */ 22 package org.hipparchus.geometry.spherical.oned; 23 24 import org.hipparchus.geometry.Point; 25 import org.hipparchus.geometry.Space; 26 import org.hipparchus.geometry.euclidean.twod.Vector2D; 27 import org.hipparchus.util.FastMath; 28 import org.hipparchus.util.MathUtils; 29 import org.hipparchus.util.SinCos; 30 31 /** This class represents a point on the 1-sphere. 32 * <p>Instances of this class are guaranteed to be immutable.</p> 33 */ 34 public class S1Point implements Point<Sphere1D, S1Point> { 35 36 // CHECKSTYLE: stop ConstantName 37 /** A vector with all coordinates set to NaN. */ 38 public static final S1Point NaN = new S1Point(Double.NaN, Vector2D.NaN); 39 // CHECKSTYLE: resume ConstantName 40 41 /** Serializable UID. */ 42 private static final long serialVersionUID = 20131218L; 43 44 /** Azimuthal angle \( \alpha \). */ 45 private final double alpha; 46 47 /** Corresponding 2D normalized vector. */ 48 private final Vector2D vector; 49 50 /** Simple constructor. 51 * Build a vector from its coordinates 52 * @param alpha azimuthal angle \( \alpha \) 53 * @see #getAlpha() 54 */ 55 public S1Point(final double alpha) { 56 this(MathUtils.normalizeAngle(alpha, FastMath.PI), buildVector(alpha)); 57 } 58 59 /** Build a point from its internal components. 60 * @param alpha azimuthal angle \( \alpha \) 61 * @param vector corresponding vector 62 */ 63 private S1Point(final double alpha, final Vector2D vector) { 64 this.alpha = alpha; 65 this.vector = vector; 66 } 67 68 /** Get the azimuthal angle \( \alpha \). 69 * @return azimuthal angle \( \alpha \) 70 * @see #S1Point(double) 71 */ 72 public double getAlpha() { 73 return alpha; 74 } 75 76 /** Get the corresponding normalized vector in the 2D euclidean space. 77 * @return normalized vector 78 */ 79 public Vector2D getVector() { 80 return vector; 81 } 82 83 /** {@inheritDoc} */ 84 @Override 85 public Space getSpace() { 86 return Sphere1D.getInstance(); 87 } 88 89 /** {@inheritDoc} */ 90 @Override 91 public boolean isNaN() { 92 return Double.isNaN(alpha); 93 } 94 95 /** {@inheritDoc} */ 96 @Override 97 public double distance(final S1Point point) { 98 return distance(this, point); 99 } 100 101 /** Compute the distance (angular separation) between two points. 102 * @param p1 first vector 103 * @param p2 second vector 104 * @return the angular separation between p1 and p2 105 */ 106 public static double distance(S1Point p1, S1Point p2) { 107 return Vector2D.angle(p1.vector, p2.vector); 108 } 109 110 /** {@inheritDoc} */ 111 @Override 112 public S1Point moveTowards(final S1Point other, final double ratio) { 113 return new S1Point(alpha + ratio * (other.alpha - alpha)); 114 } 115 116 /** 117 * Test for the equality of two points on the 1-sphere. 118 * <p> 119 * If all coordinates of two points are exactly the same, and none are 120 * {@code Double.NaN}, the two points are considered to be equal. 121 * </p> 122 * <p> 123 * {@code NaN} coordinates are considered to affect globally the point 124 * and be equals to each other - i.e, if either (or all) coordinates of the 125 * point are equal to {@code Double.NaN}, the point is equal to 126 * {@link #NaN}. 127 * </p> 128 * 129 * @param other Object to test for equality to this 130 * @return true if two points on the 1-sphere objects are equal, false if 131 * object is null, not an instance of S1Point, or 132 * not equal to this S1Point instance 133 * 134 */ 135 @Override 136 public boolean equals(Object other) { 137 138 if (this == other) { 139 return true; 140 } 141 142 if (other instanceof S1Point) { 143 final S1Point rhs = (S1Point) other; 144 return alpha == rhs.alpha || isNaN() && rhs.isNaN(); 145 } 146 147 return false; 148 149 } 150 151 /** 152 * Test for the equality of two points on the 1-sphere. 153 * <p> 154 * If all coordinates of two points are exactly the same, and none are 155 * {@code Double.NaN}, the two points are considered to be equal. 156 * </p> 157 * <p> 158 * In compliance with IEEE754 handling, if any coordinates of any of the 159 * two points are {@code NaN}, then the points are considered different. 160 * This implies that {@link #NaN S1Point.NaN}.equals({@link #NaN S1Point.NaN}) 161 * returns {@code false} despite the instance is checked against itself. 162 * </p> 163 * 164 * @param other Object to test for equality to this 165 * @return true if two points objects are equal, false if 166 * object is null, not an instance of S1Point, or 167 * not equal to this S1Point instance 168 * @since 2.1 169 */ 170 public boolean equalsIeee754(Object other) { 171 172 if (this == other && !isNaN()) { 173 return true; 174 } 175 176 if (other instanceof S1Point) { 177 final S1Point rhs = (S1Point) other; 178 return alpha == rhs.alpha; 179 } 180 181 return false; 182 183 } 184 185 /** 186 * Get a hashCode for the point. 187 * <p> 188 * All NaN values have the same hash code.</p> 189 * 190 * @return a hash code value for this object 191 */ 192 @Override 193 public int hashCode() { 194 if (isNaN()) { 195 return 542; 196 } 197 return 1759 * MathUtils.hash(alpha); 198 } 199 200 /** 201 * Build the 2D vector corresponding to the given angle. 202 * @param alpha angle 203 * @return the corresponding 2D vector 204 */ 205 private static Vector2D buildVector(final double alpha) { 206 final SinCos sc = FastMath.sinCos(alpha); 207 return new Vector2D(sc.cos(), sc.sin()); 208 } 209 210 }