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 import java.util.regex.Pattern;
20
21 import org.apache.commons.geometry.core.GeometryTestUtils;
22 import org.apache.commons.geometry.core.partitioning.HyperplaneLocation;
23 import org.apache.commons.geometry.euclidean.threed.Vector3D;
24 import org.apache.commons.geometry.spherical.SphericalTestUtils;
25 import org.apache.commons.geometry.spherical.oned.AngularInterval;
26 import org.apache.commons.geometry.spherical.oned.Point1S;
27 import org.apache.commons.numbers.angle.Angle;
28 import org.apache.commons.numbers.core.Precision;
29 import org.junit.jupiter.api.Assertions;
30 import org.junit.jupiter.api.Test;
31
32 class GreatCircleTest {
33
34 private static final double TEST_EPS = 1e-10;
35
36 private static final Precision.DoubleEquivalence TEST_PRECISION =
37 Precision.doubleEquivalenceOfEpsilon(TEST_EPS);
38
39 private static final Vector3D.Unit X = Vector3D.Unit.PLUS_X;
40 private static final Vector3D.Unit Y = Vector3D.Unit.PLUS_Y;
41 private static final Vector3D.Unit Z = Vector3D.Unit.PLUS_Z;
42
43 @Test
44 void testFromPole() {
45
46 checkGreatCircle(GreatCircles.fromPole(X, TEST_PRECISION), X, Z);
47 checkGreatCircle(GreatCircles.fromPole(Y, TEST_PRECISION), Y, Z.negate());
48 checkGreatCircle(GreatCircles.fromPole(Z, TEST_PRECISION), Z, Y);
49 }
50
51 @Test
52 void testFromPoleAndXAxis() {
53
54 checkGreatCircle(GreatCircles.fromPoleAndU(X, Y, TEST_PRECISION), X, Y);
55 checkGreatCircle(GreatCircles.fromPoleAndU(X, Z, TEST_PRECISION), X, Z);
56 checkGreatCircle(GreatCircles.fromPoleAndU(Y, Z, TEST_PRECISION), Y, Z);
57 }
58
59 @Test
60 void testFromPoints() {
61
62 checkGreatCircle(GreatCircles.fromPoints(
63 Point2S.of(0, Angle.PI_OVER_TWO),
64 Point2S.of(Angle.PI_OVER_TWO, Angle.PI_OVER_TWO),
65 TEST_PRECISION),
66 Z, X);
67
68 checkGreatCircle(GreatCircles.fromPoints(
69 Point2S.of(0, Angle.PI_OVER_TWO),
70 Point2S.of(-0.1 * Math.PI, Angle.PI_OVER_TWO),
71 TEST_PRECISION),
72 Z.negate(), X);
73
74 checkGreatCircle(GreatCircles.fromPoints(
75 Point2S.of(0, Angle.PI_OVER_TWO),
76 Point2S.of(1.5 * Math.PI, Angle.PI_OVER_TWO),
77 TEST_PRECISION),
78 Z.negate(), X);
79
80 checkGreatCircle(GreatCircles.fromPoints(
81 Point2S.of(0, 0),
82 Point2S.of(0, Angle.PI_OVER_TWO),
83 TEST_PRECISION),
84 Y, Z);
85 }
86
87 @Test
88 void testFromPoints_invalidPoints() {
89
90 final Point2S p1 = Point2S.of(0, Angle.PI_OVER_TWO);
91 final Point2S p2 = Point2S.of(Math.PI, Angle.PI_OVER_TWO);
92
93
94 GeometryTestUtils.assertThrowsWithMessage(() -> {
95 GreatCircles.fromPoints(p1, p1, TEST_PRECISION);
96 }, IllegalArgumentException.class, Pattern.compile("^.*points are equal$"));
97
98 GeometryTestUtils.assertThrowsWithMessage(() -> {
99 GreatCircles.fromPoints(p1, Point2S.of(1e-12, Angle.PI_OVER_TWO), TEST_PRECISION);
100 }, IllegalArgumentException.class, Pattern.compile("^.*points are equal$"));
101
102 GeometryTestUtils.assertThrowsWithMessage(() -> {
103 GreatCircles.fromPoints(
104 Point2S.from(Vector3D.Unit.PLUS_X),
105 Point2S.from(Vector3D.Unit.MINUS_X),
106 TEST_PRECISION);
107 }, IllegalArgumentException.class, Pattern.compile("^.*points are antipodal$"));
108
109 Assertions.assertThrows(IllegalArgumentException.class, () -> GreatCircles.fromPoints(p1, Point2S.NaN, TEST_PRECISION));
110 Assertions.assertThrows(IllegalArgumentException.class, () -> GreatCircles.fromPoints(Point2S.NaN, p2, TEST_PRECISION));
111 Assertions.assertThrows(IllegalArgumentException.class, () -> GreatCircles.fromPoints(p1, Point2S.of(Double.POSITIVE_INFINITY, Angle.PI_OVER_TWO), TEST_PRECISION));
112 Assertions.assertThrows(IllegalArgumentException.class, () -> GreatCircles.fromPoints(Point2S.of(Double.POSITIVE_INFINITY, Angle.PI_OVER_TWO), p2, TEST_PRECISION));
113 }
114
115 @Test
116 void testOffset_point() {
117
118 final GreatCircle circle = GreatCircles.fromPoleAndU(
119 Vector3D.Unit.MINUS_X, Vector3D.Unit.PLUS_Z, TEST_PRECISION);
120
121
122
123
124 for (double polar = -Angle.PI_OVER_TWO; polar <= Angle.PI_OVER_TWO; polar += 0.1) {
125 Assertions.assertEquals(0, circle.offset(Point2S.of(Angle.PI_OVER_TWO, polar)), TEST_EPS);
126 Assertions.assertEquals(0, circle.offset(Point2S.of(-Angle.PI_OVER_TWO, polar)), TEST_EPS);
127 }
128
129
130 Assertions.assertEquals(-1, circle.offset(Point2S.of(Angle.PI_OVER_TWO + 1, Angle.PI_OVER_TWO)), TEST_EPS);
131 Assertions.assertEquals(1, circle.offset(Point2S.of(-Angle.PI_OVER_TWO + 1, Angle.PI_OVER_TWO)), TEST_EPS);
132
133
134 Assertions.assertEquals(-Angle.PI_OVER_TWO, circle.offset(Point2S.of(Math.PI, Angle.PI_OVER_TWO)), TEST_EPS);
135 Assertions.assertEquals(Angle.PI_OVER_TWO, circle.offset(Point2S.of(0.0, Angle.PI_OVER_TWO)), TEST_EPS);
136 }
137
138 @Test
139 void testOffset_vector() {
140
141 final GreatCircle circle = GreatCircles.fromPoleAndU(
142 Vector3D.Unit.MINUS_X, Vector3D.Unit.PLUS_Z, TEST_PRECISION);
143
144
145
146
147 Assertions.assertEquals(0, circle.offset(Vector3D.of(0, 1, 0)), TEST_EPS);
148 Assertions.assertEquals(0, circle.offset(Vector3D.of(0, 0, 1)), TEST_EPS);
149 Assertions.assertEquals(0, circle.offset(Vector3D.of(0, -1, 0)), TEST_EPS);
150 Assertions.assertEquals(0, circle.offset(Vector3D.of(0, 0, -1)), TEST_EPS);
151
152
153 Assertions.assertEquals(-0.25 * Math.PI, circle.offset(Vector3D.of(-1, 1, 0)), TEST_EPS);
154 Assertions.assertEquals(-0.25 * Math.PI, circle.offset(Vector3D.of(-1, 0, 1)), TEST_EPS);
155 Assertions.assertEquals(-0.25 * Math.PI, circle.offset(Vector3D.of(-1, -1, 0)), TEST_EPS);
156 Assertions.assertEquals(-0.25 * Math.PI, circle.offset(Vector3D.of(-1, 0, -1)), TEST_EPS);
157
158 Assertions.assertEquals(0.25 * Math.PI, circle.offset(Vector3D.of(1, 1, 0)), TEST_EPS);
159 Assertions.assertEquals(0.25 * Math.PI, circle.offset(Vector3D.of(1, 0, 1)), TEST_EPS);
160 Assertions.assertEquals(0.25 * Math.PI, circle.offset(Vector3D.of(1, -1, 0)), TEST_EPS);
161 Assertions.assertEquals(0.25 * Math.PI, circle.offset(Vector3D.of(1, 0, -1)), TEST_EPS);
162
163
164 Assertions.assertEquals(-Angle.PI_OVER_TWO, circle.offset(Vector3D.Unit.MINUS_X), TEST_EPS);
165 Assertions.assertEquals(Angle.PI_OVER_TWO, circle.offset(Vector3D.Unit.PLUS_X), TEST_EPS);
166 }
167
168 @Test
169 void testAzimuth_point() {
170
171 final GreatCircle circle = GreatCircles.fromPoleAndU(
172 Vector3D.Unit.MINUS_X, Vector3D.Unit.PLUS_Z, TEST_PRECISION);
173
174
175
176
177 Assertions.assertEquals(Angle.PI_OVER_TWO, circle.azimuth(Point2S.from(Vector3D.of(0, 1, 0))), TEST_EPS);
178 Assertions.assertEquals(0.0, circle.azimuth(Point2S.from(Vector3D.of(0, 0, 1))), TEST_EPS);
179 Assertions.assertEquals(1.5 * Math.PI, circle.azimuth(Point2S.from(Vector3D.of(0, -1, 0))), TEST_EPS);
180 Assertions.assertEquals(Math.PI, circle.azimuth(Point2S.from(Vector3D.of(0, 0, -1))), TEST_EPS);
181
182
183 Assertions.assertEquals(Angle.PI_OVER_TWO, circle.azimuth(Point2S.from(Vector3D.of(-1, 1, 0))), TEST_EPS);
184 Assertions.assertEquals(0.0, circle.azimuth(Point2S.from(Vector3D.of(-1, 0, 1))), TEST_EPS);
185 Assertions.assertEquals(1.5 * Math.PI, circle.azimuth(Point2S.from(Vector3D.of(-1, -1, 0))), TEST_EPS);
186 Assertions.assertEquals(Math.PI, circle.azimuth(Point2S.from(Vector3D.of(-1, 0, -1))), TEST_EPS);
187
188 Assertions.assertEquals(Angle.PI_OVER_TWO, circle.azimuth(Point2S.from(Vector3D.of(1, 1, 0))), TEST_EPS);
189 Assertions.assertEquals(0.0, circle.azimuth(Point2S.from(Vector3D.of(1, 0, 1))), TEST_EPS);
190 Assertions.assertEquals(1.5 * Math.PI, circle.azimuth(Point2S.from(Vector3D.of(1, -1, 0))), TEST_EPS);
191 Assertions.assertEquals(Math.PI, circle.azimuth(Point2S.from(Vector3D.of(1, 0, -1))), TEST_EPS);
192
193
194 Assertions.assertEquals(0, circle.azimuth(Point2S.from(Vector3D.Unit.MINUS_X)), TEST_EPS);
195 Assertions.assertEquals(0, circle.azimuth(Point2S.from(Vector3D.Unit.PLUS_X)), TEST_EPS);
196 }
197
198 @Test
199 void testAzimuth_vector() {
200
201 final GreatCircle circle = GreatCircles.fromPoleAndU(
202 Vector3D.Unit.MINUS_X, Vector3D.Unit.PLUS_Z, TEST_PRECISION);
203
204
205
206
207 Assertions.assertEquals(Angle.PI_OVER_TWO, circle.azimuth(Vector3D.of(0, 1, 0)), TEST_EPS);
208 Assertions.assertEquals(0.0, circle.azimuth(Vector3D.of(0, 0, 1)), TEST_EPS);
209 Assertions.assertEquals(1.5 * Math.PI, circle.azimuth(Vector3D.of(0, -1, 0)), TEST_EPS);
210 Assertions.assertEquals(Math.PI, circle.azimuth(Vector3D.of(0, 0, -1)), TEST_EPS);
211
212
213 Assertions.assertEquals(Angle.PI_OVER_TWO, circle.azimuth(Vector3D.of(-1, 1, 0)), TEST_EPS);
214 Assertions.assertEquals(0.0, circle.azimuth(Vector3D.of(-1, 0, 1)), TEST_EPS);
215 Assertions.assertEquals(1.5 * Math.PI, circle.azimuth(Vector3D.of(-1, -1, 0)), TEST_EPS);
216 Assertions.assertEquals(Math.PI, circle.azimuth(Vector3D.of(-1, 0, -1)), TEST_EPS);
217
218 Assertions.assertEquals(Angle.PI_OVER_TWO, circle.azimuth(Vector3D.of(1, 1, 0)), TEST_EPS);
219 Assertions.assertEquals(0.0, circle.azimuth(Vector3D.of(1, 0, 1)), TEST_EPS);
220 Assertions.assertEquals(1.5 * Math.PI, circle.azimuth(Vector3D.of(1, -1, 0)), TEST_EPS);
221 Assertions.assertEquals(Math.PI, circle.azimuth(Vector3D.of(1, 0, -1)), TEST_EPS);
222
223
224 Assertions.assertEquals(0, circle.azimuth(Vector3D.Unit.MINUS_X), TEST_EPS);
225 Assertions.assertEquals(0, circle.azimuth(Vector3D.Unit.PLUS_X), TEST_EPS);
226 }
227
228 @Test
229 void testVectorAt() {
230
231 final GreatCircle circle = GreatCircles.fromPoleAndU(
232 Vector3D.Unit.MINUS_X, Vector3D.Unit.PLUS_Z, TEST_PRECISION);
233
234
235 SphericalTestUtils.assertVectorsEqual(Vector3D.Unit.PLUS_Z, circle.vectorAt(0.0), TEST_EPS);
236 SphericalTestUtils.assertVectorsEqual(Vector3D.Unit.PLUS_Y, circle.vectorAt(Angle.PI_OVER_TWO), TEST_EPS);
237 SphericalTestUtils.assertVectorsEqual(Vector3D.Unit.MINUS_Z, circle.vectorAt(Math.PI), TEST_EPS);
238 SphericalTestUtils.assertVectorsEqual(Vector3D.Unit.MINUS_Y, circle.vectorAt(-Angle.PI_OVER_TWO), TEST_EPS);
239 SphericalTestUtils.assertVectorsEqual(Vector3D.Unit.PLUS_Z, circle.vectorAt(Angle.TWO_PI), TEST_EPS);
240 }
241
242 @Test
243 void testProject() {
244
245 final GreatCircle circle = GreatCircles.fromPoleAndU(
246 Vector3D.Unit.MINUS_X, Vector3D.Unit.PLUS_Z, TEST_PRECISION);
247
248
249 SphericalTestUtils.assertPointsEqual(Point2S.of(Angle.PI_OVER_TWO, Angle.PI_OVER_TWO),
250 circle.project(Point2S.of(Angle.PI_OVER_TWO, Angle.PI_OVER_TWO)), TEST_EPS);
251 SphericalTestUtils.assertPointsEqual(Point2S.of(Angle.PI_OVER_TWO, Angle.PI_OVER_TWO),
252 circle.project(Point2S.of(Angle.PI_OVER_TWO + 1, Angle.PI_OVER_TWO)), TEST_EPS);
253 SphericalTestUtils.assertPointsEqual(Point2S.of(Angle.PI_OVER_TWO, Angle.PI_OVER_TWO),
254 circle.project(Point2S.of(Angle.PI_OVER_TWO - 1, Angle.PI_OVER_TWO)), TEST_EPS);
255
256 SphericalTestUtils.assertPointsEqual(Point2S.of(-Angle.PI_OVER_TWO, Angle.PI_OVER_TWO),
257 circle.project(Point2S.of(-Angle.PI_OVER_TWO, Angle.PI_OVER_TWO)), TEST_EPS);
258 SphericalTestUtils.assertPointsEqual(Point2S.of(-Angle.PI_OVER_TWO, Angle.PI_OVER_TWO),
259 circle.project(Point2S.of(-Angle.PI_OVER_TWO + 1, Angle.PI_OVER_TWO)), TEST_EPS);
260 SphericalTestUtils.assertPointsEqual(Point2S.of(-Angle.PI_OVER_TWO, Angle.PI_OVER_TWO),
261 circle.project(Point2S.of(-Angle.PI_OVER_TWO - 1, Angle.PI_OVER_TWO)), TEST_EPS);
262 }
263
264 @Test
265 void testProject_poles() {
266
267 final GreatCircle minusXCircle = GreatCircles.fromPoleAndU(
268 Vector3D.Unit.MINUS_X, Vector3D.Unit.PLUS_Z, TEST_PRECISION);
269 final GreatCircle plusZCircle = GreatCircles.fromPoleAndU(
270 Vector3D.Unit.PLUS_Z, Vector3D.Unit.MINUS_Y, TEST_PRECISION);
271
272
273 SphericalTestUtils.assertPointsEqual(Point2S.of(0.0, 0.0),
274 minusXCircle.project(Point2S.from(Vector3D.Unit.MINUS_X)), TEST_EPS);
275 SphericalTestUtils.assertPointsEqual(Point2S.of(0.0, 0.0),
276 minusXCircle.project(Point2S.from(Vector3D.Unit.PLUS_X)), TEST_EPS);
277
278 SphericalTestUtils.assertPointsEqual(Point2S.of(1.5 * Math.PI, Angle.PI_OVER_TWO),
279 plusZCircle.project(Point2S.from(Vector3D.Unit.PLUS_Z)), TEST_EPS);
280 SphericalTestUtils.assertPointsEqual(Point2S.of(1.5 * Math.PI, Angle.PI_OVER_TWO),
281 plusZCircle.project(Point2S.from(Vector3D.Unit.MINUS_Z)), TEST_EPS);
282 }
283
284 @Test
285 void testReverse() {
286
287 final GreatCircle circle = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X, TEST_PRECISION);
288
289
290 final GreatCircle reverse = circle.reverse();
291
292
293 checkGreatCircle(reverse, Vector3D.Unit.MINUS_Z, Vector3D.Unit.PLUS_X);
294 }
295
296 @Test
297 void testTransform_rotateAroundPole() {
298
299 final GreatCircle circle = GreatCircles.fromPoints(
300 Point2S.of(0, Angle.PI_OVER_TWO),
301 Point2S.of(1, Angle.PI_OVER_TWO),
302 TEST_PRECISION);
303
304 final Transform2S t = Transform2S.createRotation(circle.getPolePoint(), 0.25 * Math.PI);
305
306
307 final GreatCircle result = circle.transform(t);
308
309
310 Assertions.assertNotSame(circle, result);
311 checkGreatCircle(result, Vector3D.Unit.PLUS_Z, Vector3D.Unit.from(1, 1, 0));
312 }
313
314 @Test
315 void testTransform_rotateAroundNonPole() {
316
317 final GreatCircle circle = GreatCircles.fromPoints(
318 Point2S.of(0, Angle.PI_OVER_TWO),
319 Point2S.of(1, Angle.PI_OVER_TWO),
320 TEST_PRECISION);
321
322 final Transform2S t = Transform2S.createRotation(Point2S.of(0, Angle.PI_OVER_TWO), Angle.PI_OVER_TWO);
323
324
325 final GreatCircle result = circle.transform(t);
326
327
328 Assertions.assertNotSame(circle, result);
329 checkGreatCircle(result, Vector3D.Unit.MINUS_Y, Vector3D.Unit.PLUS_X);
330 }
331
332 @Test
333 void testTransform_piMinusAzimuth() {
334
335 final GreatCircle circle = GreatCircles.fromPoints(
336 Point2S.of(0, Angle.PI_OVER_TWO),
337 Point2S.of(1, Angle.PI_OVER_TWO),
338 TEST_PRECISION);
339
340 final Transform2S t = Transform2S.createReflection(Point2S.PLUS_J)
341 .rotate(Point2S.PLUS_K, Math.PI);
342
343
344 final GreatCircle result = circle.transform(t);
345
346
347 Assertions.assertNotSame(circle, result);
348 checkGreatCircle(result, Vector3D.Unit.MINUS_Z, Vector3D.Unit.MINUS_X);
349 }
350
351 @Test
352 void testSimilarOrientation() {
353
354 final GreatCircle a = GreatCircles.fromPole(Vector3D.Unit.PLUS_Z, TEST_PRECISION);
355 final GreatCircle b = GreatCircles.fromPole(Vector3D.Unit.PLUS_X, TEST_PRECISION);
356 final GreatCircle c = GreatCircles.fromPole(Vector3D.Unit.MINUS_Z, TEST_PRECISION);
357 final GreatCircle d = GreatCircles.fromPole(Vector3D.Unit.from(1, 1, -1), TEST_PRECISION);
358 final GreatCircle e = GreatCircles.fromPole(Vector3D.Unit.from(1, 1, 1), TEST_PRECISION);
359
360
361 Assertions.assertTrue(a.similarOrientation(a));
362
363 Assertions.assertFalse(a.similarOrientation(b));
364 Assertions.assertFalse(a.similarOrientation(c));
365 Assertions.assertFalse(a.similarOrientation(d));
366
367 Assertions.assertTrue(a.similarOrientation(e));
368 }
369
370 @Test
371 void testSpan() {
372
373 final GreatCircle circle = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_X, Vector3D.Unit.PLUS_Z, TEST_PRECISION);
374
375
376 final GreatArc span = circle.span();
377
378
379 Assertions.assertSame(circle, span.getCircle());
380 Assertions.assertTrue(span.getInterval().isFull());
381
382 Assertions.assertNull(span.getStartPoint());
383 Assertions.assertNull(span.getEndPoint());
384 }
385
386 @Test
387 void testArc_points_2s() {
388
389 final GreatCircle circle = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_X, Vector3D.Unit.PLUS_Z, TEST_PRECISION);
390
391
392 checkArc(circle.arc(Point2S.of(1, Angle.PI_OVER_TWO), Point2S.of(0, 1)),
393 Point2S.of(Angle.PI_OVER_TWO, Angle.PI_OVER_TWO), Point2S.of(0, 0));
394
395 Assertions.assertTrue(circle.arc(Point2S.PLUS_I, Point2S.PLUS_I).isFull());
396 }
397
398 @Test
399 void testArc_points_1s() {
400
401 final GreatCircle circle = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_X, Vector3D.Unit.PLUS_Z, TEST_PRECISION);
402
403
404 checkArc(circle.arc(Point1S.of(Math.PI), Point1S.of(1.5 * Math.PI)),
405 Point2S.of(0, Math.PI), Point2S.of(Angle.PI_OVER_TWO, Angle.PI_OVER_TWO));
406
407 Assertions.assertTrue(circle.arc(Point1S.of(1), Point1S.of(1)).isFull());
408 }
409
410 @Test
411 void testArc_azimuths() {
412
413 final GreatCircle circle = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_X, Vector3D.Unit.PLUS_Z, TEST_PRECISION);
414
415
416 checkArc(circle.arc(Math.PI, 1.5 * Math.PI),
417 Point2S.of(0, Math.PI), Point2S.of(Angle.PI_OVER_TWO, Angle.PI_OVER_TWO));
418
419 Assertions.assertTrue(circle.arc(1, 1).isFull());
420 }
421
422 @Test
423 void testArc_interval() {
424
425 final GreatCircle circle = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_X, Vector3D.Unit.PLUS_Z, TEST_PRECISION);
426 final AngularInterval.Convex interval = AngularInterval.Convex.of(1, 2, TEST_PRECISION);
427
428
429 final GreatArc arc = circle.arc(interval);
430
431
432 Assertions.assertSame(circle, arc.getCircle());
433 Assertions.assertSame(interval, arc.getInterval());
434 }
435
436 @Test
437 void testIntersection_parallel() {
438
439 final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-3);
440
441 final GreatCircle a = GreatCircles.fromPole(Vector3D.Unit.PLUS_X, precision);
442 final GreatCircle b = GreatCircles.fromPole(Vector3D.Unit.PLUS_X, precision);
443 final GreatCircle c = GreatCircles.fromPole(Vector3D.Unit.of(1, 1e-4, 1e-4), precision);
444 final GreatCircle d = GreatCircles.fromPole(Vector3D.Unit.MINUS_X, precision);
445 final GreatCircle e = GreatCircles.fromPole(Vector3D.Unit.of(-1, 1e-4, 1e-4), precision);
446
447
448 Assertions.assertNull(a.intersection(b));
449 Assertions.assertNull(a.intersection(c));
450 Assertions.assertNull(a.intersection(d));
451 Assertions.assertNull(a.intersection(e));
452 }
453
454 @Test
455 void testIntersection() {
456
457 final GreatCircle a = GreatCircles.fromPole(Vector3D.Unit.PLUS_X, TEST_PRECISION);
458 final GreatCircle b = GreatCircles.fromPole(Vector3D.Unit.PLUS_Y, TEST_PRECISION);
459 final GreatCircle c = GreatCircles.fromPole(Vector3D.Unit.PLUS_Z, TEST_PRECISION);
460
461
462 SphericalTestUtils.assertVectorsEqual(Vector3D.Unit.PLUS_Z,
463 a.intersection(b).getVector(), TEST_EPS);
464 SphericalTestUtils.assertVectorsEqual(Vector3D.Unit.MINUS_Z,
465 b.intersection(a).getVector(), TEST_EPS);
466
467 SphericalTestUtils.assertVectorsEqual(Vector3D.Unit.PLUS_X,
468 b.intersection(c).getVector(), TEST_EPS);
469 SphericalTestUtils.assertVectorsEqual(Vector3D.Unit.MINUS_X,
470 c.intersection(b).getVector(), TEST_EPS);
471 }
472
473 @Test
474 void testAngle_withoutReferencePoint() {
475
476 final GreatCircle a = GreatCircles.fromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION);
477 final GreatCircle b = GreatCircles.fromPoints(Point2S.PLUS_J, Point2S.PLUS_I, TEST_PRECISION);
478 final GreatCircle c = GreatCircles.fromPoints(Point2S.PLUS_I, Point2S.PLUS_K, TEST_PRECISION);
479 final GreatCircle d = GreatCircles.fromPoints(Point2S.PLUS_J, Point2S.PLUS_K, TEST_PRECISION);
480 final GreatCircle e = GreatCircles.fromPoleAndU(
481 Vector3D.Unit.of(1, 0, 1),
482 Vector3D.Unit.PLUS_Y,
483 TEST_PRECISION);
484
485 final GreatCircle f = GreatCircles.fromPoleAndU(
486 Vector3D.Unit.of(1, 0, -1),
487 Vector3D.Unit.PLUS_Y,
488 TEST_PRECISION);
489
490
491 Assertions.assertEquals(0, a.angle(a), TEST_EPS);
492 Assertions.assertEquals(Math.PI, a.angle(b), TEST_EPS);
493
494 Assertions.assertEquals(Angle.PI_OVER_TWO, a.angle(c), TEST_EPS);
495 Assertions.assertEquals(Angle.PI_OVER_TWO, c.angle(a), TEST_EPS);
496
497 Assertions.assertEquals(Angle.PI_OVER_TWO, a.angle(d), TEST_EPS);
498 Assertions.assertEquals(Angle.PI_OVER_TWO, d.angle(a), TEST_EPS);
499
500 Assertions.assertEquals(0.25 * Math.PI, a.angle(e), TEST_EPS);
501 Assertions.assertEquals(0.25 * Math.PI, e.angle(a), TEST_EPS);
502
503 Assertions.assertEquals(0.75 * Math.PI, a.angle(f), TEST_EPS);
504 Assertions.assertEquals(0.75 * Math.PI, f.angle(a), TEST_EPS);
505 }
506
507 @Test
508 void testAngle_withReferencePoint() {
509
510 final GreatCircle a = GreatCircles.fromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION);
511 final GreatCircle b = GreatCircles.fromPoints(Point2S.PLUS_J, Point2S.PLUS_I, TEST_PRECISION);
512 final GreatCircle c = GreatCircles.fromPoints(Point2S.PLUS_I, Point2S.PLUS_K, TEST_PRECISION);
513 final GreatCircle d = GreatCircles.fromPoints(Point2S.PLUS_J, Point2S.PLUS_K, TEST_PRECISION);
514 final GreatCircle e = GreatCircles.fromPoleAndU(
515 Vector3D.Unit.of(1, 0, 1),
516 Vector3D.Unit.PLUS_Y,
517 TEST_PRECISION);
518
519 final GreatCircle f = GreatCircles.fromPoleAndU(
520 Vector3D.Unit.of(1, 0, -1),
521 Vector3D.Unit.PLUS_Y,
522 TEST_PRECISION);
523
524
525 Assertions.assertEquals(0, a.angle(a, Point2S.PLUS_J), TEST_EPS);
526 Assertions.assertEquals(0, a.angle(a, Point2S.MINUS_J), TEST_EPS);
527
528 Assertions.assertEquals(-Math.PI, a.angle(b, Point2S.PLUS_J), TEST_EPS);
529 Assertions.assertEquals(-Math.PI, a.angle(b, Point2S.MINUS_J), TEST_EPS);
530
531 Assertions.assertEquals(Angle.PI_OVER_TWO, a.angle(c, Point2S.PLUS_I), TEST_EPS);
532 Assertions.assertEquals(-Angle.PI_OVER_TWO, a.angle(c, Point2S.MINUS_I), TEST_EPS);
533
534 Assertions.assertEquals(-Angle.PI_OVER_TWO, c.angle(a, Point2S.PLUS_I), TEST_EPS);
535 Assertions.assertEquals(Angle.PI_OVER_TWO, c.angle(a, Point2S.MINUS_I), TEST_EPS);
536
537 Assertions.assertEquals(Angle.PI_OVER_TWO, a.angle(d, Point2S.PLUS_J), TEST_EPS);
538 Assertions.assertEquals(-Angle.PI_OVER_TWO, a.angle(d, Point2S.MINUS_J), TEST_EPS);
539
540 Assertions.assertEquals(-Angle.PI_OVER_TWO, d.angle(a, Point2S.PLUS_J), TEST_EPS);
541 Assertions.assertEquals(Angle.PI_OVER_TWO, d.angle(a, Point2S.MINUS_J), TEST_EPS);
542
543 Assertions.assertEquals(0.25 * Math.PI, a.angle(e, Point2S.PLUS_J), TEST_EPS);
544 Assertions.assertEquals(-0.25 * Math.PI, a.angle(e, Point2S.MINUS_J), TEST_EPS);
545
546 Assertions.assertEquals(-0.25 * Math.PI, e.angle(a, Point2S.PLUS_J), TEST_EPS);
547 Assertions.assertEquals(0.25 * Math.PI, e.angle(a, Point2S.MINUS_J), TEST_EPS);
548
549 Assertions.assertEquals(0.75 * Math.PI, a.angle(f, Point2S.PLUS_J), TEST_EPS);
550 Assertions.assertEquals(-0.75 * Math.PI, a.angle(f, Point2S.MINUS_J), TEST_EPS);
551
552 Assertions.assertEquals(-0.75 * Math.PI, f.angle(a, Point2S.PLUS_J), TEST_EPS);
553 Assertions.assertEquals(0.75 * Math.PI, f.angle(a, Point2S.MINUS_J), TEST_EPS);
554 }
555
556 @Test
557 void testAngle_withReferencePoint_pointEquidistanceFromIntersections() {
558
559 final GreatCircle a = GreatCircles.fromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION);
560 final GreatCircle b = GreatCircles.fromPoleAndU(
561 Vector3D.Unit.of(1, 0, 1),
562 Vector3D.Unit.PLUS_Y,
563 TEST_PRECISION);
564
565
566 Assertions.assertEquals(-0.25 * Math.PI, a.angle(b, Point2S.PLUS_I), TEST_EPS);
567 Assertions.assertEquals(-0.25 * Math.PI, a.angle(b, Point2S.MINUS_I), TEST_EPS);
568 }
569
570 @Test
571 void testToSubspace() {
572
573 final GreatCircle circle = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Y, Vector3D.Unit.MINUS_Z, TEST_PRECISION);
574
575
576 SphericalTestUtils.assertPointsEqual(Point1S.ZERO,
577 circle.toSubspace(Point2S.from(Vector3D.Unit.MINUS_Z)), TEST_EPS);
578
579 SphericalTestUtils.assertPointsEqual(Point1S.of(0.25 * Math.PI),
580 circle.toSubspace(Point2S.from(Vector3D.of(-1, -1, -1))), TEST_EPS);
581 SphericalTestUtils.assertPointsEqual(Point1S.of(0.75 * Math.PI),
582 circle.toSubspace(Point2S.from(Vector3D.of(-1, 1, 1))), TEST_EPS);
583 SphericalTestUtils.assertPointsEqual(Point1S.of(1.25 * Math.PI),
584 circle.toSubspace(Point2S.from(Vector3D.of(1, -1, 1))), TEST_EPS);
585 SphericalTestUtils.assertPointsEqual(Point1S.of(1.75 * Math.PI),
586 circle.toSubspace(Point2S.from(Vector3D.of(1, 1, -1))), TEST_EPS);
587
588 SphericalTestUtils.assertPointsEqual(Point1S.ZERO,
589 circle.toSubspace(Point2S.from(Vector3D.Unit.PLUS_Y)), TEST_EPS);
590 SphericalTestUtils.assertPointsEqual(Point1S.ZERO,
591 circle.toSubspace(Point2S.from(Vector3D.Unit.MINUS_Y)), TEST_EPS);
592 }
593
594 @Test
595 void testToSpace() {
596
597 final GreatCircle circle = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Y, Vector3D.Unit.MINUS_Z, TEST_PRECISION);
598
599
600 SphericalTestUtils.assertPointsEqual(Point2S.from(Vector3D.Unit.MINUS_Z),
601 circle.toSpace(Point1S.ZERO), TEST_EPS);
602
603 SphericalTestUtils.assertPointsEqual(Point2S.from(Vector3D.of(-1, 0, -1)),
604 circle.toSpace(Point1S.of(0.25 * Math.PI)), TEST_EPS);
605 SphericalTestUtils.assertPointsEqual(Point2S.from(Vector3D.of(-1, 0, 1)),
606 circle.toSpace(Point1S.of(0.75 * Math.PI)), TEST_EPS);
607 SphericalTestUtils.assertPointsEqual(Point2S.from(Vector3D.of(1, 0, 1)),
608 circle.toSpace(Point1S.of(1.25 * Math.PI)), TEST_EPS);
609 SphericalTestUtils.assertPointsEqual(Point2S.from(Vector3D.of(1, 0, -1)),
610 circle.toSpace(Point1S.of(1.75 * Math.PI)), TEST_EPS);
611 }
612
613 @Test
614 void testEq() {
615
616 final double eps = 1e-3;
617 final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(eps);
618
619 final GreatCircle a = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X, precision);
620
621 final GreatCircle b = GreatCircles.fromPoleAndU(Vector3D.Unit.MINUS_Z, Vector3D.Unit.PLUS_X, precision);
622 final GreatCircle c = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.MINUS_X, precision);
623 final GreatCircle d = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X, TEST_PRECISION);
624
625 final GreatCircle e = GreatCircles.fromPoleAndU(Vector3D.of(1e-6, 0, 1), Vector3D.Unit.PLUS_X, precision);
626 final GreatCircle f = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.of(1, 1e-6, 0), precision);
627 final GreatCircle g = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X,
628 Precision.doubleEquivalenceOfEpsilon(eps));
629
630
631 Assertions.assertTrue(a.eq(a, precision));
632
633 Assertions.assertFalse(a.eq(b, precision));
634 Assertions.assertFalse(a.eq(c, precision));
635
636 Assertions.assertTrue(a.eq(d, precision));
637 Assertions.assertTrue(a.eq(e, precision));
638 Assertions.assertTrue(e.eq(a, precision));
639
640 Assertions.assertTrue(a.eq(f, precision));
641 Assertions.assertTrue(f.eq(a, precision));
642
643 Assertions.assertTrue(g.eq(e, precision));
644 Assertions.assertTrue(e.eq(g, precision));
645 }
646
647 @Test
648 void testHashCode() {
649
650 final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-3);
651
652 final GreatCircle a = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X, TEST_PRECISION);
653
654 final GreatCircle b = GreatCircles.fromPoleAndU(Vector3D.of(0, 1, 1), Vector3D.Unit.PLUS_X, TEST_PRECISION);
655 final GreatCircle c = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.MINUS_X, TEST_PRECISION);
656 final GreatCircle d = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X, precision);
657
658 final GreatCircle e = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X, TEST_PRECISION);
659
660
661 final int hash = a.hashCode();
662
663
664 Assertions.assertEquals(hash, a.hashCode());
665
666 Assertions.assertNotEquals(hash, b.hashCode());
667 Assertions.assertNotEquals(hash, c.hashCode());
668 Assertions.assertNotEquals(hash, d.hashCode());
669
670 Assertions.assertEquals(hash, e.hashCode());
671 }
672
673 @Test
674 void testEquals() {
675
676 final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-3);
677
678 final GreatCircle a = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X, TEST_PRECISION);
679
680 final GreatCircle b = GreatCircles.fromPoleAndU(Vector3D.Unit.MINUS_Z, Vector3D.Unit.PLUS_X, TEST_PRECISION);
681 final GreatCircle c = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.MINUS_X, TEST_PRECISION);
682 final GreatCircle d = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X, precision);
683
684 final GreatCircle e = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X, TEST_PRECISION);
685
686
687 GeometryTestUtils.assertSimpleEqualsCases(a);
688
689 Assertions.assertNotEquals(a, b);
690 Assertions.assertNotEquals(a, c);
691 Assertions.assertNotEquals(a, d);
692
693 Assertions.assertEquals(a, e);
694 Assertions.assertEquals(e, a);
695 }
696
697 @Test
698 void testToString() {
699
700 final GreatCircle circle = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X, TEST_PRECISION);
701
702
703 final String str = circle.toString();
704
705
706 GeometryTestUtils.assertContains("GreatCircle[", str);
707 GeometryTestUtils.assertContains("pole= (0.0, 0.0, 1.0)", str);
708 GeometryTestUtils.assertContains("u= (1.0, 0.0, 0.0)", str);
709 GeometryTestUtils.assertContains("v= (0.0, 1.0, 0.0)", str);
710 }
711
712 private static void checkGreatCircle(final GreatCircle circle, final Vector3D pole, final Vector3D u) {
713 SphericalTestUtils.assertVectorsEqual(pole, circle.getPole(), TEST_EPS);
714 SphericalTestUtils.assertVectorsEqual(pole, circle.getW(), TEST_EPS);
715 SphericalTestUtils.assertVectorsEqual(u, circle.getU(), TEST_EPS);
716 SphericalTestUtils.assertVectorsEqual(pole.cross(u), circle.getV(), TEST_EPS);
717
718 final Point2S plusPolePt = Point2S.from(circle.getPole());
719 final Point2S minusPolePt = Point2S.from(circle.getPole().negate());
720 final Point2S origin = Point2S.from(circle.getU());
721
722 SphericalTestUtils.assertPointsEqual(plusPolePt, circle.getPolePoint(), TEST_EPS);
723
724 Assertions.assertFalse(circle.contains(plusPolePt));
725 Assertions.assertFalse(circle.contains(minusPolePt));
726 Assertions.assertTrue(circle.contains(origin));
727
728 Assertions.assertEquals(HyperplaneLocation.MINUS, circle.classify(plusPolePt));
729 Assertions.assertEquals(HyperplaneLocation.PLUS, circle.classify(minusPolePt));
730 Assertions.assertEquals(HyperplaneLocation.ON, circle.classify(origin));
731 }
732
733 private static void checkArc(final GreatArc arc, final Point2S start, final Point2S end) {
734 SphericalTestUtils.assertPointsEq(start, arc.getStartPoint(), TEST_EPS);
735 SphericalTestUtils.assertPointsEq(end, arc.getEndPoint(), TEST_EPS);
736 }
737 }