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.Arrays;
20 import java.util.Collections;
21 import java.util.List;
22
23 import org.apache.commons.geometry.euclidean.threed.Vector3D;
24 import org.apache.commons.geometry.spherical.SphericalTestUtils;
25 import org.apache.commons.geometry.spherical.twod.AbstractGreatArcConnector.ConnectableGreatArc;
26 import org.apache.commons.numbers.angle.Angle;
27 import org.apache.commons.numbers.core.Precision;
28 import org.junit.jupiter.api.Assertions;
29 import org.junit.jupiter.api.Test;
30
31 class AbstractGreatArcPathConnectorTest {
32
33 private static final double TEST_EPS = 1e-10;
34
35 private static final Precision.DoubleEquivalence TEST_PRECISION =
36 Precision.doubleEquivalenceOfEpsilon(TEST_EPS);
37
38 private static final GreatCircle XY_PLANE = GreatCircles.fromPoleAndU(
39 Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X, TEST_PRECISION);
40
41 private static final GreatCircle XZ_PLANE = GreatCircles.fromPoleAndU(
42 Vector3D.Unit.PLUS_Y, Vector3D.Unit.PLUS_X, TEST_PRECISION);
43
44 private final TestConnector connector = new TestConnector();
45
46 @Test
47 void testConnectAll_emptyCollection() {
48
49 final List<GreatArcPath> paths = connector.connectAll(Collections.emptyList());
50
51
52 Assertions.assertEquals(0, paths.size());
53 }
54
55 @Test
56 void testConnectAll_singleFullArc() {
57
58 connector.add(Collections.singletonList(XY_PLANE.span()));
59 final List<GreatArcPath> paths = connector.connectAll();
60
61
62 Assertions.assertEquals(1, paths.size());
63
64 final GreatArcPath a = paths.get(0);
65 Assertions.assertEquals(1, a.getArcs().size());
66 Assertions.assertSame(XY_PLANE, a.getStartArc().getCircle());
67 }
68
69 @Test
70 void testConnectAll_twoFullArcs() {
71
72 connector.add(XZ_PLANE.span());
73 final List<GreatArcPath> paths = connector.connectAll(Collections.singletonList(XY_PLANE.span()));
74
75
76 Assertions.assertEquals(2, paths.size());
77
78 final GreatArcPath a = paths.get(0);
79 Assertions.assertEquals(1, a.getArcs().size());
80 Assertions.assertSame(XY_PLANE, a.getStartArc().getCircle());
81
82 final GreatArcPath b = paths.get(1);
83 Assertions.assertEquals(1, b.getArcs().size());
84 Assertions.assertSame(XZ_PLANE, b.getStartArc().getCircle());
85 }
86
87 @Test
88 void testConnectAll_singleLune() {
89
90 final GreatCircle upperBound = GreatCircles.fromPoleAndU(
91 Vector3D.of(0, 1, -1), Vector3D.Unit.PLUS_X, TEST_PRECISION);
92
93 connector.add(XY_PLANE.arc(0, Math.PI));
94 connector.add(upperBound.arc(Math.PI, 0));
95
96
97 final List<GreatArcPath> paths = connector.connectAll();
98
99
100 Assertions.assertEquals(1, paths.size());
101
102 final GreatArcPath a = paths.get(0);
103 Assertions.assertEquals(2, a.getArcs().size());
104 Assertions.assertSame(XY_PLANE, a.getStartArc().getCircle());
105 Assertions.assertSame(upperBound, a.getEndArc().getCircle());
106 }
107
108 @Test
109 void testConnectAll_singleLune_pathsNotOrientedCorrectly() {
110
111 final GreatCircle upperBound = GreatCircles.fromPoleAndU(
112 Vector3D.of(0, 1, -1), Vector3D.Unit.PLUS_X, TEST_PRECISION);
113
114 connector.add(XY_PLANE.arc(0, Math.PI));
115 connector.add(upperBound.arc(0, Math.PI));
116
117
118 final List<GreatArcPath> paths = connector.connectAll();
119
120
121 Assertions.assertEquals(2, paths.size());
122
123 final GreatArcPath a = paths.get(0);
124 Assertions.assertEquals(1, a.getArcs().size());
125 Assertions.assertSame(XY_PLANE, a.getStartArc().getCircle());
126
127 final GreatArcPath b = paths.get(1);
128 Assertions.assertEquals(1, b.getArcs().size());
129 Assertions.assertSame(upperBound, b.getStartArc().getCircle());
130 }
131
132 @Test
133 void testConnectAll_largeTriangle() {
134
135 final Point2S p1 = Point2S.PLUS_I;
136 final Point2S p2 = Point2S.PLUS_J;
137 final Point2S p3 = Point2S.PLUS_K;
138
139
140 final List<GreatArcPath> paths = connector.connectAll(Arrays.asList(
141 GreatCircles.arcFromPoints(p1, p2, TEST_PRECISION),
142 GreatCircles.arcFromPoints(p2, p3, TEST_PRECISION),
143 GreatCircles.arcFromPoints(p3, p1, TEST_PRECISION)
144 ));
145
146
147 Assertions.assertEquals(1, paths.size());
148
149 final GreatArcPath a = paths.get(0);
150 Assertions.assertEquals(3, a.getArcs().size());
151
152 assertPathPoints(a, p3, p1, p2, p3);
153 }
154
155 @Test
156 void testConnectAll_smallTriangleWithDisconnectedLuneAndArc() {
157
158 final Point2S p1 = Point2S.of(0, 0);
159 final Point2S p2 = Point2S.of(0, 0.1 * Math.PI);
160 final Point2S p3 = Point2S.of(0.1, 0.1 * Math.PI);
161
162 final GreatArc luneEdge1 = GreatCircles.fromPoints(
163 Point2S.PLUS_J,
164 Point2S.MINUS_I,
165 TEST_PRECISION)
166 .arc(0, Math.PI);
167 final GreatArc luneEdge2 = GreatCircles.fromPoints(
168 Point2S.MINUS_J,
169 Point2S.of(Angle.PI_OVER_TWO, 0.4 * Math.PI),
170 TEST_PRECISION)
171 .arc(0, Math.PI);
172
173 final GreatArc separateArc = GreatCircles.arcFromPoints(
174 Point2S.of(-Angle.PI_OVER_TWO, 0.7 * Math.PI),
175 Point2S.of(-Angle.PI_OVER_TWO, 0.8 * Math.PI),
176 TEST_PRECISION);
177
178
179 final List<GreatArcPath> paths = connector.connectAll(Arrays.asList(
180 luneEdge1,
181 GreatCircles.arcFromPoints(p2, p3, TEST_PRECISION),
182 separateArc,
183 GreatCircles.arcFromPoints(p1, p2, TEST_PRECISION),
184 GreatCircles.arcFromPoints(p3, p1, TEST_PRECISION),
185 luneEdge2
186 ));
187
188
189 Assertions.assertEquals(3, paths.size());
190
191 final GreatArcPath triangle = paths.get(0);
192 Assertions.assertEquals(3, triangle.getArcs().size());
193 assertPathPoints(triangle, p1, p2, p3, p1);
194
195 final GreatArcPath lune = paths.get(1);
196 Assertions.assertEquals(2, lune.getArcs().size());
197 Assertions.assertSame(luneEdge1, lune.getStartArc());
198 Assertions.assertSame(luneEdge2, lune.getEndArc());
199
200 final GreatArcPath separate = paths.get(2);
201 Assertions.assertEquals(1, separate.getArcs().size());
202 Assertions.assertSame(separateArc, separate.getStartArc());
203 }
204
205 @Test
206 void testConnectAll_choosesBestPointLikeConnection() {
207
208 final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-1);
209
210 final Point2S p1 = Point2S.PLUS_I;
211 final Point2S p2 = Point2S.of(1, Angle.PI_OVER_TWO);
212 final Point2S p3 = Point2S.of(1.001, 0.491 * Math.PI);
213 final Point2S p4 = Point2S.of(1.001, 0.502 * Math.PI);
214
215 connector.add(GreatCircles.arcFromPoints(p2, p3, TEST_PRECISION));
216 connector.add(GreatCircles.arcFromPoints(p2, p4, TEST_PRECISION));
217 connector.add(GreatCircles.arcFromPoints(p1, p2, precision));
218
219
220 final List<GreatArcPath> paths = connector.connectAll();
221
222
223 Assertions.assertEquals(2, paths.size());
224
225 final GreatArcPath a = paths.get(0);
226 Assertions.assertEquals(2, a.getArcs().size());
227 assertPathPoints(a, p1, p2, p4);
228
229 final GreatArcPath b = paths.get(1);
230 Assertions.assertEquals(1, b.getArcs().size());
231 assertPathPoints(b, p2, p3);
232 }
233
234 @Test
235 void testConnect() {
236
237 final GreatArc arcA = GreatCircles.arcFromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION);
238 final GreatArc arcB = GreatCircles.arcFromPoints(Point2S.PLUS_J, Point2S.MINUS_I, TEST_PRECISION);
239 final GreatArc arcC = GreatCircles.arcFromPoints(Point2S.PLUS_J, Point2S.PLUS_K, TEST_PRECISION);
240
241
242 connector.connect(Arrays.asList(
243 arcB,
244 arcA
245 ));
246
247 connector.connect(Collections.singletonList(arcC));
248
249 final List<GreatArcPath> paths = connector.connectAll();
250
251
252 Assertions.assertEquals(2, paths.size());
253
254 final GreatArcPath a = paths.get(0);
255 Assertions.assertEquals(2, a.getArcs().size());
256 assertPathPoints(a, Point2S.PLUS_I, Point2S.PLUS_J, Point2S.MINUS_I);
257
258 final GreatArcPath b = paths.get(1);
259 Assertions.assertEquals(1, b.getArcs().size());
260 assertPathPoints(b, Point2S.PLUS_J, Point2S.PLUS_K);
261 }
262
263 @Test
264 void testConnectableSegment_hashCode() {
265
266 final GreatArc arcA = GreatCircles.arcFromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION);
267 final GreatArc arcB = GreatCircles.arcFromPoints(Point2S.PLUS_J, Point2S.MINUS_I, TEST_PRECISION);
268
269 final ConnectableGreatArc a = new ConnectableGreatArc(arcA);
270
271
272 final int hash = a.hashCode();
273
274
275 Assertions.assertEquals(hash, a.hashCode());
276
277 Assertions.assertNotEquals(hash, new ConnectableGreatArc(arcB).hashCode());
278 Assertions.assertNotEquals(hash, new ConnectableGreatArc(Point2S.MINUS_I).hashCode());
279
280 Assertions.assertEquals(hash, new ConnectableGreatArc(arcA).hashCode());
281 }
282
283 @Test
284 void testConnectableSegment_equals() {
285
286 final GreatArc arcA = GreatCircles.arcFromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION);
287 final GreatArc arcB = GreatCircles.arcFromPoints(Point2S.PLUS_J, Point2S.MINUS_I, TEST_PRECISION);
288
289 final ConnectableGreatArc a = new ConnectableGreatArc(arcA);
290
291
292 Assertions.assertEquals(a, a);
293
294 Assertions.assertFalse(a.equals(null));
295 Assertions.assertFalse(a.equals(new Object()));
296
297 Assertions.assertNotEquals(a, new ConnectableGreatArc(arcB));
298 Assertions.assertNotEquals(a, new ConnectableGreatArc(Point2S.MINUS_I));
299
300 Assertions.assertEquals(a, new ConnectableGreatArc(arcA));
301 }
302
303 @Test
304 void testConnectorCanBeReused() {
305
306 final GreatArc a = GreatCircles.arcFromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION);
307 final GreatArc b = GreatCircles.arcFromPoints(Point2S.MINUS_I, Point2S.MINUS_J, TEST_PRECISION);
308
309
310 final List<GreatArcPath> path1 = connector.connectAll(Collections.singletonList(a));
311 final List<GreatArcPath> path2 = connector.connectAll(Collections.singletonList(b));
312
313
314 Assertions.assertEquals(1, path1.size());
315 assertPathPoints(path1.get(0), Point2S.PLUS_I, Point2S.PLUS_J);
316
317 Assertions.assertEquals(1, path2.size());
318 assertPathPoints(path2.get(0), Point2S.MINUS_I, Point2S.MINUS_J);
319 }
320
321 private static void assertPathPoints(final GreatArcPath path, final Point2S... points) {
322 final List<Point2S> expectedPoints = Arrays.asList(points);
323 final List<Point2S> actualPoints = path.getVertices();
324
325 final String msg = "Expected path points to equal " + expectedPoints + " but was " + actualPoints;
326 Assertions.assertEquals(expectedPoints.size(), actualPoints.size(), msg);
327
328 for (int i = 0; i < expectedPoints.size(); ++i) {
329 SphericalTestUtils.assertPointsEq(expectedPoints.get(i), actualPoints.get(i), TEST_EPS);
330 }
331 }
332
333 private static class TestConnector extends AbstractGreatArcConnector {
334
335 @Override
336 protected ConnectableGreatArc selectConnection(final ConnectableGreatArc incoming,
337 final List<ConnectableGreatArc> outgoing) {
338
339
340 return outgoing.get(0);
341 }
342 }
343 }