1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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.stream.Collectors;
24
25 import org.apache.commons.geometry.core.GeometryTestUtils;
26 import org.apache.commons.geometry.core.RegionLocation;
27 import org.apache.commons.geometry.core.partitioning.Split;
28 import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
29 import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
30 import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
31 import org.apache.commons.geometry.euclidean.twod.AffineTransformMatrix2D;
32 import org.apache.commons.geometry.euclidean.twod.Line;
33 import org.apache.commons.geometry.euclidean.twod.LineConvexSubset;
34 import org.apache.commons.geometry.euclidean.twod.LinecastChecker2D;
35 import org.apache.commons.geometry.euclidean.twod.Lines;
36 import org.apache.commons.geometry.euclidean.twod.Ray;
37 import org.apache.commons.geometry.euclidean.twod.RegionBSPTree2D;
38 import org.apache.commons.geometry.euclidean.twod.ReverseRay;
39 import org.apache.commons.geometry.euclidean.twod.Segment;
40 import org.apache.commons.geometry.euclidean.twod.Vector2D;
41 import org.apache.commons.geometry.euclidean.twod.path.LinePath.Builder;
42 import org.apache.commons.numbers.angle.PlaneAngleRadians;
43 import org.junit.Assert;
44 import org.junit.Test;
45
46 public class LinePathTest {
47
48 private static final double TEST_EPS = 1e-10;
49
50 private static final DoublePrecisionContext TEST_PRECISION =
51 new EpsilonDoublePrecisionContext(TEST_EPS);
52
53 @Test
54 public void testFrom_empty() {
55
56 final LinePath path = LinePath.from(new ArrayList<>());
57
58
59 Assert.assertTrue(path.isEmpty());
60 Assert.assertFalse(path.isInfinite());
61 Assert.assertTrue(path.isFinite());
62 Assert.assertFalse(path.isClosed());
63
64 Assert.assertEquals(0, path.getSize(), TEST_EPS);
65
66 Assert.assertNull(path.getStart());
67 Assert.assertNull(path.getEnd());
68
69 Assert.assertEquals(0, path.getElements().size());
70
71 Assert.assertEquals(0, path.getVertexSequence().size());
72 }
73
74 @Test
75 public void testFrom_singleFiniteSegment() {
76
77 final Segment a = Lines.segmentFromPoints(Vector2D.ZERO, Vector2D.of(1, 0), TEST_PRECISION);
78
79
80 final LinePath path = LinePath.from(a);
81
82
83 Assert.assertFalse(path.isEmpty());
84 Assert.assertFalse(path.isInfinite());
85 Assert.assertTrue(path.isFinite());
86 Assert.assertFalse(path.isClosed());
87
88 Assert.assertEquals(1, path.getSize(), TEST_EPS);
89
90 Assert.assertSame(a, path.getStart());
91 Assert.assertSame(a, path.getEnd());
92
93 final List<LineConvexSubset> segments = path.getElements();
94 Assert.assertEquals(1, segments.size());
95 Assert.assertSame(a, segments.get(0));
96
97 Assert.assertEquals(Arrays.asList(Vector2D.ZERO, Vector2D.of(1, 0)), path.getVertexSequence());
98 }
99
100 @Test
101 public void testFrom_singleInfiniteSegment() {
102
103 final LineConvexSubset a = Lines.fromPoints(Vector2D.ZERO, Vector2D.of(1, 0), TEST_PRECISION).span();
104
105
106 final LinePath path = LinePath.from(a);
107
108
109 Assert.assertFalse(path.isEmpty());
110 Assert.assertTrue(path.isInfinite());
111 Assert.assertFalse(path.isFinite());
112 Assert.assertFalse(path.isClosed());
113
114 GeometryTestUtils.assertPositiveInfinity(path.getSize());
115
116 Assert.assertSame(a, path.getStart());
117 Assert.assertSame(a, path.getEnd());
118
119 final List<LineConvexSubset> segments = path.getElements();
120 Assert.assertEquals(1, segments.size());
121 Assert.assertSame(a, segments.get(0));
122
123 Assert.assertEquals(0, path.getVertexSequence().size());
124 }
125
126 @Test
127 public void testFrom_finiteSegments_notClosed() {
128
129 final Vector2D p1 = Vector2D.ZERO;
130 final Vector2D p2 = Vector2D.of(1, 0);
131 final Vector2D p3 = Vector2D.of(1, 1);
132
133 final Segment a = Lines.segmentFromPoints(p1, p2, TEST_PRECISION);
134 final Segment b = Lines.segmentFromPoints(p2, p3, TEST_PRECISION);
135
136
137 final LinePath path = LinePath.from(a, b);
138
139
140 Assert.assertFalse(path.isEmpty());
141 Assert.assertFalse(path.isInfinite());
142 Assert.assertTrue(path.isFinite());
143 Assert.assertFalse(path.isClosed());
144
145 Assert.assertEquals(2, path.getSize(), TEST_EPS);
146
147 Assert.assertSame(a, path.getStart());
148 Assert.assertSame(b, path.getEnd());
149
150 final List<LineConvexSubset> segments = path.getElements();
151 Assert.assertEquals(2, segments.size());
152 Assert.assertSame(a, segments.get(0));
153 Assert.assertSame(b, segments.get(1));
154
155 Assert.assertEquals(Arrays.asList(p1, p2, p3), path.getVertexSequence());
156 }
157
158 @Test
159 public void testFrom_finiteSegments_closed() {
160
161 final Vector2D p1 = Vector2D.ZERO;
162 final Vector2D p2 = Vector2D.of(1, 0);
163 final Vector2D p3 = Vector2D.of(1, 1);
164
165 final Segment a = Lines.segmentFromPoints(p1, p2, TEST_PRECISION);
166 final Segment b = Lines.segmentFromPoints(p2, p3, TEST_PRECISION);
167 final Segment c = Lines.segmentFromPoints(p3, p1, TEST_PRECISION);
168
169
170 final LinePath path = LinePath.from(Arrays.asList(a, b, c));
171
172
173 Assert.assertFalse(path.isEmpty());
174 Assert.assertFalse(path.isInfinite());
175 Assert.assertTrue(path.isFinite());
176 Assert.assertTrue(path.isClosed());
177
178 Assert.assertSame(a, path.getStart());
179 Assert.assertSame(c, path.getEnd());
180
181 Assert.assertEquals(2 + Math.sqrt(2), path.getSize(), TEST_EPS);
182
183 final List<LineConvexSubset> segments = path.getElements();
184 Assert.assertEquals(3, segments.size());
185 Assert.assertSame(a, segments.get(0));
186 Assert.assertSame(b, segments.get(1));
187 Assert.assertSame(c, segments.get(2));
188
189 Assert.assertEquals(Arrays.asList(p1, p2, p3, p1), path.getVertexSequence());
190 }
191
192 @Test
193 public void testFrom_infiniteSegments() {
194
195 final ReverseRay a = Lines.fromPointAndAngle(Vector2D.ZERO, 0, TEST_PRECISION)
196 .reverseRayTo(1.0);
197 final Ray b = Lines.fromPointAndAngle(Vector2D.of(1, 0), PlaneAngleRadians.PI_OVER_TWO, TEST_PRECISION)
198 .rayFrom(0.0);
199
200
201 final LinePath path = LinePath.from(Arrays.asList(a, b));
202
203
204 Assert.assertFalse(path.isEmpty());
205 Assert.assertTrue(path.isInfinite());
206 Assert.assertFalse(path.isFinite());
207 Assert.assertFalse(path.isClosed());
208
209 GeometryTestUtils.assertPositiveInfinity(path.getSize());
210
211 Assert.assertSame(a, path.getStart());
212 Assert.assertSame(b, path.getEnd());
213
214 final List<LineConvexSubset> segments = path.getElements();
215 Assert.assertEquals(2, segments.size());
216 Assert.assertSame(a, segments.get(0));
217 Assert.assertSame(b, segments.get(1));
218
219 Assert.assertEquals(Collections.singletonList(Vector2D.of(1, 0)), path.getVertexSequence());
220 }
221
222 @Test
223 public void testFrom_finiteAndInfiniteSegments_startInfinite() {
224
225 final ReverseRay a = Lines.fromPointAndAngle(Vector2D.ZERO, 0, TEST_PRECISION).reverseRayTo(1.0);
226 final Segment b = Lines.segmentFromPoints(Vector2D.of(1, 0), Vector2D.of(1, 1), TEST_PRECISION);
227
228
229 final LinePath path = LinePath.from(Arrays.asList(a, b));
230
231
232 Assert.assertFalse(path.isEmpty());
233 Assert.assertTrue(path.isInfinite());
234 Assert.assertFalse(path.isFinite());
235 Assert.assertFalse(path.isClosed());
236
237 Assert.assertSame(a, path.getStart());
238 Assert.assertSame(b, path.getEnd());
239
240 final List<LineConvexSubset> segments = path.getElements();
241 Assert.assertEquals(2, segments.size());
242 Assert.assertSame(a, segments.get(0));
243 Assert.assertSame(b, segments.get(1));
244
245 Assert.assertEquals(Arrays.asList(Vector2D.of(1, 0), Vector2D.of(1, 1)), path.getVertexSequence());
246 }
247
248 @Test
249 public void testFrom_finiteAndInfiniteSegments_endInfinite() {
250
251 final Segment a = Lines.segmentFromPoints(Vector2D.ZERO, Vector2D.of(1, 0), TEST_PRECISION);
252 final Ray b = Lines.fromPointAndAngle(Vector2D.of(1, 0), PlaneAngleRadians.PI_OVER_TWO, TEST_PRECISION)
253 .rayFrom(0.0);
254
255
256 final LinePath path = LinePath.from(Arrays.asList(a, b));
257
258
259 Assert.assertFalse(path.isEmpty());
260 Assert.assertTrue(path.isInfinite());
261 Assert.assertFalse(path.isFinite());
262 Assert.assertFalse(path.isClosed());
263
264 Assert.assertSame(a, path.getStart());
265 Assert.assertSame(b, path.getEnd());
266
267 final List<LineConvexSubset> segments = path.getElements();
268 Assert.assertEquals(2, segments.size());
269 Assert.assertSame(a, segments.get(0));
270 Assert.assertSame(b, segments.get(1));
271
272 Assert.assertEquals(Arrays.asList(Vector2D.ZERO, Vector2D.of(1, 0)), path.getVertexSequence());
273 }
274
275 @Test
276 public void testFrom_segmentsNotConnected() {
277
278 final Segment a = Lines.segmentFromPoints(Vector2D.ZERO, Vector2D.of(1, 0), TEST_PRECISION);
279 final Segment b = Lines.segmentFromPoints(Vector2D.of(1.01, 0), Vector2D.of(1, 0), TEST_PRECISION);
280
281 final LineConvexSubset c = Lines.fromPointAndAngle(Vector2D.ZERO, 0.0, TEST_PRECISION).span();
282 final LineConvexSubset d = Lines.fromPointAndAngle(Vector2D.of(1, 0), PlaneAngleRadians.PI_OVER_TWO, TEST_PRECISION).span();
283
284
285 GeometryTestUtils.assertThrows(() -> {
286 LinePath.from(a, b);
287 }, IllegalStateException.class);
288
289 GeometryTestUtils.assertThrows(() -> {
290 LinePath.from(c, b);
291 }, IllegalStateException.class);
292
293 GeometryTestUtils.assertThrows(() -> {
294 LinePath.from(a, d);
295 }, IllegalStateException.class);
296 }
297
298 @Test
299 public void testFromVertices_empty() {
300
301 final LinePath path = LinePath.fromVertices(new ArrayList<>(), TEST_PRECISION);
302
303
304 Assert.assertTrue(path.isEmpty());
305 Assert.assertFalse(path.isInfinite());
306 Assert.assertTrue(path.isFinite());
307 Assert.assertFalse(path.isClosed());
308
309 Assert.assertNull(path.getStart());
310 Assert.assertNull(path.getEnd());
311
312 Assert.assertEquals(0, path.getElements().size());
313
314 Assert.assertEquals(0, path.getVertexSequence().size());
315 }
316
317 @Test
318 public void testFromVertices_singleVertex_failsToCreatePath() {
319
320 GeometryTestUtils.assertThrows(() -> {
321 LinePath.fromVertices(Collections.singletonList(Vector2D.ZERO), TEST_PRECISION);
322 }, IllegalStateException.class);
323 }
324
325 @Test
326 public void testFromVertices_twoVertices() {
327
328 final Vector2D p1 = Vector2D.ZERO;
329 final Vector2D p2 = Vector2D.of(1, 0);
330
331
332 final LinePath path = LinePath.fromVertices(Arrays.asList(p1, p2), TEST_PRECISION);
333
334
335 Assert.assertFalse(path.isEmpty());
336 Assert.assertFalse(path.isInfinite());
337 Assert.assertTrue(path.isFinite());
338 Assert.assertFalse(path.isClosed());
339
340 assertFiniteSegment(path.getStart(), p1, p2);
341 Assert.assertSame(path.getStart(), path.getEnd());
342
343 final List<LineConvexSubset> segments = path.getElements();
344 Assert.assertEquals(1, segments.size());
345 assertFiniteSegment(segments.get(0), p1, p2);
346
347 Assert.assertEquals(Arrays.asList(p1, p2), path.getVertexSequence());
348 }
349
350 @Test
351 public void testFromVertices_multipleVertices_notClosed() {
352
353 final Vector2D p1 = Vector2D.ZERO;
354 final Vector2D p2 = Vector2D.of(1, 0);
355 final Vector2D p3 = Vector2D.of(1, 1);
356 final Vector2D p4 = Vector2D.of(0, 1);
357
358
359 final LinePath path = LinePath.fromVertices(Arrays.asList(p1, p2, p3, p4), TEST_PRECISION);
360
361
362 Assert.assertFalse(path.isEmpty());
363 Assert.assertFalse(path.isInfinite());
364 Assert.assertTrue(path.isFinite());
365 Assert.assertFalse(path.isClosed());
366
367 assertFiniteSegment(path.getStart(), p1, p2);
368 assertFiniteSegment(path.getEnd(), p3, p4);
369
370 final List<LineConvexSubset> segments = path.getElements();
371 Assert.assertEquals(3, segments.size());
372 assertFiniteSegment(segments.get(0), p1, p2);
373 assertFiniteSegment(segments.get(1), p2, p3);
374 assertFiniteSegment(segments.get(2), p3, p4);
375
376 Assert.assertEquals(Arrays.asList(p1, p2, p3, p4), path.getVertexSequence());
377 }
378
379 @Test
380 public void testFromVertices_multipleVertices_closed() {
381
382 final Vector2D p1 = Vector2D.ZERO;
383 final Vector2D p2 = Vector2D.of(1, 0);
384 final Vector2D p3 = Vector2D.of(1, 1);
385 final Vector2D p4 = Vector2D.of(0, 1);
386
387
388 final LinePath path = LinePath.fromVertices(Arrays.asList(p1, p2, p3, p4, p1), TEST_PRECISION);
389
390
391 Assert.assertFalse(path.isEmpty());
392 Assert.assertFalse(path.isInfinite());
393 Assert.assertTrue(path.isFinite());
394 Assert.assertTrue(path.isClosed());
395
396 assertFiniteSegment(path.getStart(), p1, p2);
397 assertFiniteSegment(path.getEnd(), p4, p1);
398
399 final List<LineConvexSubset> segments = path.getElements();
400 Assert.assertEquals(4, segments.size());
401 assertFiniteSegment(segments.get(0), p1, p2);
402 assertFiniteSegment(segments.get(1), p2, p3);
403 assertFiniteSegment(segments.get(2), p3, p4);
404 assertFiniteSegment(segments.get(3), p4, p1);
405
406 Assert.assertEquals(Arrays.asList(p1, p2, p3, p4, p1), path.getVertexSequence());
407 }
408
409 @Test
410 public void testFromVertexLoop_empty() {
411
412 final LinePath path = LinePath.fromVertexLoop(new ArrayList<>(), TEST_PRECISION);
413
414
415 Assert.assertTrue(path.isEmpty());
416 Assert.assertFalse(path.isInfinite());
417 Assert.assertTrue(path.isFinite());
418 Assert.assertFalse(path.isClosed());
419
420 Assert.assertNull(path.getStart());
421 Assert.assertNull(path.getEnd());
422
423 Assert.assertEquals(0, path.getElements().size());
424
425 Assert.assertEquals(0, path.getVertexSequence().size());
426 }
427
428 @Test
429 public void testFromVertexLoop_singleVertex_failsToCreatePath() {
430
431 GeometryTestUtils.assertThrows(() -> {
432 LinePath.fromVertexLoop(Collections.singletonList(Vector2D.ZERO), TEST_PRECISION);
433 }, IllegalStateException.class);
434 }
435
436 @Test
437 public void testFromVertexLoop_closeRequired() {
438
439 final Vector2D p1 = Vector2D.ZERO;
440 final Vector2D p2 = Vector2D.of(1, 0);
441 final Vector2D p3 = Vector2D.of(1, 1);
442
443
444 final LinePath path = LinePath.fromVertexLoop(Arrays.asList(p1, p2, p3), TEST_PRECISION);
445
446
447 Assert.assertFalse(path.isEmpty());
448 Assert.assertFalse(path.isInfinite());
449 Assert.assertTrue(path.isFinite());
450 Assert.assertTrue(path.isClosed());
451
452 final List<LineConvexSubset> segments = path.getElements();
453 Assert.assertEquals(3, segments.size());
454 assertFiniteSegment(segments.get(0), p1, p2);
455 assertFiniteSegment(segments.get(1), p2, p3);
456 assertFiniteSegment(segments.get(2), p3, p1);
457
458 Assert.assertEquals(Arrays.asList(p1, p2, p3, p1), path.getVertexSequence());
459 }
460
461 @Test
462 public void testFromVertexLoop_closeNotRequired() {
463
464 final Vector2D p1 = Vector2D.ZERO;
465 final Vector2D p2 = Vector2D.of(1, 0);
466 final Vector2D p3 = Vector2D.of(1, 1);
467
468
469 final LinePath path = LinePath.fromVertexLoop(Arrays.asList(p1, p2, p3, Vector2D.of(0, 0)), TEST_PRECISION);
470
471
472 Assert.assertFalse(path.isEmpty());
473 Assert.assertFalse(path.isInfinite());
474 Assert.assertTrue(path.isFinite());
475 Assert.assertTrue(path.isClosed());
476
477 final List<LineConvexSubset> segments = path.getElements();
478 Assert.assertEquals(3, segments.size());
479 assertFiniteSegment(segments.get(0), p1, p2);
480 assertFiniteSegment(segments.get(1), p2, p3);
481 assertFiniteSegment(segments.get(2), p3, p1);
482
483 Assert.assertEquals(Arrays.asList(p1, p2, p3, p1), path.getVertexSequence());
484 }
485
486 @Test
487 public void testFromVertices_booleanArg() {
488
489 final Vector2D p1 = Vector2D.ZERO;
490 final Vector2D p2 = Vector2D.of(1, 0);
491 final Vector2D p3 = Vector2D.of(0, 1);
492
493
494 final LinePath open = LinePath.fromVertices(Arrays.asList(p1, p2, p3), false, TEST_PRECISION);
495 final LinePath closed = LinePath.fromVertices(Arrays.asList(p1, p2, p3), true, TEST_PRECISION);
496
497
498 Assert.assertFalse(open.isClosed());
499
500 final List<LineConvexSubset> openSegments = open.getElements();
501 Assert.assertEquals(2, openSegments.size());
502 assertFiniteSegment(openSegments.get(0), p1, p2);
503 assertFiniteSegment(openSegments.get(1), p2, p3);
504
505 Assert.assertTrue(closed.isClosed());
506
507 final List<LineConvexSubset> closedSegments = closed.getElements();
508 Assert.assertEquals(3, closedSegments.size());
509 assertFiniteSegment(closedSegments.get(0), p1, p2);
510 assertFiniteSegment(closedSegments.get(1), p2, p3);
511 assertFiniteSegment(closedSegments.get(2), p3, p1);
512 }
513
514 @Test
515 public void testGetElements_listIsNotModifiable() {
516
517 final Segment a = Lines.segmentFromPoints(Vector2D.ZERO, Vector2D.of(1, 0), TEST_PRECISION);
518 final List<LineConvexSubset> inputSegments = new ArrayList<>(Collections.singletonList(a));
519
520
521 final LinePath path = LinePath.from(inputSegments);
522
523 inputSegments.clear();
524
525
526 Assert.assertNotSame(inputSegments, path.getElements());
527 Assert.assertEquals(1, path.getElements().size());
528
529 GeometryTestUtils.assertThrows(() -> {
530 path.getElements().add(a);
531 }, UnsupportedOperationException.class);
532 }
533
534 @Test
535 public void testBoundaryStream() {
536
537 final Segment seg = Lines.segmentFromPoints(Vector2D.ZERO, Vector2D.of(1, 0), TEST_PRECISION);
538 final LinePath path = LinePath.from(Collections.singletonList(seg));
539
540
541 final List<LineConvexSubset> segments = path.boundaryStream().collect(Collectors.toList());
542
543
544 Assert.assertEquals(1, segments.size());
545 Assert.assertSame(seg, segments.get(0));
546 }
547
548 @Test
549 public void testBoundaryStream_empty() {
550
551 final LinePath path = LinePath.empty();
552
553
554 final List<LineConvexSubset> segments = path.boundaryStream().collect(Collectors.toList());
555
556
557 Assert.assertEquals(0, segments.size());
558 }
559
560 @Test
561 public void testTransform_empty() {
562
563 final LinePath path = LinePath.empty();
564 final AffineTransformMatrix2D t = AffineTransformMatrix2D.createTranslation(Vector2D.Unit.PLUS_X);
565
566
567 Assert.assertSame(path, path.transform(t));
568 }
569
570 @Test
571 public void testTransform_finite() {
572
573 final LinePath path = LinePath.builder(TEST_PRECISION)
574 .append(Vector2D.Unit.ZERO)
575 .append(Vector2D.Unit.PLUS_X)
576 .append(Vector2D.Unit.PLUS_Y)
577 .close();
578
579 final AffineTransformMatrix2D t =
580 AffineTransformMatrix2D.createRotation(Vector2D.of(1, 1), PlaneAngleRadians.PI_OVER_TWO);
581
582
583 final LinePath result = path.transform(t);
584
585
586 Assert.assertNotSame(path, result);
587 Assert.assertTrue(result.isClosed());
588 Assert.assertTrue(result.isFinite());
589
590 final List<LineConvexSubset> segments = result.getElements();
591
592 Assert.assertEquals(3, segments.size());
593 assertFiniteSegment(segments.get(0), Vector2D.of(2, 0), Vector2D.of(2, 1));
594 assertFiniteSegment(segments.get(1), Vector2D.of(2, 1), Vector2D.Unit.PLUS_X);
595 assertFiniteSegment(segments.get(2), Vector2D.Unit.PLUS_X, Vector2D.of(2, 0));
596 }
597
598 @Test
599 public void testTransform_infinite() {
600
601 final LinePath path = LinePath.from(
602 Lines.fromPoints(Vector2D.ZERO, Vector2D.Unit.PLUS_Y, TEST_PRECISION).span());
603
604 final AffineTransformMatrix2D t = AffineTransformMatrix2D.createTranslation(Vector2D.Unit.PLUS_X);
605
606
607 final LinePath result = path.transform(t);
608
609
610 Assert.assertNotSame(path, result);
611 Assert.assertFalse(result.isClosed());
612 Assert.assertFalse(result.isFinite());
613
614 final List<LineConvexSubset> segments = result.getElements();
615
616 Assert.assertEquals(1, segments.size());
617 final LineConvexSubset segment = segments.get(0);
618 Assert.assertTrue(segment.isInfinite());
619 Assert.assertNull(segment.getStartPoint());
620 Assert.assertNull(segment.getEndPoint());
621 EuclideanTestUtils.assertCoordinatesEqual(Vector2D.Unit.PLUS_X, segment.getLine().getOrigin(), TEST_EPS);
622 EuclideanTestUtils.assertCoordinatesEqual(Vector2D.Unit.PLUS_Y, segment.getLine().getDirection(), TEST_EPS);
623 }
624
625 @Test
626 public void testReverse_empty() {
627
628 final LinePath path = LinePath.empty();
629
630
631 Assert.assertSame(path, path.reverse());
632 }
633
634 @Test
635 public void testReverse() {
636
637 final LinePath path = LinePath.builder(TEST_PRECISION)
638 .append(Vector2D.Unit.ZERO)
639 .append(Vector2D.Unit.PLUS_X)
640 .append(Vector2D.Unit.PLUS_Y)
641 .close();
642
643
644 final LinePath result = path.reverse();
645
646
647 Assert.assertNotSame(path, result);
648 Assert.assertTrue(result.isClosed());
649 Assert.assertTrue(result.isFinite());
650
651 final List<LineConvexSubset> segments = result.getElements();
652
653 Assert.assertEquals(3, segments.size());
654 assertFiniteSegment(segments.get(0), Vector2D.Unit.ZERO, Vector2D.Unit.PLUS_Y);
655 assertFiniteSegment(segments.get(1), Vector2D.Unit.PLUS_Y, Vector2D.Unit.PLUS_X);
656 assertFiniteSegment(segments.get(2), Vector2D.Unit.PLUS_X, Vector2D.Unit.ZERO);
657 }
658
659 @Test
660 public void testReverse_singleInfinite() {
661
662 final LinePath path = LinePath.from(
663 Lines.fromPoints(Vector2D.ZERO, Vector2D.Unit.PLUS_Y, TEST_PRECISION).span());
664
665
666 final LinePath result = path.reverse();
667
668
669 Assert.assertNotSame(path, result);
670 Assert.assertFalse(result.isClosed());
671 Assert.assertFalse(result.isFinite());
672
673 final List<LineConvexSubset> segments = result.getElements();
674
675 Assert.assertEquals(1, segments.size());
676 final LineConvexSubset segment = segments.get(0);
677 Assert.assertTrue(segment.isInfinite());
678 Assert.assertNull(segment.getStartPoint());
679 Assert.assertNull(segment.getEndPoint());
680 EuclideanTestUtils.assertCoordinatesEqual(Vector2D.Unit.ZERO, segment.getLine().getOrigin(), TEST_EPS);
681 EuclideanTestUtils.assertCoordinatesEqual(Vector2D.Unit.MINUS_Y, segment.getLine().getDirection(), TEST_EPS);
682 }
683
684 @Test
685 public void testReverse_doubleInfinite() {
686
687 final LineConvexSubset a = Lines.fromPoints(Vector2D.ZERO, Vector2D.Unit.PLUS_Y, TEST_PRECISION).reverseRayTo(Vector2D.ZERO);
688 final LineConvexSubset b = Lines.fromPoints(Vector2D.ZERO, Vector2D.Unit.PLUS_X, TEST_PRECISION).rayFrom(Vector2D.ZERO);
689
690 final LinePath path = LinePath.from(a, b);
691
692
693 final LinePath result = path.reverse();
694
695
696 Assert.assertNotSame(path, result);
697 Assert.assertFalse(result.isClosed());
698 Assert.assertFalse(result.isFinite());
699
700 final List<LineConvexSubset> segments = result.getElements();
701 Assert.assertEquals(2, segments.size());
702
703 final LineConvexSubset bResult = segments.get(0);
704 Assert.assertTrue(bResult.isInfinite());
705 Assert.assertNull(bResult.getStartPoint());
706 EuclideanTestUtils.assertCoordinatesEqual(Vector2D.ZERO, bResult.getEndPoint(), TEST_EPS);
707 EuclideanTestUtils.assertCoordinatesEqual(Vector2D.ZERO, bResult.getLine().getOrigin(), TEST_EPS);
708 EuclideanTestUtils.assertCoordinatesEqual(Vector2D.Unit.MINUS_X, bResult.getLine().getDirection(), TEST_EPS);
709
710 final LineConvexSubset aResult = segments.get(1);
711 Assert.assertTrue(aResult.isInfinite());
712 EuclideanTestUtils.assertCoordinatesEqual(Vector2D.ZERO, aResult.getStartPoint(), TEST_EPS);
713 Assert.assertNull(aResult.getEndPoint());
714 EuclideanTestUtils.assertCoordinatesEqual(Vector2D.ZERO, aResult.getLine().getOrigin(), TEST_EPS);
715 EuclideanTestUtils.assertCoordinatesEqual(Vector2D.Unit.MINUS_Y, aResult.getLine().getDirection(), TEST_EPS);
716 }
717
718 @Test
719 public void testToTree() {
720
721 final LinePath path = LinePath.builder(TEST_PRECISION)
722 .appendVertices(Vector2D.ZERO, Vector2D.Unit.PLUS_X, Vector2D.of(1, 1), Vector2D.of(0, 1))
723 .close();
724
725
726 final RegionBSPTree2D tree = path.toTree();
727
728
729 Assert.assertEquals(1, tree.getSize(), TEST_EPS);
730 Assert.assertEquals(4, tree.getBoundarySize(), TEST_EPS);
731
732 Assert.assertEquals(RegionLocation.INSIDE, tree.classify(Vector2D.of(0.5, 0.5)));
733
734 Assert.assertEquals(RegionLocation.OUTSIDE, tree.classify(Vector2D.of(0.5, -1)));
735 Assert.assertEquals(RegionLocation.OUTSIDE, tree.classify(Vector2D.of(0.5, 2)));
736 Assert.assertEquals(RegionLocation.OUTSIDE, tree.classify(Vector2D.of(-1, 0.5)));
737 Assert.assertEquals(RegionLocation.OUTSIDE, tree.classify(Vector2D.of(2, 0.5)));
738 }
739
740 @Test
741 public void testSimplify() {
742
743 final Builder builder = LinePath.builder(TEST_PRECISION);
744
745 final LinePath path = builder.appendVertices(
746 Vector2D.of(-1, 0),
747 Vector2D.ZERO,
748 Vector2D.of(1, 0),
749 Vector2D.of(1, 1),
750 Vector2D.of(1, 2))
751 .build();
752
753
754 final LinePath result = path.simplify();
755
756
757 final List<LineConvexSubset> segments = result.getElements();
758 Assert.assertEquals(2, segments.size());
759 assertFiniteSegment(segments.get(0), Vector2D.of(-1, 0), Vector2D.of(1, 0));
760 assertFiniteSegment(segments.get(1), Vector2D.of(1, 0), Vector2D.of(1, 2));
761 }
762
763 @Test
764 public void testSimplify_startAndEndCombined() {
765
766 final Builder builder = LinePath.builder(TEST_PRECISION);
767
768 final LinePath path = builder.appendVertices(
769 Vector2D.ZERO,
770 Vector2D.of(1, 0),
771 Vector2D.of(0, 1),
772 Vector2D.of(-1, 0))
773 .close();
774
775
776 final LinePath result = path.simplify();
777
778
779 Assert.assertNotSame(path, result);
780 Assert.assertTrue(result.isClosed());
781 Assert.assertFalse(result.isInfinite());
782
783 final List<LineConvexSubset> segments = result.getElements();
784 Assert.assertEquals(3, segments.size());
785 assertFiniteSegment(segments.get(0), Vector2D.of(-1, 0), Vector2D.of(1, 0));
786 assertFiniteSegment(segments.get(1), Vector2D.of(1, 0), Vector2D.of(0, 1));
787 assertFiniteSegment(segments.get(2), Vector2D.of(0, 1), Vector2D.of(-1, 0));
788 }
789
790 @Test
791 public void testSimplify_empty() {
792
793 final Builder builder = LinePath.builder(TEST_PRECISION);
794
795 final LinePath path = builder.build();
796
797
798 final LinePath result = path.simplify();
799
800
801 Assert.assertNotSame(path, result);
802 Assert.assertFalse(result.isClosed());
803 Assert.assertFalse(result.isInfinite());
804
805 final List<LineConvexSubset> segments = result.getElements();
806 Assert.assertEquals(0, segments.size());
807 }
808
809 @Test
810 public void testSimplify_infiniteSegment() {
811
812 final Line line = Lines.fromPointAndAngle(Vector2D.ZERO, 0.0, TEST_PRECISION);
813
814 final Builder builder = LinePath.builder(TEST_PRECISION);
815 final LinePath path = builder
816 .append(line.span())
817 .build();
818
819
820 final LinePath result = path.simplify();
821
822
823 Assert.assertNotSame(path, result);
824 Assert.assertFalse(result.isClosed());
825 Assert.assertTrue(result.isInfinite());
826
827 Assert.assertNotNull(path.getStart());
828 Assert.assertNotNull(path.getEnd());
829 Assert.assertSame(path.getStart(), path.getEnd());
830
831 final List<LineConvexSubset> segments = result.getElements();
832 Assert.assertEquals(1, segments.size());
833 Assert.assertSame(line, segments.get(0).getLine());
834 }
835
836 @Test
837 public void testSimplify_combinedInfiniteSegment() {
838
839 final Line line = Lines.fromPointAndAngle(Vector2D.ZERO, 0.0, TEST_PRECISION);
840 final Split<LineConvexSubset> split = line.span().split(
841 Lines.fromPointAndAngle(Vector2D.ZERO, PlaneAngleRadians.PI_OVER_TWO, TEST_PRECISION));
842
843 final Builder builder = LinePath.builder(TEST_PRECISION);
844 final LinePath path = builder
845 .append(split.getMinus())
846 .append(split.getPlus())
847 .build();
848
849
850 final LinePath result = path.simplify();
851
852
853 Assert.assertNotSame(path, result);
854 Assert.assertFalse(result.isClosed());
855 Assert.assertTrue(result.isInfinite());
856
857 Assert.assertNotNull(result.getStart());
858 Assert.assertNotNull(result.getEnd());
859 Assert.assertSame(result.getStart(), result.getEnd());
860
861 final List<LineConvexSubset> segments = result.getElements();
862 Assert.assertEquals(1, segments.size());
863 Assert.assertSame(line, segments.get(0).getLine());
864 }
865
866 @Test
867 public void testSimplify_startAndEndNotCombinedWhenNotClosed() {
868
869 final Line xAxis = Lines.fromPointAndAngle(Vector2D.ZERO, 0.0, TEST_PRECISION);
870 final Builder builder = LinePath.builder(TEST_PRECISION);
871
872 final LinePath path = builder
873 .append(xAxis.segment(0, 1))
874 .appendVertices(
875 Vector2D.of(2, 1),
876 Vector2D.of(3, 0))
877 .append(xAxis.segment(3, 4))
878 .build();
879
880
881 final LinePath result = path.simplify();
882
883
884 Assert.assertNotSame(path, result);
885 Assert.assertFalse(result.isClosed());
886 Assert.assertFalse(result.isInfinite());
887
888 final List<LineConvexSubset> segments = result.getElements();
889 Assert.assertEquals(4, segments.size());
890 assertFiniteSegment(segments.get(0), Vector2D.ZERO, Vector2D.of(1, 0));
891 assertFiniteSegment(segments.get(1), Vector2D.of(1, 0), Vector2D.of(2, 1));
892 assertFiniteSegment(segments.get(2), Vector2D.of(2, 1), Vector2D.of(3, 0));
893 assertFiniteSegment(segments.get(3), Vector2D.of(3, 0), Vector2D.of(4, 0));
894 }
895
896 @Test
897 public void testSimplify_subsequentCallsToReturnedObjectReturnSameObject() {
898
899 final Builder builder = LinePath.builder(TEST_PRECISION);
900 final LinePath path = builder.appendVertices(
901 Vector2D.ZERO,
902 Vector2D.of(1, 0),
903 Vector2D.of(2, 0))
904 .build();
905
906
907 final LinePath result = path.simplify();
908
909
910 Assert.assertNotSame(path, result);
911 Assert.assertSame(result, result.simplify());
912 }
913
914 @Test
915 public void testLinecast_empty() {
916
917 final LinePath path = LinePath.empty();
918
919
920 LinecastChecker2D.with(path)
921 .expectNothing()
922 .whenGiven(Lines.fromPoints(Vector2D.ZERO, Vector2D.Unit.PLUS_X, TEST_PRECISION));
923
924 LinecastChecker2D.with(path)
925 .expectNothing()
926 .whenGiven(Lines.segmentFromPoints(Vector2D.Unit.MINUS_X, Vector2D.Unit.PLUS_X, TEST_PRECISION));
927 }
928
929 @Test
930 public void testLinecast() {
931
932 final LinePath path = LinePath.fromVertexLoop(Arrays.asList(
933 Vector2D.ZERO, Vector2D.of(1, 0),
934 Vector2D.of(1, 1), Vector2D.of(0, 1)
935 ), TEST_PRECISION);
936
937
938 LinecastChecker2D.with(path)
939 .expectNothing()
940 .whenGiven(Lines.fromPoints(Vector2D.of(0, 5), Vector2D.of(1, 6), TEST_PRECISION));
941
942 LinecastChecker2D.with(path)
943 .expect(Vector2D.ZERO, Vector2D.Unit.MINUS_X)
944 .and(Vector2D.ZERO, Vector2D.Unit.MINUS_Y)
945 .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_Y)
946 .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X)
947 .whenGiven(Lines.fromPoints(Vector2D.ZERO, Vector2D.of(1, 1), TEST_PRECISION));
948
949 LinecastChecker2D.with(path)
950 .expect(Vector2D.of(1, 1), Vector2D.Unit.PLUS_Y)
951 .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X)
952 .whenGiven(Lines.segmentFromPoints(Vector2D.of(0.5, 0.5), Vector2D.of(1, 1), TEST_PRECISION));
953 }
954
955 @Test
956 public void testToString() {
957
958 final Line yAxis = Lines.fromPoints(Vector2D.ZERO, Vector2D.Unit.PLUS_Y, TEST_PRECISION);
959 final Line xAxis = Lines.fromPoints(Vector2D.ZERO, Vector2D.Unit.PLUS_X, TEST_PRECISION);
960
961 final LinePath empty = LinePath.empty();
962
963 final LinePath singleFullSegment = LinePath.from(xAxis.span());
964 final LinePath singleFiniteSegment = LinePath.from(
965 Lines.segmentFromPoints(Vector2D.ZERO, Vector2D.Unit.PLUS_X, TEST_PRECISION));
966
967 final LinePath startOpenPath = LinePath.builder(TEST_PRECISION)
968 .append(xAxis.reverseRayTo(Vector2D.Unit.PLUS_X))
969 .append(Vector2D.of(1, 1))
970 .build();
971
972 final LinePath endOpenPath = LinePath.builder(TEST_PRECISION)
973 .append(Vector2D.of(0, 1))
974 .append(Vector2D.ZERO)
975 .append(xAxis.rayFrom(Vector2D.ZERO))
976 .build();
977
978 final LinePath doubleOpenPath = LinePath.from(yAxis.reverseRayTo(Vector2D.ZERO),
979 xAxis.rayFrom(Vector2D.ZERO));
980
981 final LinePath nonOpenPath = LinePath.builder(TEST_PRECISION)
982 .append(Vector2D.ZERO)
983 .append(Vector2D.Unit.PLUS_X)
984 .append(Vector2D.of(1, 1))
985 .build();
986
987
988 final String emptyStr = empty.toString();
989 GeometryTestUtils.assertContains("LinePath[empty= true", emptyStr);
990
991 final String singleFullStr = singleFullSegment.toString();
992 GeometryTestUtils.assertContains("LinePath[single= LineSpanningSubset[", singleFullStr);
993
994 final String singleFiniteStr = singleFiniteSegment.toString();
995 GeometryTestUtils.assertContains("LinePath[single= Segment[", singleFiniteStr);
996
997 final String startOpenStr = startOpenPath.toString();
998 GeometryTestUtils.assertContains("LinePath[startDirection= ", startOpenStr);
999 GeometryTestUtils.assertContains("vertexSequence=", startOpenStr);
1000
1001 final String endOpenStr = endOpenPath.toString();
1002 GeometryTestUtils.assertContains("LinePath[vertexSequence= ", endOpenStr);
1003 GeometryTestUtils.assertContains("endDirection= ", endOpenStr);
1004
1005 final String doubleOpenStr = doubleOpenPath.toString();
1006 GeometryTestUtils.assertContains("startDirection= ", doubleOpenStr);
1007 GeometryTestUtils.assertContains("vertexSequence= ", doubleOpenStr);
1008 GeometryTestUtils.assertContains("endDirection= ", doubleOpenStr);
1009
1010 final String nonOpenStr = nonOpenPath.toString();
1011 GeometryTestUtils.assertContains("LinePath[vertexSequence= ", nonOpenStr);
1012 }
1013
1014 @Test
1015 public void testBuilder_prependAndAppend_segments() {
1016
1017 final Vector2D p1 = Vector2D.ZERO;
1018 final Vector2D p2 = Vector2D.of(1, 0);
1019 final Vector2D p3 = Vector2D.of(1, 1);
1020 final Vector2D p4 = Vector2D.of(1, 0);
1021
1022 final Segment a = Lines.segmentFromPoints(p1, p2, TEST_PRECISION);
1023 final Segment b = Lines.segmentFromPoints(p2, p3, TEST_PRECISION);
1024 final Segment c = Lines.segmentFromPoints(p3, p4, TEST_PRECISION);
1025 final Segment d = Lines.segmentFromPoints(p4, p1, TEST_PRECISION);
1026
1027 final Builder builder = LinePath.builder(null);
1028
1029
1030 builder.prepend(b)
1031 .append(c)
1032 .prepend(a)
1033 .append(d);
1034
1035 final LinePath path = builder.build();
1036
1037
1038 final List<LineConvexSubset> segments = path.getElements();
1039 Assert.assertEquals(4, segments.size());
1040 Assert.assertSame(a, segments.get(0));
1041 Assert.assertSame(b, segments.get(1));
1042 Assert.assertSame(c, segments.get(2));
1043 Assert.assertSame(d, segments.get(3));
1044 }
1045
1046 @Test
1047 public void testBuilder_prependAndAppend_disconnectedSegments() {
1048
1049 final Segment a = Lines.segmentFromPoints(Vector2D.ZERO, Vector2D.of(1, 0), TEST_PRECISION);
1050
1051 final Builder builder = LinePath.builder(null);
1052 builder.append(a);
1053
1054
1055 GeometryTestUtils.assertThrows(() -> {
1056 builder.append(a);
1057 }, IllegalStateException.class);
1058
1059 GeometryTestUtils.assertThrows(() -> {
1060 builder.prepend(a);
1061 }, IllegalStateException.class);
1062 }
1063
1064 @Test
1065 public void testBuilder_prependAndAppend_vertices() {
1066
1067 final Vector2D p1 = Vector2D.ZERO;
1068 final Vector2D p2 = Vector2D.of(1, 0);
1069 final Vector2D p3 = Vector2D.of(1, 1);
1070 final Vector2D p4 = Vector2D.of(1, 0);
1071
1072 final Builder builder = LinePath.builder(TEST_PRECISION);
1073
1074
1075 builder.prepend(p2)
1076 .append(p3)
1077 .prepend(p1)
1078 .append(p4)
1079 .append(p1);
1080
1081 final LinePath path = builder.build();
1082
1083
1084 final List<LineConvexSubset> segments = path.getElements();
1085 Assert.assertEquals(4, segments.size());
1086 assertFiniteSegment(segments.get(0), p1, p2);
1087 assertFiniteSegment(segments.get(1), p2, p3);
1088 assertFiniteSegment(segments.get(2), p3, p4);
1089 assertFiniteSegment(segments.get(3), p4, p1);
1090 }
1091
1092 @Test
1093 public void testBuilder_prependAndAppend_noPrecisionSpecified() {
1094
1095 final Vector2D p = Vector2D.ZERO;
1096 final Builder builder = LinePath.builder(null);
1097
1098 final String msg = "Unable to create line segment: no vertex precision specified";
1099
1100
1101 GeometryTestUtils.assertThrows(() -> {
1102 builder.append(p);
1103 }, IllegalStateException.class, msg);
1104
1105 GeometryTestUtils.assertThrows(() -> {
1106 builder.prepend(p);
1107 }, IllegalStateException.class, msg);
1108 }
1109
1110 @Test
1111 public void testBuilder_prependAndAppend_addingToInfinitePath() {
1112
1113 final Vector2D p = Vector2D.Unit.PLUS_X;
1114 final Builder builder = LinePath.builder(TEST_PRECISION);
1115
1116 builder.append(Lines.fromPointAndAngle(Vector2D.ZERO, 0.0, TEST_PRECISION).span());
1117
1118
1119 GeometryTestUtils.assertThrows(() -> {
1120 builder.append(p);
1121 }, IllegalStateException.class);
1122
1123 GeometryTestUtils.assertThrows(() -> {
1124 builder.prepend(p);
1125 }, IllegalStateException.class);
1126 }
1127
1128 @Test
1129 public void testBuilder_prependAndAppend_ignoresEquivalentVertices() {
1130
1131 final Vector2D p = Vector2D.ZERO;
1132
1133 final Builder builder = LinePath.builder(TEST_PRECISION);
1134 builder.append(p);
1135
1136
1137 builder.append(p)
1138 .prepend(p)
1139 .append(Vector2D.of(0, 1e-20))
1140 .prepend(Vector2D.of(1e-20, 0));
1141
1142 builder.append(Vector2D.Unit.PLUS_X);
1143
1144
1145 final LinePath path = builder.build();
1146
1147 final List<LineConvexSubset> segments = path.getElements();
1148 Assert.assertEquals(1, segments.size());
1149 assertFiniteSegment(segments.get(0), p, Vector2D.Unit.PLUS_X);
1150 }
1151
1152 @Test
1153 public void testBuilder_prependAndAppend_mixedVerticesAndSegments() {
1154
1155 final Vector2D p1 = Vector2D.ZERO;
1156 final Vector2D p2 = Vector2D.of(1, 0);
1157 final Vector2D p3 = Vector2D.of(1, 1);
1158 final Vector2D p4 = Vector2D.of(0, 1);
1159
1160 final Segment a = Lines.segmentFromPoints(p1, p2, TEST_PRECISION);
1161 final Segment c = Lines.segmentFromPoints(p3, p4, TEST_PRECISION);
1162
1163 final Builder builder = LinePath.builder(TEST_PRECISION);
1164
1165
1166 builder.prepend(p2)
1167 .append(p3)
1168 .append(c)
1169 .prepend(a)
1170 .append(p1);
1171
1172 final LinePath path = builder.build();
1173
1174
1175 final List<LineConvexSubset> segments = path.getElements();
1176 Assert.assertEquals(4, segments.size());
1177 assertFiniteSegment(segments.get(0), p1, p2);
1178 assertFiniteSegment(segments.get(1), p2, p3);
1179 assertFiniteSegment(segments.get(2), p3, p4);
1180 assertFiniteSegment(segments.get(3), p4, p1);
1181 }
1182
1183 @Test
1184 public void testBuilder_appendVertices() {
1185
1186 final Vector2D p1 = Vector2D.ZERO;
1187 final Vector2D p2 = Vector2D.of(1, 0);
1188 final Vector2D p3 = Vector2D.of(1, 1);
1189 final Vector2D p4 = Vector2D.of(0, 1);
1190
1191 final Builder builder = LinePath.builder(TEST_PRECISION);
1192
1193
1194 builder.appendVertices(p1, p2)
1195 .appendVertices(Arrays.asList(p3, p4, p1));
1196
1197 final LinePath path = builder.build();
1198
1199
1200 final List<LineConvexSubset> segments = path.getElements();
1201 Assert.assertEquals(4, segments.size());
1202 assertFiniteSegment(segments.get(0), p1, p2);
1203 assertFiniteSegment(segments.get(1), p2, p3);
1204 assertFiniteSegment(segments.get(2), p3, p4);
1205 assertFiniteSegment(segments.get(3), p4, p1);
1206 }
1207
1208 @Test
1209 public void testBuilder_prependVertices() {
1210
1211 final Vector2D p1 = Vector2D.ZERO;
1212 final Vector2D p2 = Vector2D.of(1, 0);
1213 final Vector2D p3 = Vector2D.of(1, 1);
1214 final Vector2D p4 = Vector2D.of(0, 1);
1215
1216 final Builder builder = LinePath.builder(TEST_PRECISION);
1217
1218
1219 builder.prependVertices(p3, p4, p1)
1220 .prependVertices(Arrays.asList(p1, p2));
1221
1222 final LinePath path = builder.build();
1223
1224
1225 final List<LineConvexSubset> segments = path.getElements();
1226 Assert.assertEquals(4, segments.size());
1227 assertFiniteSegment(segments.get(0), p1, p2);
1228 assertFiniteSegment(segments.get(1), p2, p3);
1229 assertFiniteSegment(segments.get(2), p3, p4);
1230 assertFiniteSegment(segments.get(3), p4, p1);
1231 }
1232
1233 @Test
1234 public void testBuilder_close_notYetClosed() {
1235
1236 final Vector2D p1 = Vector2D.ZERO;
1237 final Vector2D p2 = Vector2D.of(1, 0);
1238 final Vector2D p3 = Vector2D.of(1, 1);
1239
1240 final Builder builder = LinePath.builder(TEST_PRECISION);
1241
1242
1243 builder.append(p1)
1244 .append(p2)
1245 .append(p3);
1246
1247 final LinePath path = builder.close();
1248
1249
1250 final List<LineConvexSubset> segments = path.getElements();
1251 Assert.assertEquals(3, segments.size());
1252 assertFiniteSegment(segments.get(0), p1, p2);
1253 assertFiniteSegment(segments.get(1), p2, p3);
1254 assertFiniteSegment(segments.get(2), p3, p1);
1255 }
1256
1257 @Test
1258 public void testBuilder_close_alreadyClosed() {
1259
1260 final Vector2D p1 = Vector2D.ZERO;
1261 final Vector2D p2 = Vector2D.of(1, 0);
1262 final Vector2D p3 = Vector2D.of(1, 1);
1263
1264 final Builder builder = LinePath.builder(TEST_PRECISION);
1265
1266
1267 builder.append(p1)
1268 .append(p2)
1269 .append(p3)
1270 .append(p1);
1271
1272 final LinePath path = builder.close();
1273
1274
1275 final List<LineConvexSubset> segments = path.getElements();
1276 Assert.assertEquals(3, segments.size());
1277 assertFiniteSegment(segments.get(0), p1, p2);
1278 assertFiniteSegment(segments.get(1), p2, p3);
1279 assertFiniteSegment(segments.get(2), p3, p1);
1280 }
1281
1282 @Test
1283 public void testBuilder_close_infiniteSegmentAtStart() {
1284
1285 final Builder builder = LinePath.builder(TEST_PRECISION);
1286
1287 builder.append(Lines.fromPointAndAngle(Vector2D.ZERO, 0.0, TEST_PRECISION)
1288 .reverseRayTo(1))
1289 .append(Vector2D.of(1, 1));
1290
1291
1292 GeometryTestUtils.assertThrows(builder::close, IllegalStateException.class,
1293 "Unable to close line path: line path is infinite");
1294 }
1295
1296 @Test
1297 public void testBuilder_close_infiniteSegmentAtEnd() {
1298
1299 final Builder builder = LinePath.builder(TEST_PRECISION);
1300
1301 builder
1302 .append(Vector2D.ZERO)
1303 .append(Vector2D.Unit.PLUS_X)
1304 .append(Lines.fromPointAndAngle(Vector2D.Unit.PLUS_X, PlaneAngleRadians.PI_OVER_TWO, TEST_PRECISION)
1305 .rayFrom(0));
1306
1307
1308 GeometryTestUtils.assertThrows(builder::close, IllegalStateException.class,
1309 "Unable to close line path: line path is infinite");
1310 }
1311
1312 @Test
1313 public void testBuilder_close_emptyPath() {
1314
1315 final Builder builder = LinePath.builder(TEST_PRECISION);
1316
1317
1318 final LinePath path = builder.close();
1319
1320
1321 Assert.assertEquals(0, path.getElements().size());
1322 }
1323
1324 @Test
1325 public void testBuilder_close_obtuseTriangle() {
1326
1327 final Builder builder = LinePath.builder(TEST_PRECISION);
1328 builder.appendVertices(Vector2D.ZERO, Vector2D.of(1, 0), Vector2D.of(2, 1));
1329
1330
1331 final LinePath path = builder.close();
1332
1333
1334 Assert.assertEquals(3, path.getElements().size());
1335 assertFiniteSegment(path.getElements().get(0), Vector2D.ZERO, Vector2D.of(1, 0));
1336 assertFiniteSegment(path.getElements().get(1), Vector2D.of(1, 0), Vector2D.of(2, 1));
1337 assertFiniteSegment(path.getElements().get(2), Vector2D.of(2, 1), Vector2D.ZERO);
1338 }
1339
1340 private static void assertFiniteSegment(final LineConvexSubset segment, final Vector2D start, final Vector2D end) {
1341 Assert.assertFalse(segment.isInfinite());
1342 Assert.assertTrue(segment.isFinite());
1343
1344 EuclideanTestUtils.assertCoordinatesEqual(start, segment.getStartPoint(), TEST_EPS);
1345 EuclideanTestUtils.assertCoordinatesEqual(end, segment.getEndPoint(), TEST_EPS);
1346 }
1347 }