1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.geometry.spherical.twod;
18
19
20 import java.util.Comparator;
21
22 import org.apache.commons.geometry.core.GeometryTestUtils;
23 import org.apache.commons.geometry.euclidean.threed.Vector3D;
24 import org.apache.commons.geometry.spherical.SphericalTestUtils;
25 import org.apache.commons.numbers.angle.Angle;
26 import org.apache.commons.numbers.core.Precision;
27 import org.junit.jupiter.api.Assertions;
28 import org.junit.jupiter.api.Test;
29
30
31 class Point2STest {
32
33 private static final double TEST_EPS = 1e-10;
34
35 @Test
36 void testProperties() {
37 for (int k = -2; k < 3; ++k) {
38
39 final Point2S p = Point2S.of(1.0 + k * Angle.TWO_PI, 1.4);
40
41
42 Assertions.assertEquals(1.0, p.getAzimuth(), TEST_EPS);
43 Assertions.assertEquals(1.4, p.getPolar(), TEST_EPS);
44
45 Assertions.assertEquals(Math.cos(1.0) * Math.sin(1.4), p.getVector().getX(), TEST_EPS);
46 Assertions.assertEquals(Math.sin(1.0) * Math.sin(1.4), p.getVector().getY(), TEST_EPS);
47 Assertions.assertEquals(Math.cos(1.4), p.getVector().getZ(), TEST_EPS);
48
49 Assertions.assertFalse(p.isNaN());
50 }
51 }
52
53 @Test
54 void testAzimuthPolarComparator() {
55
56 final Comparator<Point2S> comp = Point2S.POLAR_AZIMUTH_ASCENDING_ORDER;
57
58
59 Assertions.assertEquals(0, comp.compare(Point2S.of(1, 2), Point2S.of(1, 2)));
60 Assertions.assertEquals(1, comp.compare(Point2S.of(1, 2), Point2S.of(2, 1)));
61 Assertions.assertEquals(-1, comp.compare(Point2S.of(2, 1), Point2S.of(1, 2)));
62
63 Assertions.assertEquals(-1, comp.compare(Point2S.of(1, 2), Point2S.of(1, 3)));
64 Assertions.assertEquals(1, comp.compare(Point2S.of(1, 3), Point2S.of(1, 2)));
65
66 Assertions.assertEquals(1, comp.compare(null, Point2S.of(1, 2)));
67 Assertions.assertEquals(-1, comp.compare(Point2S.of(1, 2), null));
68 Assertions.assertEquals(0, comp.compare(null, null));
69 }
70
71 @Test
72 void testFrom_vector() {
73
74 final double quarterPi = 0.25 * Math.PI;
75
76
77 checkPoint(Point2S.from(Vector3D.of(1, 1, 0)), quarterPi, Angle.PI_OVER_TWO);
78 checkPoint(Point2S.from(Vector3D.of(1, 0, 1)), 0, quarterPi);
79 checkPoint(Point2S.from(Vector3D.of(0, 1, 1)), Angle.PI_OVER_TWO, quarterPi);
80
81 checkPoint(Point2S.from(Vector3D.of(1, -1, 0)), Angle.TWO_PI - quarterPi, Angle.PI_OVER_TWO);
82 checkPoint(Point2S.from(Vector3D.of(-1, 0, -1)), Math.PI, Math.PI - quarterPi);
83 checkPoint(Point2S.from(Vector3D.of(0, -1, -1)), Angle.TWO_PI - Angle.PI_OVER_TWO, Math.PI - quarterPi);
84 }
85
86 @Test
87 void testNaN() {
88
89 Assertions.assertTrue(Point2S.NaN.isNaN());
90 Assertions.assertEquals(Point2S.NaN, Point2S.of(Double.NaN, 1.0));
91 Assertions.assertNotEquals(Point2S.of(1.0, 1.3), Point2S.NaN);
92 Assertions.assertNull(Point2S.NaN.getVector());
93
94 Assertions.assertEquals(Point2S.NaN.hashCode(), Point2S.of(Double.NaN, Double.NaN).hashCode());
95 }
96
97 @Test
98 void testInfinite() {
99
100 Assertions.assertTrue(Point2S.of(0, Double.POSITIVE_INFINITY).isInfinite());
101 Assertions.assertTrue(Point2S.of(Double.POSITIVE_INFINITY, 0).isInfinite());
102
103 Assertions.assertTrue(Point2S.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY).isInfinite());
104
105 Assertions.assertFalse(Point2S.of(0, 0).isInfinite());
106 Assertions.assertFalse(Point2S.of(1, 1).isInfinite());
107 Assertions.assertFalse(Point2S.NaN.isInfinite());
108 }
109
110 @Test
111 void testFinite() {
112
113 Assertions.assertTrue(Point2S.of(0, 0).isFinite());
114 Assertions.assertTrue(Point2S.of(1, 1).isFinite());
115
116 Assertions.assertFalse(Point2S.of(0, Double.POSITIVE_INFINITY).isFinite());
117 Assertions.assertFalse(Point2S.of(Double.POSITIVE_INFINITY, 0).isFinite());
118 Assertions.assertFalse(Point2S.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY).isFinite());
119
120 Assertions.assertFalse(Point2S.NaN.isFinite());
121 }
122
123 @Test
124 void testDistance() {
125
126 final Point2S a = Point2S.of(1.0, 0.5 * Math.PI);
127 final Point2S b = Point2S.of(a.getAzimuth() + 0.5 * Math.PI, a.getPolar());
128
129
130 Assertions.assertEquals(0.5 * Math.PI, a.distance(b), 1.0e-10);
131 Assertions.assertEquals(Math.PI, a.distance(a.antipodal()), 1.0e-10);
132 Assertions.assertEquals(0.5 * Math.PI, Point2S.MINUS_I.distance(Point2S.MINUS_K), 1.0e-10);
133 Assertions.assertEquals(0.0, Point2S.of(1.0, 0).distance(Point2S.of(2.0, 0)), 1.0e-10);
134 }
135
136 @Test
137 void testSlerp_alongEquator() {
138
139 final Point2S p1 = Point2S.PLUS_I;
140 final Point2S p2 = Point2S.PLUS_J;
141
142
143 SphericalTestUtils.assertPointsEq(p1, p1.slerp(p2, 0), TEST_EPS);
144 SphericalTestUtils.assertPointsEq(Point2S.of(0.25 * Angle.PI_OVER_TWO, Angle.PI_OVER_TWO), p1.slerp(p2, 0.25), TEST_EPS);
145 SphericalTestUtils.assertPointsEq(Point2S.of(0.5 * Angle.PI_OVER_TWO, Angle.PI_OVER_TWO), p1.slerp(p2, 0.5), TEST_EPS);
146 SphericalTestUtils.assertPointsEq(Point2S.of(0.75 * Angle.PI_OVER_TWO, Angle.PI_OVER_TWO), p1.slerp(p2, 0.75), TEST_EPS);
147 SphericalTestUtils.assertPointsEq(p2, p1.slerp(p2, 1), TEST_EPS);
148
149 SphericalTestUtils.assertPointsEq(p2, p2.slerp(p1, 0), TEST_EPS);
150 SphericalTestUtils.assertPointsEq(Point2S.of(0.75 * Angle.PI_OVER_TWO, Angle.PI_OVER_TWO), p2.slerp(p1, 0.25), TEST_EPS);
151 SphericalTestUtils.assertPointsEq(Point2S.of(0.5 * Angle.PI_OVER_TWO, Angle.PI_OVER_TWO), p2.slerp(p1, 0.5), TEST_EPS);
152 SphericalTestUtils.assertPointsEq(Point2S.of(0.25 * Angle.PI_OVER_TWO, Angle.PI_OVER_TWO), p2.slerp(p1, 0.75), TEST_EPS);
153 SphericalTestUtils.assertPointsEq(p1, p2.slerp(p1, 1), TEST_EPS);
154
155 SphericalTestUtils.assertPointsEq(Point2S.MINUS_I, p1.slerp(p2, 2), TEST_EPS);
156 SphericalTestUtils.assertPointsEq(Point2S.MINUS_J, p1.slerp(p2, -1), TEST_EPS);
157 }
158
159 @Test
160 void testSlerp_alongMeridian() {
161
162 final Point2S p1 = Point2S.PLUS_J;
163 final Point2S p2 = Point2S.PLUS_K;
164
165
166 SphericalTestUtils.assertPointsEq(p1, p1.slerp(p2, 0), TEST_EPS);
167 SphericalTestUtils.assertPointsEq(Point2S.of(Angle.PI_OVER_TWO, 0.75 * Angle.PI_OVER_TWO), p1.slerp(p2, 0.25), TEST_EPS);
168 SphericalTestUtils.assertPointsEq(Point2S.of(Angle.PI_OVER_TWO, 0.5 * Angle.PI_OVER_TWO), p1.slerp(p2, 0.5), TEST_EPS);
169 SphericalTestUtils.assertPointsEq(Point2S.of(Angle.PI_OVER_TWO, 0.25 * Angle.PI_OVER_TWO), p1.slerp(p2, 0.75), TEST_EPS);
170 SphericalTestUtils.assertPointsEq(p2, p1.slerp(p2, 1), TEST_EPS);
171
172 SphericalTestUtils.assertPointsEq(p2, p2.slerp(p1, 0), TEST_EPS);
173 SphericalTestUtils.assertPointsEq(Point2S.of(Angle.PI_OVER_TWO, 0.25 * Angle.PI_OVER_TWO), p2.slerp(p1, 0.25), TEST_EPS);
174 SphericalTestUtils.assertPointsEq(Point2S.of(Angle.PI_OVER_TWO, 0.5 * Angle.PI_OVER_TWO), p2.slerp(p1, 0.5), TEST_EPS);
175 SphericalTestUtils.assertPointsEq(Point2S.of(Angle.PI_OVER_TWO, 0.75 * Angle.PI_OVER_TWO), p2.slerp(p1, 0.75), TEST_EPS);
176 SphericalTestUtils.assertPointsEq(p1, p2.slerp(p1, 1), TEST_EPS);
177
178 SphericalTestUtils.assertPointsEq(Point2S.MINUS_J, p1.slerp(p2, 2), TEST_EPS);
179 SphericalTestUtils.assertPointsEq(Point2S.MINUS_K, p1.slerp(p2, -1), TEST_EPS);
180 }
181
182 @Test
183 void testSlerp_samePoint() {
184
185 final Point2S p1 = Point2S.PLUS_I;
186
187
188 SphericalTestUtils.assertPointsEq(p1, p1.slerp(p1, 0), TEST_EPS);
189 SphericalTestUtils.assertPointsEq(p1, p1.slerp(p1, 0.5), TEST_EPS);
190 SphericalTestUtils.assertPointsEq(p1, p1.slerp(p1, 1), TEST_EPS);
191 }
192
193 @Test
194 void testSlerp_antipodal() {
195
196 final Point2S p1 = Point2S.PLUS_I;
197 final Point2S p2 = Point2S.MINUS_I;
198
199
200 SphericalTestUtils.assertPointsEq(p1, p1.slerp(p1, 0), TEST_EPS);
201 SphericalTestUtils.assertPointsEq(p1, p1.slerp(p1, 1), TEST_EPS);
202
203 final Point2S pt = p1.slerp(p2, 0.5);
204 Assertions.assertEquals(p1.distance(pt), p2.distance(pt), TEST_EPS);
205 }
206
207 @Test
208 void testAntipodal() {
209 for (double az = -6 * Math.PI; az <= 6 * Math.PI; az += 0.1) {
210 for (double p = 0; p <= Math.PI; p += 0.1) {
211
212 final Point2S pt = Point2S.of(az, p);
213
214
215 final Point2S result = pt.antipodal();
216
217
218 Assertions.assertEquals(Math.PI, pt.distance(result), TEST_EPS);
219
220
221
222 Assertions.assertEquals(Math.PI,
223 Point2S.of(result.getAzimuth(), result.getPolar()).distance(pt), TEST_EPS);
224
225
226 Assertions.assertEquals(-1, pt.getVector().dot(result.getVector()), TEST_EPS);
227 }
228 }
229 }
230
231 @Test
232 void testAntipodal_numericalStability() {
233
234 final double eps = 1e-16;
235 final Point2S pt = Point2S.of(1, 2);
236
237
238 final Point2S result = pt.antipodal().antipodal();
239
240
241 Assertions.assertEquals(1.0, result.getAzimuth(), eps);
242 Assertions.assertEquals(2.0, result.getPolar(), eps);
243 }
244
245 @Test
246 void testDimension() {
247
248 final Point2S pt = Point2S.of(1, 2);
249
250
251 Assertions.assertEquals(2, pt.getDimension());
252 }
253
254 @Test
255 void testEq() {
256
257 final Precision.DoubleEquivalence smallEps = Precision.doubleEquivalenceOfEpsilon(1e-5);
258 final Precision.DoubleEquivalence largeEps = Precision.doubleEquivalenceOfEpsilon(5e-1);
259
260 final Point2S a = Point2S.of(1.0, 2.0);
261 final Point2S b = Point2S.of(1.0, 2.01);
262 final Point2S c = Point2S.of(1.01, 2.0);
263 final Point2S d = Point2S.of(1.0, 2.0);
264 final Point2S e = Point2S.of(3.0, 2.0);
265
266
267 Assertions.assertTrue(a.eq(a, smallEps));
268 Assertions.assertFalse(a.eq(b, smallEps));
269 Assertions.assertFalse(a.eq(c, smallEps));
270 Assertions.assertTrue(a.eq(d, smallEps));
271 Assertions.assertFalse(a.eq(e, smallEps));
272
273 Assertions.assertTrue(a.eq(a, largeEps));
274 Assertions.assertTrue(a.eq(b, largeEps));
275 Assertions.assertTrue(a.eq(c, largeEps));
276 Assertions.assertTrue(a.eq(d, largeEps));
277 Assertions.assertFalse(a.eq(e, largeEps));
278 }
279
280 @Test
281 void testHashCode() {
282
283 final Point2S a = Point2S.of(1.0, 2.0);
284 final Point2S b = Point2S.of(1.0, 3.0);
285 final Point2S c = Point2S.of(4.0, 2.0);
286 final Point2S d = Point2S.of(1.0, 2.0);
287
288
289 final int hash = a.hashCode();
290
291
292 Assertions.assertEquals(hash, a.hashCode());
293
294 Assertions.assertNotEquals(hash, b.hashCode());
295 Assertions.assertNotEquals(hash, c.hashCode());
296
297 Assertions.assertEquals(hash, d.hashCode());
298 }
299
300 @Test
301 void testEquals() {
302
303 final Point2S a = Point2S.of(1.0, 2.0);
304 final Point2S b = Point2S.of(1.0, 3.0);
305 final Point2S c = Point2S.of(4.0, 2.0);
306 final Point2S d = Point2S.of(1.0, 2.0);
307
308
309 GeometryTestUtils.assertSimpleEqualsCases(a);
310
311 Assertions.assertNotEquals(a, b);
312 Assertions.assertNotEquals(a, c);
313
314 Assertions.assertEquals(a, d);
315 Assertions.assertEquals(d, a);
316 }
317
318 @Test
319 void testEquals_poles() {
320
321 final Point2S a = Point2S.of(1.0, 0.0);
322 final Point2S b = Point2S.of(0.0, 0.0);
323 final Point2S c = Point2S.of(1.0, 0.0);
324
325 final Point2S d = Point2S.of(-1.0, Math.PI);
326 final Point2S e = Point2S.of(0.0, Math.PI);
327 final Point2S f = Point2S.of(-1.0, Math.PI);
328
329
330 Assertions.assertEquals(a, a);
331 Assertions.assertNotEquals(a, b);
332 Assertions.assertEquals(a, c);
333
334 Assertions.assertEquals(d, d);
335 Assertions.assertNotEquals(d, e);
336 Assertions.assertEquals(d, f);
337 }
338
339 @Test
340 void testToString() {
341
342 Assertions.assertEquals("(0.0, 0.0)", Point2S.of(0.0, 0.0).toString());
343 Assertions.assertEquals("(1.0, 2.0)", Point2S.of(1.0, 2.0).toString());
344 }
345
346 @Test
347 void testParse() {
348
349 checkPoint(Point2S.parse("(0,0)"), 0.0, 0.0);
350 checkPoint(Point2S.parse("(1,2)"), 1.0, 2.0);
351 }
352
353 @Test
354 void testParse_failure() {
355
356 Assertions.assertThrows(IllegalArgumentException.class, () -> Point2S.parse("abc"));
357 }
358
359 private static void checkPoint(final Point2S p, final double az, final double polar) {
360 final String msg = "Expected (" + az + "," + polar + ") but was " + p;
361
362 Assertions.assertEquals(az, p.getAzimuth(), TEST_EPS, msg);
363 Assertions.assertEquals(polar, p.getPolar(), TEST_EPS, msg);
364 }
365 }