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.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.numbers.angle.PlaneAngleRadians;
28 import org.junit.Assert;
29 import org.junit.Test;
30
31 public class AbstractGreatArcPathConnectorTest {
32
33 private static final double TEST_EPS = 1e-10;
34
35 private static final DoublePrecisionContext TEST_PRECISION =
36 new EpsilonDoublePrecisionContext(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 public void testConnectAll_emptyCollection() {
48
49 final List<GreatArcPath> paths = connector.connectAll(Collections.emptyList());
50
51
52 Assert.assertEquals(0, paths.size());
53 }
54
55 @Test
56 public void testConnectAll_singleFullArc() {
57
58 connector.add(Collections.singletonList(XY_PLANE.span()));
59 final List<GreatArcPath> paths = connector.connectAll();
60
61
62 Assert.assertEquals(1, paths.size());
63
64 final GreatArcPath a = paths.get(0);
65 Assert.assertEquals(1, a.getArcs().size());
66 Assert.assertSame(XY_PLANE, a.getStartArc().getCircle());
67 }
68
69 @Test
70 public 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 Assert.assertEquals(2, paths.size());
77
78 final GreatArcPath a = paths.get(0);
79 Assert.assertEquals(1, a.getArcs().size());
80 Assert.assertSame(XY_PLANE, a.getStartArc().getCircle());
81
82 final GreatArcPath b = paths.get(1);
83 Assert.assertEquals(1, b.getArcs().size());
84 Assert.assertSame(XZ_PLANE, b.getStartArc().getCircle());
85 }
86
87 @Test
88 public 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, PlaneAngleRadians.PI));
94 connector.add(upperBound.arc(PlaneAngleRadians.PI, 0));
95
96
97 final List<GreatArcPath> paths = connector.connectAll();
98
99
100 Assert.assertEquals(1, paths.size());
101
102 final GreatArcPath a = paths.get(0);
103 Assert.assertEquals(2, a.getArcs().size());
104 Assert.assertSame(XY_PLANE, a.getStartArc().getCircle());
105 Assert.assertSame(upperBound, a.getEndArc().getCircle());
106 }
107
108 @Test
109 public 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, PlaneAngleRadians.PI));
115 connector.add(upperBound.arc(0, PlaneAngleRadians.PI));
116
117
118 final List<GreatArcPath> paths = connector.connectAll();
119
120
121 Assert.assertEquals(2, paths.size());
122
123 final GreatArcPath a = paths.get(0);
124 Assert.assertEquals(1, a.getArcs().size());
125 Assert.assertSame(XY_PLANE, a.getStartArc().getCircle());
126
127 final GreatArcPath b = paths.get(1);
128 Assert.assertEquals(1, b.getArcs().size());
129 Assert.assertSame(upperBound, b.getStartArc().getCircle());
130 }
131
132 @Test
133 public 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 Assert.assertEquals(1, paths.size());
148
149 final GreatArcPath a = paths.get(0);
150 Assert.assertEquals(3, a.getArcs().size());
151
152 assertPathPoints(a, p3, p1, p2, p3);
153 }
154
155 @Test
156 public void testConnectAll_smallTriangleWithDisconnectedLuneAndArc() {
157
158 final Point2S p1 = Point2S.of(0, 0);
159 final Point2S p2 = Point2S.of(0, 0.1 * PlaneAngleRadians.PI);
160 final Point2S p3 = Point2S.of(0.1, 0.1 * PlaneAngleRadians.PI);
161
162 final GreatArc luneEdge1 = GreatCircles.fromPoints(
163 Point2S.PLUS_J,
164 Point2S.MINUS_I,
165 TEST_PRECISION)
166 .arc(0, PlaneAngleRadians.PI);
167 final GreatArc luneEdge2 = GreatCircles.fromPoints(
168 Point2S.MINUS_J,
169 Point2S.of(PlaneAngleRadians.PI_OVER_TWO, 0.4 * PlaneAngleRadians.PI),
170 TEST_PRECISION)
171 .arc(0, PlaneAngleRadians.PI);
172
173 final GreatArc separateArc = GreatCircles.arcFromPoints(
174 Point2S.of(-PlaneAngleRadians.PI_OVER_TWO, 0.7 * PlaneAngleRadians.PI),
175 Point2S.of(-PlaneAngleRadians.PI_OVER_TWO, 0.8 * PlaneAngleRadians.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 Assert.assertEquals(3, paths.size());
190
191 final GreatArcPath triangle = paths.get(0);
192 Assert.assertEquals(3, triangle.getArcs().size());
193 assertPathPoints(triangle, p1, p2, p3, p1);
194
195 final GreatArcPath lune = paths.get(1);
196 Assert.assertEquals(2, lune.getArcs().size());
197 Assert.assertSame(luneEdge1, lune.getStartArc());
198 Assert.assertSame(luneEdge2, lune.getEndArc());
199
200 final GreatArcPath separate = paths.get(2);
201 Assert.assertEquals(1, separate.getArcs().size());
202 Assert.assertSame(separateArc, separate.getStartArc());
203 }
204
205 @Test
206 public void testConnectAll_choosesBestPointLikeConnection() {
207
208 final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-1);
209
210 final Point2S p1 = Point2S.PLUS_I;
211 final Point2S p2 = Point2S.of(1, PlaneAngleRadians.PI_OVER_TWO);
212 final Point2S p3 = Point2S.of(1.001, 0.491 * PlaneAngleRadians.PI);
213 final Point2S p4 = Point2S.of(1.001, 0.502 * PlaneAngleRadians.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 Assert.assertEquals(2, paths.size());
224
225 final GreatArcPath a = paths.get(0);
226 Assert.assertEquals(2, a.getArcs().size());
227 assertPathPoints(a, p1, p2, p4);
228
229 final GreatArcPath b = paths.get(1);
230 Assert.assertEquals(1, b.getArcs().size());
231 assertPathPoints(b, p2, p3);
232 }
233
234 @Test
235 public 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 Assert.assertEquals(2, paths.size());
253
254 final GreatArcPath a = paths.get(0);
255 Assert.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 Assert.assertEquals(1, b.getArcs().size());
260 assertPathPoints(b, Point2S.PLUS_J, Point2S.PLUS_K);
261 }
262
263 @Test
264 public void testConnectorCanBeReused() {
265
266 final GreatArc a = GreatCircles.arcFromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION);
267 final GreatArc b = GreatCircles.arcFromPoints(Point2S.MINUS_I, Point2S.MINUS_J, TEST_PRECISION);
268
269
270 final List<GreatArcPath> path1 = connector.connectAll(Collections.singletonList(a));
271 final List<GreatArcPath> path2 = connector.connectAll(Collections.singletonList(b));
272
273
274 Assert.assertEquals(1, path1.size());
275 assertPathPoints(path1.get(0), Point2S.PLUS_I, Point2S.PLUS_J);
276
277 Assert.assertEquals(1, path2.size());
278 assertPathPoints(path2.get(0), Point2S.MINUS_I, Point2S.MINUS_J);
279 }
280
281 private static void assertPathPoints(final GreatArcPath path, final Point2S... points) {
282 final List<Point2S> expectedPoints = Arrays.asList(points);
283 final List<Point2S> actualPoints = path.getVertices();
284
285 final String msg = "Expected path points to equal " + expectedPoints + " but was " + actualPoints;
286 Assert.assertEquals(msg, expectedPoints.size(), actualPoints.size());
287
288 for (int i = 0; i < expectedPoints.size(); ++i) {
289 SphericalTestUtils.assertPointsEq(expectedPoints.get(i), actualPoints.get(i), TEST_EPS);
290 }
291 }
292
293 private static class TestConnector extends AbstractGreatArcConnector {
294
295 @Override
296 protected ConnectableGreatArc selectConnection(final ConnectableGreatArc incoming,
297 final List<ConnectableGreatArc> outgoing) {
298
299
300 return outgoing.get(0);
301 }
302 }
303 }