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 }