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.List;
20
21 import org.apache.commons.geometry.core.GeometryTestUtils;
22 import org.apache.commons.geometry.core.RegionLocation;
23 import org.apache.commons.geometry.core.partitioning.Split;
24 import org.apache.commons.geometry.core.partitioning.SplitLocation;
25 import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
26 import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
27 import org.apache.commons.geometry.euclidean.threed.Vector3D;
28 import org.apache.commons.geometry.spherical.SphericalTestUtils;
29 import org.apache.commons.geometry.spherical.oned.AngularInterval;
30 import org.apache.commons.numbers.angle.PlaneAngleRadians;
31 import org.junit.Assert;
32 import org.junit.Test;
33
34 public class GreatArcTest {
35
36 private static final double TEST_EPS = 1e-10;
37
38 private static final DoublePrecisionContext TEST_PRECISION =
39 new EpsilonDoublePrecisionContext(TEST_EPS);
40
41 @Test
42 public void testFromInterval_full() {
43
44 final GreatArc arc = GreatCircles.arcFromInterval(
45 GreatCircles.fromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION),
46 AngularInterval.full());
47
48
49 Assert.assertTrue(arc.isFull());
50 Assert.assertFalse(arc.isEmpty());
51 Assert.assertTrue(arc.isFinite());
52 Assert.assertFalse(arc.isInfinite());
53
54 Assert.assertNull(arc.getStartPoint());
55 Assert.assertNull(arc.getEndPoint());
56
57 Assert.assertEquals(PlaneAngleRadians.TWO_PI, arc.getSize(), TEST_EPS);
58 Assert.assertNull(arc.getCentroid());
59
60 for (double az = 0; az < PlaneAngleRadians.TWO_PI; az += 0.1) {
61 checkClassify(arc, RegionLocation.INSIDE, Point2S.of(az, PlaneAngleRadians.PI_OVER_TWO));
62 }
63
64 checkClassify(arc, RegionLocation.OUTSIDE,
65 Point2S.PLUS_K, Point2S.of(0, PlaneAngleRadians.PI_OVER_TWO + 0.1),
66 Point2S.MINUS_K, Point2S.of(0, PlaneAngleRadians.PI_OVER_TWO - 0.1));
67 }
68
69 @Test
70 public void testFromInterval_partial() {
71
72 final GreatArc arc = GreatCircles.arcFromInterval(
73 GreatCircles.fromPoints(Point2S.PLUS_J, Point2S.PLUS_K, TEST_PRECISION),
74 AngularInterval.Convex.of(PlaneAngleRadians.PI_OVER_TWO, 1.5 * PlaneAngleRadians.PI, TEST_PRECISION));
75
76
77 Assert.assertFalse(arc.isFull());
78 Assert.assertFalse(arc.isEmpty());
79 Assert.assertTrue(arc.isFinite());
80 Assert.assertFalse(arc.isInfinite());
81
82 checkArc(arc, Point2S.PLUS_K, Point2S.MINUS_K);
83 }
84
85 @Test
86 public void testFromPoints() {
87
88 final Point2S start = Point2S.PLUS_I;
89 final Point2S end = Point2S.MINUS_K;
90
91
92 final GreatArc arc = GreatCircles.arcFromPoints(start, end, TEST_PRECISION);
93
94
95 Assert.assertFalse(arc.isFull());
96 Assert.assertFalse(arc.isEmpty());
97 Assert.assertTrue(arc.isFinite());
98 Assert.assertFalse(arc.isInfinite());
99
100 SphericalTestUtils.assertVectorsEqual(Vector3D.Unit.PLUS_Y, arc.getCircle().getPole(), TEST_EPS);
101
102 checkArc(arc, start, end);
103
104 checkClassify(arc, RegionLocation.INSIDE, Point2S.of(0, 0.75 * PlaneAngleRadians.PI));
105 checkClassify(arc, RegionLocation.BOUNDARY, start, end);
106 checkClassify(arc, RegionLocation.OUTSIDE,
107 Point2S.of(0, 0.25 * PlaneAngleRadians.PI), Point2S.of(PlaneAngleRadians.PI, 0.75 * PlaneAngleRadians.PI),
108 Point2S.of(PlaneAngleRadians.PI, 0.25 * PlaneAngleRadians.PI));
109 }
110
111 @Test
112 public void testFromPoints_almostPi() {
113
114 final Point2S start = Point2S.PLUS_J;
115 final Point2S end = Point2S.of(1.5 * PlaneAngleRadians.PI, PlaneAngleRadians.PI_OVER_TWO - 1e-5);
116
117
118 final GreatArc arc = GreatCircles.arcFromPoints(start, end, TEST_PRECISION);
119
120
121 Assert.assertFalse(arc.isFull());
122 Assert.assertFalse(arc.isEmpty());
123 Assert.assertTrue(arc.isFinite());
124 Assert.assertFalse(arc.isInfinite());
125
126 SphericalTestUtils.assertVectorsEqual(Vector3D.Unit.PLUS_X, arc.getCircle().getPole(), TEST_EPS);
127
128 checkArc(arc, start, end);
129
130 checkClassify(arc, RegionLocation.INSIDE, Point2S.PLUS_K);
131 checkClassify(arc, RegionLocation.BOUNDARY, start, end);
132 checkClassify(arc, RegionLocation.OUTSIDE, Point2S.MINUS_K);
133 }
134
135 @Test
136 public void testFromPoints_usesShortestPath() {
137
138 SphericalTestUtils.assertVectorsEqual(
139 Vector3D.Unit.MINUS_Y,
140 GreatCircles.arcFromPoints(
141 Point2S.PLUS_I,
142 Point2S.of(PlaneAngleRadians.PI, PlaneAngleRadians.PI_OVER_TWO - 1e-5),
143 TEST_PRECISION).getCircle().getPole(), TEST_EPS);
144
145 SphericalTestUtils.assertVectorsEqual(
146 Vector3D.Unit.PLUS_Y,
147 GreatCircles.arcFromPoints(
148 Point2S.PLUS_I,
149 Point2S.of(PlaneAngleRadians.PI, PlaneAngleRadians.PI_OVER_TWO + 1e-5),
150 TEST_PRECISION).getCircle().getPole(), TEST_EPS);
151 }
152
153 @Test
154 public void testFromPoints_invalidPoints() {
155
156 GeometryTestUtils.assertThrows(() -> {
157 GreatCircles.arcFromPoints(Point2S.PLUS_I, Point2S.of(1e-12, PlaneAngleRadians.PI_OVER_TWO), TEST_PRECISION);
158 }, IllegalArgumentException.class);
159
160 GeometryTestUtils.assertThrows(() -> {
161 GreatCircles.arcFromPoints(Point2S.PLUS_I, Point2S.MINUS_I, TEST_PRECISION);
162 }, IllegalArgumentException.class);
163 }
164
165 @Test
166 public void testToConvex() {
167
168 final GreatArc arc = GreatCircles.arcFromInterval(
169 GreatCircles.fromPoints(Point2S.PLUS_J, Point2S.MINUS_I, TEST_PRECISION),
170 AngularInterval.Convex.of(0.0, PlaneAngleRadians.PI, TEST_PRECISION));
171
172
173 final List<GreatArc> result = arc.toConvex();
174
175
176 Assert.assertEquals(1, result.size());
177 Assert.assertSame(arc, result.get(0));
178 }
179
180 @Test
181 public void testReverse_full() {
182
183 final GreatArc arc = GreatCircles.arcFromInterval(
184 GreatCircles.fromPoints(Point2S.PLUS_J, Point2S.MINUS_I, TEST_PRECISION),
185 AngularInterval.full());
186
187
188 final GreatArc result = arc.reverse();
189
190
191 checkGreatCircle(result.getCircle(), Vector3D.Unit.MINUS_Z, Vector3D.Unit.PLUS_Y);
192
193 Assert.assertTrue(result.isFull());
194 }
195
196 @Test
197 public void testReverse() {
198
199 final GreatArc arc = GreatCircles.arcFromInterval(
200 GreatCircles.fromPoints(Point2S.PLUS_J, Point2S.MINUS_I, TEST_PRECISION),
201 AngularInterval.Convex.of(PlaneAngleRadians.PI_OVER_TWO, PlaneAngleRadians.PI, TEST_PRECISION));
202
203
204 final GreatArc result = arc.reverse();
205
206
207 checkGreatCircle(result.getCircle(), Vector3D.Unit.MINUS_Z, Vector3D.Unit.PLUS_Y);
208
209 checkArc(result, Point2S.MINUS_J, Point2S.MINUS_I);
210 }
211
212 @Test
213 public void testTransform() {
214
215 final GreatArc arc = GreatCircles.fromPoints(Point2S.PLUS_K, Point2S.MINUS_I, TEST_PRECISION)
216 .arc(PlaneAngleRadians.PI, -PlaneAngleRadians.PI_OVER_TWO);
217
218 final Transform2S t = Transform2S.createRotation(Point2S.PLUS_I, PlaneAngleRadians.PI_OVER_TWO)
219 .reflect(Point2S.of(-0.25 * PlaneAngleRadians.PI, PlaneAngleRadians.PI_OVER_TWO));
220
221
222 final GreatArc result = arc.transform(t);
223
224
225 checkArc(result, Point2S.PLUS_I, Point2S.PLUS_J);
226 }
227
228 @Test
229 public void testSplit_full() {
230
231 final GreatArc arc = GreatCircles.fromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION).span();
232 final GreatCircle splitter = GreatCircles.fromPole(Vector3D.of(-1, 0, 1), TEST_PRECISION);
233
234
235 final Split<GreatArc> split = arc.split(splitter);
236
237
238 Assert.assertEquals(SplitLocation.BOTH, split.getLocation());
239
240 final GreatArc minus = split.getMinus();
241 Assert.assertSame(arc.getCircle(), minus.getCircle());
242 checkArc(minus, Point2S.PLUS_J, Point2S.MINUS_J);
243 checkClassify(minus, RegionLocation.OUTSIDE, Point2S.PLUS_I);
244 checkClassify(minus, RegionLocation.INSIDE, Point2S.MINUS_I);
245
246 final GreatArc plus = split.getPlus();
247 Assert.assertSame(arc.getCircle(), plus.getCircle());
248 checkArc(plus, Point2S.MINUS_J, Point2S.PLUS_J);
249 checkClassify(plus, RegionLocation.INSIDE, Point2S.PLUS_I);
250 checkClassify(plus, RegionLocation.OUTSIDE, Point2S.MINUS_I);
251 }
252
253 @Test
254 public void testSplit_both() {
255
256 final GreatArc arc = GreatCircles.fromPoints(Point2S.PLUS_J, Point2S.PLUS_K, TEST_PRECISION)
257 .arc(PlaneAngleRadians.PI_OVER_TWO, PlaneAngleRadians.PI);
258 final GreatCircle splitter = GreatCircles.fromPole(Vector3D.of(0, 1, 1), TEST_PRECISION);
259
260
261 final Split<GreatArc> split = arc.split(splitter);
262
263
264 Assert.assertEquals(SplitLocation.BOTH, split.getLocation());
265
266 final GreatArc minus = split.getMinus();
267 Assert.assertSame(arc.getCircle(), minus.getCircle());
268 checkArc(minus, Point2S.of(0, 0), Point2S.of(1.5 * PlaneAngleRadians.PI, 0.25 * PlaneAngleRadians.PI));
269
270 final GreatArc plus = split.getPlus();
271 Assert.assertSame(arc.getCircle(), plus.getCircle());
272 checkArc(plus, Point2S.of(1.5 * PlaneAngleRadians.PI, 0.25 * PlaneAngleRadians.PI), Point2S.MINUS_J);
273 }
274
275 @Test
276 public void testSplit_minus() {
277
278 final GreatArc arc = GreatCircles.fromPoints(Point2S.PLUS_J, Point2S.PLUS_K, TEST_PRECISION)
279 .arc(PlaneAngleRadians.PI_OVER_TWO, PlaneAngleRadians.PI);
280 final GreatCircle splitter = GreatCircles.fromPole(Vector3D.Unit.PLUS_Z, TEST_PRECISION);
281
282
283
284 final Split<GreatArc> split = arc.split(splitter);
285
286
287 Assert.assertEquals(SplitLocation.MINUS, split.getLocation());
288
289 final GreatArc minus = split.getMinus();
290 Assert.assertSame(arc, minus);
291
292 final GreatArc plus = split.getPlus();
293 Assert.assertNull(plus);
294 }
295
296 @Test
297 public void testSplit_plus() {
298
299 final GreatArc arc = GreatCircles.fromPoints(Point2S.PLUS_J, Point2S.PLUS_K, TEST_PRECISION)
300 .arc(PlaneAngleRadians.PI_OVER_TWO, PlaneAngleRadians.PI);
301 final GreatCircle splitter = GreatCircles.fromPole(Vector3D.Unit.from(-1, 0, -1), TEST_PRECISION);
302
303
304 final Split<GreatArc> split = arc.split(splitter);
305
306
307 Assert.assertEquals(SplitLocation.PLUS, split.getLocation());
308
309 final GreatArc minus = split.getMinus();
310 Assert.assertNull(minus);
311
312 final GreatArc plus = split.getPlus();
313 Assert.assertSame(arc, plus);
314 }
315
316 @Test
317 public void testSplit_parallelAndAntiparallel() {
318
319 final GreatArc arc = GreatCircles.fromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION).span();
320
321
322 Assert.assertEquals(SplitLocation.NEITHER,
323 arc.split(GreatCircles.fromPole(Vector3D.Unit.PLUS_Z, TEST_PRECISION)).getLocation());
324 Assert.assertEquals(SplitLocation.NEITHER,
325 arc.split(GreatCircles.fromPole(Vector3D.Unit.MINUS_Z, TEST_PRECISION)).getLocation());
326 }
327
328 @Test
329 public void testToString_full() {
330
331 final GreatArc arc = GreatCircles.fromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION).span();
332
333
334 final String str = arc.toString();
335
336
337 GeometryTestUtils.assertContains("GreatArc[", str);
338 GeometryTestUtils.assertContains("full= true", str);
339 GeometryTestUtils.assertContains("circle= GreatCircle[", str);
340 }
341
342 @Test
343 public void testToString_notFull() {
344
345 final GreatArc arc = GreatCircles.arcFromInterval(
346 GreatCircles.fromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION),
347 AngularInterval.Convex.of(1, 2, TEST_PRECISION));
348
349
350 final String str = arc.toString();
351
352
353 GeometryTestUtils.assertContains("GreatArc[", str);
354 GeometryTestUtils.assertContains("start= (", str);
355 GeometryTestUtils.assertContains("end= (", str);
356 }
357
358 private static void checkClassify(final GreatArc arc, final RegionLocation loc, final Point2S... pts) {
359 for (final Point2S pt : pts) {
360 Assert.assertEquals("Unexpected location for point " + pt, loc, arc.classify(pt));
361 }
362 }
363
364 private static void checkArc(final GreatArc arc, final Point2S start, final Point2S end) {
365 SphericalTestUtils.assertPointsEq(start, arc.getStartPoint(), TEST_EPS);
366 SphericalTestUtils.assertPointsEq(end, arc.getEndPoint(), TEST_EPS);
367
368 checkClassify(arc, RegionLocation.BOUNDARY, start, end);
369
370 final Point2S mid = arc.getCircle().toSpace(arc.getInterval().getMidPoint());
371
372 checkClassify(arc, RegionLocation.INSIDE, mid);
373 checkClassify(arc, RegionLocation.OUTSIDE, mid.antipodal());
374
375 Assert.assertEquals(start.distance(end), arc.getSize(), TEST_EPS);
376 SphericalTestUtils.assertPointsEq(mid, arc.getCentroid(), TEST_EPS);
377 }
378
379 private static void checkGreatCircle(final GreatCircle circle, final Vector3D pole, final Vector3D x) {
380 SphericalTestUtils.assertVectorsEqual(pole, circle.getPole(), TEST_EPS);
381 SphericalTestUtils.assertVectorsEqual(x, circle.getU(), TEST_EPS);
382 SphericalTestUtils.assertVectorsEqual(pole.cross(x), circle.getV(), TEST_EPS);
383 }
384 }