View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.geometry.euclidean.twod.path;
18  
19  import java.util.ArrayList;
20  import java.util.Arrays;
21  import java.util.Collections;
22  import java.util.List;
23  import java.util.Random;
24  
25  import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
26  import org.apache.commons.geometry.euclidean.twod.Line;
27  import org.apache.commons.geometry.euclidean.twod.LineConvexSubset;
28  import org.apache.commons.geometry.euclidean.twod.Lines;
29  import org.apache.commons.geometry.euclidean.twod.Segment;
30  import org.apache.commons.geometry.euclidean.twod.Vector2D;
31  import org.apache.commons.geometry.euclidean.twod.path.AbstractLinePathConnector.ConnectableLineSubset;
32  import org.apache.commons.numbers.angle.Angle;
33  import org.apache.commons.numbers.core.Precision;
34  import org.junit.jupiter.api.Assertions;
35  import org.junit.jupiter.api.Test;
36  
37  class AbstractLinePathConnectorTest {
38  
39      private static final double TEST_EPS = 1e-10;
40  
41      private static final Precision.DoubleEquivalence TEST_PRECISION =
42              Precision.doubleEquivalenceOfEpsilon(TEST_EPS);
43  
44      private static final Line Y_AXIS = Lines.fromPointAndAngle(Vector2D.ZERO, Angle.PI_OVER_TWO,
45              TEST_PRECISION);
46  
47      private final TestConnector connector = new TestConnector();
48  
49      @Test
50      void testConnectAll_emptyCollection() {
51          // act
52          final List<LinePath> paths = connector.connectAll(Collections.emptyList());
53  
54          // assert
55          Assertions.assertEquals(0, paths.size());
56      }
57  
58      @Test
59      void testConnectAll_singleInfiniteLine() {
60          // arrange
61          final LineConvexSubset segment = Y_AXIS.span();
62  
63          // act
64          final List<LinePath> paths = connector.connectAll(Collections.singletonList(segment));
65  
66          // assert
67          Assertions.assertEquals(1, paths.size());
68  
69          final LinePath path = paths.get(0);
70          Assertions.assertEquals(1, path.getElements().size());
71          Assertions.assertSame(segment, path.getStart());
72      }
73  
74      @Test
75      void testConnectAll_singleHalfInfiniteLine_noEndPoint() {
76          // arrange
77          final LineConvexSubset segment = Y_AXIS.rayFrom(Vector2D.ZERO);
78  
79          // act
80          final List<LinePath> paths = connector.connectAll(Collections.singletonList(segment));
81  
82          // assert
83          Assertions.assertEquals(1, paths.size());
84  
85          final LinePath path = paths.get(0);
86          Assertions.assertEquals(1, path.getElements().size());
87          Assertions.assertSame(segment, path.getStart());
88      }
89  
90      @Test
91      void testConnectAll_singleHalfInfiniteLine_noStartPoint() {
92          // arrange
93          final LineConvexSubset segment = Y_AXIS.reverseRayTo(Vector2D.ZERO);
94  
95          // act
96          final List<LinePath> paths = connector.connectAll(Collections.singletonList(segment));
97  
98          // assert
99          Assertions.assertEquals(1, paths.size());
100 
101         final LinePath path = paths.get(0);
102         Assertions.assertEquals(1, path.getElements().size());
103         Assertions.assertSame(segment, path.getStart());
104     }
105 
106     @Test
107     void testConnectAll_disjointSegments() {
108         // arrange
109         final LineConvexSubset a = Y_AXIS.segment(Vector2D.of(0, 1), Vector2D.of(0, 2));
110         final LineConvexSubset b = Y_AXIS.segment(Vector2D.of(0, -1), Vector2D.ZERO);
111 
112         final List<LineConvexSubset> segments = Arrays.asList(a, b);
113 
114         // act
115         final List<LinePath> paths = connector.connectAll(segments);
116 
117         // assert
118         Assertions.assertEquals(2, paths.size());
119 
120         assertFinitePath(paths.get(0), Vector2D.of(0, -1), Vector2D.ZERO);
121         assertFinitePath(paths.get(1), Vector2D.of(0, 1), Vector2D.of(0, 2));
122     }
123 
124     @Test
125     void testConnectAll_singleClosedPath() {
126         // arrange
127         final LinePath input = LinePath.builder(TEST_PRECISION)
128                 .appendVertices(Vector2D.of(1, 1), Vector2D.ZERO, Vector2D.of(1, 0))
129                 .close();
130 
131         final List<LineConvexSubset> segments = new ArrayList<>(input.getElements());
132         shuffle(segments);
133 
134         // act
135         final List<LinePath> paths = connector.connectAll(segments);
136 
137         // assert
138         Assertions.assertEquals(1, paths.size());
139 
140         assertFinitePath(paths.get(0),
141                 Vector2D.ZERO, Vector2D.of(1, 0), Vector2D.of(1, 1), Vector2D.ZERO);
142     }
143 
144     @Test
145     void testConnectAll_multipleClosedPaths() {
146         // arrange
147         final LinePath a = LinePath.builder(TEST_PRECISION)
148                 .appendVertices(Vector2D.of(1, 1), Vector2D.ZERO, Vector2D.of(1, 0))
149                 .close();
150 
151         final LinePath b = LinePath.builder(TEST_PRECISION)
152                 .appendVertices(Vector2D.of(0, 1), Vector2D.of(-1, 0), Vector2D.of(-0.5, 0))
153                 .close();
154 
155         final LinePath c = LinePath.builder(TEST_PRECISION)
156                 .appendVertices(Vector2D.of(1, 3), Vector2D.of(0, 2), Vector2D.of(1, 2))
157                 .close();
158 
159         final List<LineConvexSubset> segments = new ArrayList<>();
160         segments.addAll(a.getElements());
161         segments.addAll(b.getElements());
162         segments.addAll(c.getElements());
163 
164         shuffle(segments);
165 
166         // act
167         final List<LinePath> paths = connector.connectAll(segments);
168 
169         // assert
170         Assertions.assertEquals(3, paths.size());
171 
172         assertFinitePath(paths.get(0),
173                 Vector2D.of(-1, 0), Vector2D.of(-0.5, 0), Vector2D.of(0, 1), Vector2D.of(-1, 0));
174 
175         assertFinitePath(paths.get(1),
176                 Vector2D.ZERO, Vector2D.of(1, 0), Vector2D.of(1, 1), Vector2D.ZERO);
177 
178         assertFinitePath(paths.get(2),
179                 Vector2D.of(0, 2), Vector2D.of(1, 2), Vector2D.of(1, 3), Vector2D.of(0, 2));
180     }
181 
182     @Test
183     void testConnectAll_singleOpenPath() {
184         // arrange
185         final LinePath input = LinePath.builder(TEST_PRECISION)
186                 .appendVertices(Vector2D.of(1, 1), Vector2D.ZERO, Vector2D.of(1, 0))
187                 .build();
188 
189         final List<LineConvexSubset> segments = new ArrayList<>(input.getElements());
190         shuffle(segments);
191 
192         // act
193         final List<LinePath> paths = connector.connectAll(segments);
194 
195         // assert
196         Assertions.assertEquals(1, paths.size());
197 
198         assertFinitePath(paths.get(0),
199                 Vector2D.of(1, 1), Vector2D.ZERO, Vector2D.of(1, 0));
200     }
201 
202     @Test
203     void testConnectAll_mixOfOpenConnectedAndInfinite() {
204         // arrange
205         final LineConvexSubset inputYInf = Y_AXIS.reverseRayTo(Vector2D.ZERO);
206         final LineConvexSubset inputXInf = Lines.fromPoints(Vector2D.ZERO, Vector2D.Unit.MINUS_X, TEST_PRECISION)
207                 .rayFrom(Vector2D.ZERO);
208 
209         final LinePath closedPath = LinePath.builder(TEST_PRECISION)
210                 .appendVertices(Vector2D.of(0, 2), Vector2D.of(1, 2), Vector2D.of(1, 3))
211                 .close();
212 
213         final LinePath openPath = LinePath.builder(TEST_PRECISION)
214                 .appendVertices(Vector2D.of(-1, 3), Vector2D.of(0, 1), Vector2D.of(1, 1))
215                 .build();
216 
217         final List<LineConvexSubset> segments = new ArrayList<>();
218         segments.add(inputYInf);
219         segments.add(inputXInf);
220         segments.addAll(closedPath.getElements());
221         segments.addAll(openPath.getElements());
222 
223         shuffle(segments);
224 
225         // act
226         final List<LinePath> paths = connector.connectAll(segments);
227 
228         // assert
229         Assertions.assertEquals(3, paths.size());
230 
231         assertFinitePath(paths.get(0),
232                 Vector2D.of(-1, 3), Vector2D.of(0, 1), Vector2D.of(1, 1));
233 
234         final LinePath infPath = paths.get(1);
235         Assertions.assertTrue(infPath.isInfinite());
236         Assertions.assertEquals(2, infPath.getElements().size());
237         Assertions.assertSame(inputYInf, infPath.getElements().get(0));
238         Assertions.assertSame(inputXInf, infPath.getElements().get(1));
239 
240         assertFinitePath(paths.get(2),
241                 Vector2D.of(0, 2), Vector2D.of(1, 2), Vector2D.of(1, 3), Vector2D.of(0, 2));
242     }
243 
244     @Test
245     void testConnectAll_pathWithSinglePoint() {
246         // arrange
247         final Vector2D p0 = Vector2D.ZERO;
248 
249         final List<LineConvexSubset> segments = Collections.singletonList(Lines.fromPointAndAngle(p0, 0, TEST_PRECISION).segment(p0, p0));
250 
251         // act
252         final List<LinePath> paths = connector.connectAll(segments);
253 
254         // assert
255         Assertions.assertEquals(1, paths.size());
256 
257         assertFinitePath(paths.get(0), p0, p0);
258     }
259 
260     @Test
261     void testConnectAll_pathWithPointLikeConnectedSegments() {
262         // arrange
263         final Vector2D p0 = Vector2D.ZERO;
264         final Vector2D p1 = Vector2D.of(1, 0);
265         final Vector2D p2 = Vector2D.of(1, 1);
266 
267         final Vector2D almostP0 = Vector2D.of(-1e-20, -1e-20);
268         final Vector2D almostP1 = Vector2D.of(1 - 1e-15, 0);
269 
270         final LinePath input = LinePath.builder(TEST_PRECISION)
271                 .appendVertices(p0, p1)
272                 .append(Lines.fromPointAndAngle(p1, 0.25 * Math.PI, TEST_PRECISION).segment(p1, p1))
273                 .append(Lines.fromPointAndAngle(p1, -0.25 * Math.PI, TEST_PRECISION).segment(almostP1, almostP1))
274                 .append(p2)
275                 .append(p0)
276                 .append(Lines.fromPointAndAngle(Vector2D.ZERO, -Angle.PI_OVER_TWO, TEST_PRECISION)
277                         .segment(almostP0, almostP0))
278                 .build();
279 
280         final List<LineConvexSubset> segments = new ArrayList<>(input.getElements());
281         shuffle(segments);
282 
283         // act
284         final List<LinePath> paths = connector.connectAll(segments);
285 
286         // assert
287         Assertions.assertEquals(1, paths.size());
288 
289         assertFinitePath(paths.get(0), p0, p1, almostP1, p1, p2, p0, almostP0);
290     }
291 
292     @Test
293     void testConnectAll_flatLineRegion() {
294         // arrange
295         final Vector2D p0 = Vector2D.ZERO;
296         final Vector2D p1 = Vector2D.of(1, 0);
297 
298         final Segment seg0 = Lines.segmentFromPoints(p0, p1, TEST_PRECISION);
299         final Segment seg1 = Lines.segmentFromPoints(p1, p0, TEST_PRECISION);
300         final LineConvexSubset seg2 = Lines.fromPointAndAngle(p1, Angle.PI_OVER_TWO, TEST_PRECISION).segment(p1, p1);
301         final LineConvexSubset seg3 = Lines.fromPointAndAngle(p0, -Angle.PI_OVER_TWO, TEST_PRECISION).segment(p0, p0);
302 
303         final List<LineConvexSubset> segments = new ArrayList<>(Arrays.asList(seg0, seg1, seg2, seg3));
304         shuffle(segments);
305 
306         // act
307         final List<LinePath> paths = connector.connectAll(segments);
308 
309         // assert
310         Assertions.assertEquals(1, paths.size());
311 
312         final LinePath path = paths.get(0);
313         Assertions.assertSame(seg0, path.getElements().get(0));
314         Assertions.assertSame(seg2, path.getElements().get(1));
315         Assertions.assertSame(seg1, path.getElements().get(2));
316         Assertions.assertSame(seg3, path.getElements().get(3));
317     }
318 
319     @Test
320     void testConnectAll_singlePointRegion() {
321         // arrange
322         final Vector2D p0 = Vector2D.of(1, 0);
323 
324         final LineConvexSubset seg0 = Lines.fromPointAndAngle(p0, 0.0, TEST_PRECISION).segment(p0, p0);
325         final LineConvexSubset seg1 = Lines.fromPointAndAngle(p0, Angle.PI_OVER_TWO, TEST_PRECISION).segment(p0, p0);
326         final LineConvexSubset seg2 = Lines.fromPointAndAngle(p0, Math.PI, TEST_PRECISION).segment(p0, p0);
327         final LineConvexSubset seg3 = Lines.fromPointAndAngle(p0, -Angle.PI_OVER_TWO, TEST_PRECISION).segment(p0, p0);
328 
329         final List<LineConvexSubset> segments = new ArrayList<>(Arrays.asList(seg0, seg1, seg2, seg3));
330         shuffle(segments);
331 
332         // act
333         final List<LinePath> paths = connector.connectAll(segments);
334 
335         // assert
336         Assertions.assertEquals(1, paths.size());
337 
338         final LinePath path = paths.get(0);
339         Assertions.assertSame(seg2, path.getElements().get(0));
340         Assertions.assertSame(seg3, path.getElements().get(1));
341         Assertions.assertSame(seg0, path.getElements().get(2));
342         Assertions.assertSame(seg1, path.getElements().get(3));
343     }
344 
345     @Test
346     void testConnectAll_pathWithPointLikeUnconnectedSegments() {
347         // arrange
348         final Vector2D p0 = Vector2D.ZERO;
349         final Vector2D p1 = Vector2D.of(1, 0);
350 
351         final LineConvexSubset seg0 = Lines.fromPointAndAngle(p1, 0.0, TEST_PRECISION).segment(p1, p1);
352         final LineConvexSubset seg1 = Lines.fromPointAndAngle(p1, 0.25 * Math.PI, TEST_PRECISION).segment(p1, p1);
353         final LineConvexSubset seg2 = Lines.fromPointAndAngle(p0, 0, TEST_PRECISION).segment(p0, p0);
354 
355         final List<LineConvexSubset> segments = new ArrayList<>(Arrays.asList(seg0, seg1, seg2));
356 
357         shuffle(segments);
358 
359         // act
360         final List<LinePath> paths = connector.connectAll(segments);
361 
362         // assert
363         Assertions.assertEquals(2, paths.size());
364 
365         final LinePath path0 = paths.get(0);
366         Assertions.assertEquals(1, path0.getElements().size());
367         Assertions.assertSame(seg2, path0.getElements().get(0));
368 
369         final LinePath path1 = paths.get(1);
370         Assertions.assertEquals(2, path1.getElements().size());
371         Assertions.assertSame(seg0, path1.getElements().get(0));
372         Assertions.assertSame(seg1, path1.getElements().get(1));
373     }
374 
375     @Test
376     void testConnectAll_pathStartingWithPoint() {
377         // arrange
378         final Vector2D p0 = Vector2D.ZERO;
379         final Vector2D p1 = Vector2D.of(1, 0);
380         final Vector2D p2 = Vector2D.of(1, 1);
381 
382         final LineConvexSubset seg0 = Lines.fromPointAndAngle(p0, Math.PI, TEST_PRECISION).segment(p0, p0);
383         final LineConvexSubset seg1 = Lines.segmentFromPoints(p0, p1, TEST_PRECISION);
384         final LineConvexSubset seg2 = Lines.segmentFromPoints(p1, p2, TEST_PRECISION);
385 
386         final List<LineConvexSubset> segments = new ArrayList<>(Arrays.asList(seg0, seg1, seg2));
387 
388         shuffle(segments);
389 
390         // act
391         final List<LinePath> paths = connector.connectAll(segments);
392 
393         // assert
394         Assertions.assertEquals(1, paths.size());
395 
396         final LinePath path = paths.get(0);
397         Assertions.assertSame(seg0, path.getElements().get(0));
398         Assertions.assertSame(seg1, path.getElements().get(1));
399         Assertions.assertSame(seg2, path.getElements().get(2));
400     }
401 
402     @Test
403     void testConnectAll_intersectingPaths() {
404         // arrange
405         final LinePath a = LinePath.builder(TEST_PRECISION)
406                 .appendVertices(Vector2D.of(-1, 1), Vector2D.of(0.5, 0), Vector2D.of(-1, -1))
407                 .build();
408 
409         final LinePath b = LinePath.builder(TEST_PRECISION)
410                 .appendVertices(Vector2D.of(1, 1), Vector2D.of(-0.5, 0), Vector2D.of(1, -1))
411                 .build();
412 
413         final List<LineConvexSubset> segments = new ArrayList<>();
414         segments.addAll(a.getElements());
415         segments.addAll(b.getElements());
416 
417         shuffle(segments);
418 
419         // act
420         final List<LinePath> paths = connector.connectAll(segments);
421 
422         // assert
423         Assertions.assertEquals(2, paths.size());
424 
425         assertFinitePath(paths.get(0),
426                 Vector2D.of(-1, 1), Vector2D.of(0.5, 0), Vector2D.of(-1, -1));
427 
428         assertFinitePath(paths.get(1),
429                 Vector2D.of(1, 1), Vector2D.of(-0.5, 0), Vector2D.of(1, -1));
430     }
431 
432     @Test
433     void testInstancesCanBeReused() {
434         // arrange
435         final LineConvexSubset a = Lines.segmentFromPoints(Vector2D.ZERO, Vector2D.Unit.PLUS_X, TEST_PRECISION);
436         final LineConvexSubset b = Lines.segmentFromPoints(Vector2D.Unit.PLUS_X, Vector2D.Unit.PLUS_Y, TEST_PRECISION);
437 
438         // act
439         final List<LinePath> firstPaths = connector.connectAll(Collections.singletonList(a));
440         final List<LinePath> secondPaths = connector.connectAll(Collections.singletonList(b));
441 
442         // assert
443         Assertions.assertEquals(1, firstPaths.size());
444         Assertions.assertEquals(1, secondPaths.size());
445 
446         Assertions.assertSame(a, firstPaths.get(0).getElements().get(0));
447         Assertions.assertSame(b, secondPaths.get(0).getElements().get(0));
448     }
449 
450     @Test
451     void testAdd() {
452         // arrange
453         final LineConvexSubset a = Lines.segmentFromPoints(Vector2D.ZERO, Vector2D.Unit.PLUS_X, TEST_PRECISION);
454         final LineConvexSubset b = Lines.segmentFromPoints(Vector2D.Unit.PLUS_X, Vector2D.of(1, 1), TEST_PRECISION);
455         final LineConvexSubset c = Lines.segmentFromPoints(Vector2D.Unit.PLUS_X, Vector2D.of(2, 0), TEST_PRECISION);
456 
457         // act
458         connector.add(Arrays.asList(a, b));
459         connector.add(Collections.singletonList(c));
460 
461         final List<LinePath> paths = connector.connectAll();
462 
463         // assert
464         Assertions.assertEquals(2, paths.size());
465 
466         assertFinitePath(paths.get(0), Vector2D.ZERO, Vector2D.Unit.PLUS_X, Vector2D.of(2, 0));
467         assertFinitePath(paths.get(1), Vector2D.Unit.PLUS_X, Vector2D.of(1, 1));
468     }
469 
470     @Test
471     void testConnect() {
472         // arrange
473         final LineConvexSubset a = Lines.segmentFromPoints(Vector2D.ZERO, Vector2D.Unit.PLUS_X, TEST_PRECISION);
474         final LineConvexSubset b = Lines.segmentFromPoints(Vector2D.Unit.PLUS_X, Vector2D.of(1, 1), TEST_PRECISION);
475         final LineConvexSubset c = Lines.segmentFromPoints(Vector2D.Unit.PLUS_X, Vector2D.of(2, 0), TEST_PRECISION);
476 
477         // act
478         connector.connect(Arrays.asList(a, b));
479         connector.connect(Collections.singletonList(c));
480 
481         final List<LinePath> paths = connector.connectAll();
482 
483         // assert
484         Assertions.assertEquals(2, paths.size());
485 
486         assertFinitePath(paths.get(0), Vector2D.ZERO, Vector2D.Unit.PLUS_X, Vector2D.of(1, 1));
487         assertFinitePath(paths.get(1), Vector2D.Unit.PLUS_X, Vector2D.of(2, 0));
488     }
489 
490     @Test
491     void testConnectableSegment_hashCode() {
492         // arrange
493         final LineConvexSubset segA = Lines.segmentFromPoints(Vector2D.ZERO, Vector2D.Unit.PLUS_X, TEST_PRECISION);
494         final LineConvexSubset segB = Lines.segmentFromPoints(Vector2D.Unit.PLUS_X, Vector2D.of(1, 1), TEST_PRECISION);
495 
496         final ConnectableLineSubset a = new ConnectableLineSubset(segA);
497 
498         // act
499         final int hash = a.hashCode();
500 
501         // assert
502         Assertions.assertEquals(hash, a.hashCode());
503 
504         Assertions.assertNotEquals(hash, new ConnectableLineSubset(segB).hashCode());
505         Assertions.assertNotEquals(hash, new ConnectableLineSubset(Vector2D.Unit.PLUS_X).hashCode());
506 
507         Assertions.assertEquals(hash, new ConnectableLineSubset(segA).hashCode());
508     }
509 
510     @Test
511     void testConnectableSegment_equals() {
512         // arrange
513         final LineConvexSubset segA = Lines.segmentFromPoints(Vector2D.ZERO, Vector2D.Unit.PLUS_X, TEST_PRECISION);
514         final LineConvexSubset segB = Lines.segmentFromPoints(Vector2D.Unit.PLUS_X, Vector2D.of(1, 1), TEST_PRECISION);
515 
516         final ConnectableLineSubset a = new ConnectableLineSubset(segA);
517 
518         // act/assert
519         Assertions.assertEquals(a, a);
520 
521         Assertions.assertFalse(a.equals(null));
522         Assertions.assertFalse(a.equals(new Object()));
523 
524         Assertions.assertNotEquals(a, new ConnectableLineSubset(segB));
525         Assertions.assertNotEquals(a, new ConnectableLineSubset(Vector2D.Unit.PLUS_X));
526 
527         Assertions.assertEquals(a, new ConnectableLineSubset(segA));
528     }
529 
530     private static List<LineConvexSubset> shuffle(final List<LineConvexSubset> segments) {
531         return shuffle(segments, 1);
532     }
533 
534     private static List<LineConvexSubset> shuffle(final List<LineConvexSubset> segments, final int seed) {
535         Collections.shuffle(segments, new Random(seed));
536 
537         return segments;
538     }
539 
540     private static void assertFinitePath(final LinePath path, final Vector2D... vertices) {
541         Assertions.assertFalse(path.isInfinite());
542         Assertions.assertTrue(path.isFinite());
543 
544         assertPathVertices(path, vertices);
545     }
546 
547     private static void assertPathVertices(final LinePath path, final Vector2D... vertices) {
548         final List<Vector2D> expectedVertices = Arrays.asList(vertices);
549         final List<Vector2D> actualVertices = path.getVertexSequence();
550 
551         final String msg = "Expected path vertices to equal " + expectedVertices + " but was " + actualVertices;
552         Assertions.assertEquals(expectedVertices.size(), actualVertices.size(), msg);
553 
554         for (int i = 0; i < expectedVertices.size(); ++i) {
555             EuclideanTestUtils.assertCoordinatesEqual(expectedVertices.get(i), actualVertices.get(i), TEST_EPS);
556         }
557     }
558 
559     private static class TestConnector extends AbstractLinePathConnector {
560 
561         @Override
562         protected ConnectableLineSubset selectConnection(final ConnectableLineSubset incoming, final List<ConnectableLineSubset> outgoing) {
563             // just choose the first element
564             return outgoing.get(0);
565         }
566     }
567 }