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