1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.geometry.core.partitioning;
18
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.Collections;
22 import java.util.List;
23
24 import org.apache.commons.geometry.core.GeometryTestUtils;
25 import org.apache.commons.geometry.core.Region;
26 import org.apache.commons.geometry.core.RegionLocation;
27 import org.apache.commons.geometry.core.Transform;
28 import org.apache.commons.geometry.core.partitioning.test.PartitionTestUtils;
29 import org.apache.commons.geometry.core.partitioning.test.TestLine;
30 import org.apache.commons.geometry.core.partitioning.test.TestLineSegment;
31 import org.apache.commons.geometry.core.partitioning.test.TestPoint2D;
32 import org.apache.commons.geometry.core.partitioning.test.TestTransform2D;
33 import org.junit.jupiter.api.Assertions;
34 import org.junit.jupiter.api.Test;
35
36 class AbstractConvexHyperplaneBoundedRegionTest {
37
38 @Test
39 void testBoundaries_areUnmodifiable() {
40
41 final StubRegion region = new StubRegion(new ArrayList<>());
42 final List<TestLineSegment> boundaries = region.getBoundaries();
43 final TestLineSegment span = TestLine.X_AXIS.span();
44
45
46
47 Assertions.assertThrows(UnsupportedOperationException.class, () -> boundaries.add(span));
48 }
49
50 @Test
51 void testFull() {
52
53 final StubRegion region = new StubRegion(Collections.emptyList());
54
55
56 Assertions.assertTrue(region.isFull());
57 Assertions.assertFalse(region.isEmpty());
58 }
59
60 @Test
61 void testGetBoundarySize() {
62
63 final TestPoint2D p1 = new TestPoint2D(1, 0);
64 final TestPoint2D p2 = new TestPoint2D(2, 0);
65 final TestPoint2D p3 = new TestPoint2D(1, 1);
66
67
68 Assertions.assertEquals(0, new StubRegion(Collections.emptyList()).getBoundarySize(), PartitionTestUtils.EPS);
69 GeometryTestUtils.assertPositiveInfinity(new StubRegion(Collections.singletonList(TestLine.X_AXIS.span())).getBoundarySize());
70 Assertions.assertEquals(2 + Math.sqrt(2), new StubRegion(Arrays.asList(
71 new TestLineSegment(p1, p2),
72 new TestLineSegment(p2, p3),
73 new TestLineSegment(p3, p1)
74 )).getBoundarySize(), PartitionTestUtils.EPS);
75 }
76
77 @Test
78 void testClassify() {
79
80 final TestPoint2D p1 = new TestPoint2D(1, 0);
81 final TestPoint2D p2 = new TestPoint2D(2, 0);
82 final TestPoint2D p3 = new TestPoint2D(1, 1);
83
84 final StubRegion full = new StubRegion(Collections.emptyList());
85 final StubRegion halfSpace = new StubRegion(Collections.singletonList(TestLine.X_AXIS.span()));
86 final StubRegion triangle = new StubRegion(Arrays.asList(
87 new TestLineSegment(p1, p2),
88 new TestLineSegment(p2, p3),
89 new TestLineSegment(p3, p1)
90 ));
91
92
93 checkClassify(full, RegionLocation.INSIDE, TestPoint2D.ZERO, p1, p2, p3);
94
95 checkClassify(halfSpace, RegionLocation.INSIDE, new TestPoint2D(0, 1));
96 checkClassify(halfSpace, RegionLocation.OUTSIDE, new TestPoint2D(0, -1));
97 checkClassify(halfSpace, RegionLocation.BOUNDARY,
98 new TestPoint2D(-1, 0), new TestPoint2D(0, 0), new TestPoint2D(1, 0));
99
100 checkClassify(triangle, RegionLocation.INSIDE, new TestPoint2D(1.25, 0.25));
101 checkClassify(triangle, RegionLocation.OUTSIDE, new TestPoint2D(-1, 0), new TestPoint2D(0, 0), new TestPoint2D(3, 0));
102 checkClassify(triangle, RegionLocation.BOUNDARY, p1, p2, p3);
103 }
104
105 @Test
106 void testProject() {
107
108 final TestPoint2D p1 = new TestPoint2D(1, 0);
109 final TestPoint2D p2 = new TestPoint2D(2, 0);
110 final TestPoint2D p3 = new TestPoint2D(1, 1);
111
112 final StubRegion full = new StubRegion(Collections.emptyList());
113 final StubRegion halfSpace = new StubRegion(Collections.singletonList(TestLine.X_AXIS.span()));
114 final StubRegion triangle = new StubRegion(Arrays.asList(
115 new TestLineSegment(p1, p2),
116 new TestLineSegment(p2, p3),
117 new TestLineSegment(p3, p1)
118 ));
119
120
121 Assertions.assertNull(full.project(TestPoint2D.ZERO));
122 Assertions.assertNull(full.project(new TestPoint2D(1, 1)));
123
124 PartitionTestUtils.assertPointsEqual(TestPoint2D.ZERO, halfSpace.project(new TestPoint2D(0, 1)));
125 PartitionTestUtils.assertPointsEqual(TestPoint2D.ZERO, halfSpace.project(new TestPoint2D(0, 0)));
126 PartitionTestUtils.assertPointsEqual(TestPoint2D.ZERO, halfSpace.project(new TestPoint2D(0, -1)));
127
128 PartitionTestUtils.assertPointsEqual(new TestPoint2D(1.25, 0), triangle.project(new TestPoint2D(1.25, 0.1)));
129 PartitionTestUtils.assertPointsEqual(p1, triangle.project(TestPoint2D.ZERO));
130 PartitionTestUtils.assertPointsEqual(p3, triangle.project(new TestPoint2D(0, 10)));
131 }
132
133 @Test
134 void testTrim() {
135
136 final TestPoint2D p1 = new TestPoint2D(1, 0);
137 final TestPoint2D p2 = new TestPoint2D(2, 0);
138 final TestPoint2D p3 = new TestPoint2D(2, 1);
139 final TestPoint2D p4 = new TestPoint2D(1, 1);
140
141 final StubRegion full = new StubRegion(Collections.emptyList());
142 final StubRegion halfSpace = new StubRegion(Collections.singletonList(TestLine.Y_AXIS.span()));
143 final StubRegion square = new StubRegion(Arrays.asList(
144 new TestLineSegment(p1, p2),
145 new TestLineSegment(p2, p3),
146 new TestLineSegment(p3, p4),
147 new TestLineSegment(p4, p1)
148 ));
149
150 final TestLineSegment segment = new TestLineSegment(new TestPoint2D(-1, 0.5), new TestPoint2D(4, 0.5));
151
152
153 Assertions.assertSame(segment, full.trim(segment));
154
155 final TestLineSegment trimmedA = halfSpace.trim(segment);
156 PartitionTestUtils.assertPointsEqual(new TestPoint2D(-1, 0.5), trimmedA.getStartPoint());
157 PartitionTestUtils.assertPointsEqual(new TestPoint2D(0, 0.5), trimmedA.getEndPoint());
158
159 final TestLineSegment trimmedB = square.trim(segment);
160 PartitionTestUtils.assertPointsEqual(new TestPoint2D(1, 0.5), trimmedB.getStartPoint());
161 PartitionTestUtils.assertPointsEqual(new TestPoint2D(2, 0.5), trimmedB.getEndPoint());
162 }
163
164 @Test
165 void testSplit_full() {
166
167 final StubRegion region = new StubRegion(Collections.emptyList());
168
169 final TestLine splitter = TestLine.X_AXIS;
170
171
172 final Split<StubRegion> split = region.split(splitter);
173
174
175 Assertions.assertEquals(SplitLocation.BOTH, split.getLocation());
176
177 final StubRegion minus = split.getMinus();
178 Assertions.assertEquals(1, minus.getBoundaries().size());
179 checkClassify(minus, RegionLocation.INSIDE, new TestPoint2D(0, 1));
180 checkClassify(minus, RegionLocation.BOUNDARY, new TestPoint2D(0, 0));
181 checkClassify(minus, RegionLocation.OUTSIDE, new TestPoint2D(0, -1));
182
183 final StubRegion plus = split.getPlus();
184 Assertions.assertEquals(1, plus.getBoundaries().size());
185 checkClassify(plus, RegionLocation.OUTSIDE, new TestPoint2D(0, 1));
186 checkClassify(plus, RegionLocation.BOUNDARY, new TestPoint2D(0, 0));
187 checkClassify(plus, RegionLocation.INSIDE, new TestPoint2D(0, -1));
188 }
189
190 @Test
191 void testSplit_parallel_splitterIsOutside_plusOnly() {
192
193 final StubRegion region = new StubRegion(
194 Collections.singletonList(new TestLineSegment(new TestPoint2D(0, 1), new TestPoint2D(1, 1))));
195
196 final TestLine splitter = TestLine.X_AXIS.reverse();
197
198
199 final Split<StubRegion> split = region.split(splitter);
200
201
202 Assertions.assertEquals(SplitLocation.PLUS, split.getLocation());
203
204 Assertions.assertNull(split.getMinus());
205 Assertions.assertSame(region, split.getPlus());
206 }
207
208 @Test
209 void testSplit_parallel_splitterIsOutside_minusOnly() {
210
211 final StubRegion region = new StubRegion(
212 Collections.singletonList(new TestLineSegment(new TestPoint2D(0, 1), new TestPoint2D(1, 1))));
213
214 final TestLine splitter = TestLine.X_AXIS;
215
216
217 final Split<StubRegion> split = region.split(splitter);
218
219
220 Assertions.assertEquals(SplitLocation.MINUS, split.getLocation());
221
222 Assertions.assertSame(region, split.getMinus());
223 Assertions.assertNull(split.getPlus());
224 }
225
226 @Test
227 void testSplit_parallel_splitterIsInside() {
228
229 final StubRegion region = new StubRegion(
230 Collections.singletonList(new TestLineSegment(new TestPoint2D(1, 1), new TestPoint2D(0, 1))));
231
232 final TestLine splitter = TestLine.X_AXIS;
233
234
235 final Split<StubRegion> split = region.split(splitter);
236
237
238 Assertions.assertEquals(SplitLocation.BOTH, split.getLocation());
239
240 final TestPoint2D p1 = new TestPoint2D(0, 1.5);
241 final TestPoint2D p2 = new TestPoint2D(0, 0.5);
242 final TestPoint2D p3 = new TestPoint2D(0, -0.5);
243
244 final StubRegion minus = split.getMinus();
245 Assertions.assertEquals(2, minus.getBoundaries().size());
246 checkClassify(minus, RegionLocation.INSIDE, p2);
247 checkClassify(minus, RegionLocation.OUTSIDE, p1, p3);
248
249 final StubRegion plus = split.getPlus();
250 Assertions.assertEquals(1, plus.getBoundaries().size());
251 checkClassify(plus, RegionLocation.INSIDE, p3);
252 checkClassify(plus, RegionLocation.OUTSIDE, p1, p2);
253 }
254
255 @Test
256 void testSplit_coincident_sameOrientation() {
257
258 final StubRegion region = new StubRegion(Collections.singletonList(TestLine.X_AXIS.span()));
259
260 final TestLine splitter = TestLine.X_AXIS;
261
262
263 final Split<StubRegion> split = region.split(splitter);
264
265
266 Assertions.assertEquals(SplitLocation.MINUS, split.getLocation());
267
268 Assertions.assertSame(region, split.getMinus());
269 Assertions.assertNull(split.getPlus());
270 }
271
272 @Test
273 void testSplit_coincident_oppositeOrientation() {
274
275 final StubRegion region = new StubRegion(Collections.singletonList(TestLine.X_AXIS.span()));
276
277 final TestLine splitter = TestLine.X_AXIS.reverse();
278
279
280 final Split<StubRegion> split = region.split(splitter);
281
282
283 Assertions.assertEquals(SplitLocation.PLUS, split.getLocation());
284
285 Assertions.assertNull(split.getMinus());
286 Assertions.assertSame(region, split.getPlus());
287 }
288
289 @Test
290 void testSplit_finite_both() {
291
292 final TestPoint2D p1 = new TestPoint2D(1, -0.5);
293 final TestPoint2D p2 = new TestPoint2D(2, -0.5);
294 final TestPoint2D p3 = new TestPoint2D(2, 0.5);
295 final TestPoint2D p4 = new TestPoint2D(1, 0.5);
296
297 final StubRegion region = new StubRegion(Arrays.asList(
298 new TestLineSegment(p1, p2),
299 new TestLineSegment(p2, p3),
300 new TestLineSegment(p3, p4),
301 new TestLineSegment(p4, p1)
302 ));
303
304 final TestLine splitter = TestLine.X_AXIS;
305
306
307 final Split<StubRegion> split = region.split(splitter);
308
309
310 Assertions.assertEquals(SplitLocation.BOTH, split.getLocation());
311
312 final StubRegion minus = split.getMinus();
313 Assertions.assertEquals(4, minus.getBoundaries().size());
314 checkClassify(minus, RegionLocation.INSIDE, new TestPoint2D(1.5, 0.25));
315 checkClassify(minus, RegionLocation.BOUNDARY, new TestPoint2D(1.5, 0));
316 checkClassify(minus, RegionLocation.OUTSIDE, new TestPoint2D(1.5, -0.25));
317
318 final StubRegion plus = split.getPlus();
319 Assertions.assertEquals(4, plus.getBoundaries().size());
320 checkClassify(plus, RegionLocation.OUTSIDE, new TestPoint2D(1.5, 0.25));
321 checkClassify(plus, RegionLocation.BOUNDARY, new TestPoint2D(1.5, 0));
322 checkClassify(plus, RegionLocation.INSIDE, new TestPoint2D(1.5, -0.25));
323 }
324
325
326
327
328
329
330
331
332 @Test
333 void testSplit_inconsistentBoundarySplitLocations_minus() {
334
335 final TestLine a = new TestLine(new TestPoint2D(0, 0), new TestPoint2D(1, 1));
336 final TestLine b = new TestLine(new TestPoint2D(-1, 1), new TestPoint2D(0, 0));
337
338 final StubRegion region = new StubRegion(Arrays.asList(
339 new TestLineSegment(-1e-8, Double.POSITIVE_INFINITY, a),
340 new TestLineSegment(Double.NEGATIVE_INFINITY, 1e-8, b)
341 ));
342
343 final List<TestLineSegment> segments = region.getBoundaries();
344 PartitionTestUtils.assertPointsEqual(segments.get(0).getStartPoint(), segments.get(1).getEndPoint());
345
346 final TestLine splitter = new TestLine(new TestPoint2D(0, 0), new TestPoint2D(1, 0));
347
348
349 final Split<StubRegion> split = region.split(splitter);
350
351
352 Assertions.assertEquals(SplitLocation.MINUS, split.getLocation());
353 Assertions.assertSame(region, split.getMinus());
354 Assertions.assertNull(split.getPlus());
355 }
356
357 @Test
358 void testSplit_inconsistentBoundarySplitLocations_plus() {
359
360 final TestLine a = new TestLine(new TestPoint2D(0, 0), new TestPoint2D(1, 1));
361 final TestLine b = new TestLine(new TestPoint2D(-1, 1), new TestPoint2D(0, 0));
362
363 final StubRegion region = new StubRegion(Arrays.asList(
364 new TestLineSegment(-1e-8, Double.POSITIVE_INFINITY, a),
365 new TestLineSegment(Double.NEGATIVE_INFINITY, 1e-8, b)
366 ));
367
368 final List<TestLineSegment> segments = region.getBoundaries();
369 PartitionTestUtils.assertPointsEqual(segments.get(0).getStartPoint(), segments.get(1).getEndPoint());
370
371 final TestLine splitter = new TestLine(new TestPoint2D(1, 0), new TestPoint2D(0, 0));
372
373
374 final Split<StubRegion> split = region.split(splitter);
375
376
377 Assertions.assertEquals(SplitLocation.PLUS, split.getLocation());
378 Assertions.assertNull(split.getMinus());
379 Assertions.assertSame(region, split.getPlus());
380 }
381
382 @Test
383 void testSplit_inconsistentBoundarySplitLocations_trimmedNotNull_minus() {
384
385 final TestLine a = new TestLine(new TestPoint2D(1e-8, 0), new TestPoint2D(1, 1));
386 final TestLine b = new TestLine(new TestPoint2D(-1, 1), new TestPoint2D(-1e-8, 0));
387
388 final StubRegion region = new StubRegion(Arrays.asList(
389 new TestLineSegment(1e-8, Double.POSITIVE_INFINITY, a),
390 new TestLineSegment(Double.NEGATIVE_INFINITY, -1e-8, b)
391 ));
392
393 final List<TestLineSegment> segments = region.getBoundaries();
394 PartitionTestUtils.assertPointsEqual(segments.get(0).getStartPoint(), segments.get(1).getEndPoint());
395
396 final TestLine splitter = new TestLine(new TestPoint2D(0, 0), new TestPoint2D(1, 0));
397
398
399 final Split<StubRegion> split = region.split(splitter);
400
401
402 Assertions.assertEquals(SplitLocation.MINUS, split.getLocation());
403 Assertions.assertSame(region, split.getMinus());
404 Assertions.assertNull(split.getPlus());
405 }
406
407 @Test
408 void testSplit_inconsistentBoundarySplitLocations_trimmedNotNull_plus() {
409
410 final TestLine a = new TestLine(new TestPoint2D(1e-8, 0), new TestPoint2D(1, 1));
411 final TestLine b = new TestLine(new TestPoint2D(-1, 1), new TestPoint2D(-1e-8, 0));
412
413 final StubRegion region = new StubRegion(Arrays.asList(
414 new TestLineSegment(1e-8, Double.POSITIVE_INFINITY, a),
415 new TestLineSegment(Double.NEGATIVE_INFINITY, -1e-8, b)
416 ));
417
418 final List<TestLineSegment> segments = region.getBoundaries();
419 PartitionTestUtils.assertPointsEqual(segments.get(0).getStartPoint(), segments.get(1).getEndPoint());
420
421 final TestLine splitter = new TestLine(new TestPoint2D(0, 0), new TestPoint2D(-1, 0));
422
423
424 final Split<StubRegion> split = region.split(splitter);
425
426
427 Assertions.assertEquals(SplitLocation.PLUS, split.getLocation());
428 Assertions.assertNull(split.getMinus());
429 Assertions.assertSame(region, split.getPlus());
430 }
431
432 @Test
433 void testSplit_inconsistentBoundarySplitLocations_trimmedNotNull_neither() {
434
435 final TestLine a = new TestLine(new TestPoint2D(1e-8, 0), new TestPoint2D(1, 1));
436 final TestLine b = new TestLine(new TestPoint2D(-1, 1), new TestPoint2D(-1e-8, 0));
437
438 final StubRegion region = new StubRegion(Arrays.asList(
439 new TestLineSegment(0, 0, a),
440 new TestLineSegment(0, 0, b)
441 ));
442
443 final List<TestLineSegment> segments = region.getBoundaries();
444 PartitionTestUtils.assertPointsEqual(segments.get(0).getStartPoint(), segments.get(1).getEndPoint());
445
446 final TestLine splitter = new TestLine(new TestPoint2D(0, 0), new TestPoint2D(1, 0));
447
448
449 final Split<StubRegion> split = region.split(splitter);
450
451
452 Assertions.assertEquals(SplitLocation.NEITHER, split.getLocation());
453 Assertions.assertNull(split.getMinus());
454 Assertions.assertNull(split.getPlus());
455 }
456
457 @Test
458 void testTransform_full() {
459
460 final StubRegion region = new StubRegion(Collections.emptyList());
461
462 final Transform<TestPoint2D> transform = new TestTransform2D(p -> new TestPoint2D(p.getX() + 1, p.getY() + 2));
463
464
465 final StubRegion transformed = region.transform(transform);
466
467
468 Assertions.assertTrue(transformed.isFull());
469 Assertions.assertFalse(transformed.isEmpty());
470 }
471
472 @Test
473 void testTransform_infinite() {
474
475 final TestLine line = TestLine.Y_AXIS;
476
477 final StubRegion region = new StubRegion(Collections.singletonList(line.span()));
478
479 final Transform<TestPoint2D> transform = new TestTransform2D(p -> new TestPoint2D(p.getX() + 1, p.getY() + 2));
480
481
482 final StubRegion transformed = region.transform(transform);
483
484
485 final List<TestLineSegment> boundaries = transformed.getBoundaries();
486
487 Assertions.assertEquals(1, boundaries.size());
488
489 final TestLineSegment a = boundaries.get(0);
490 final TestLine aLine = a.getHyperplane();
491 PartitionTestUtils.assertPointsEqual(aLine.getOrigin(), new TestPoint2D(1, 0));
492 Assertions.assertEquals(0.0, aLine.getDirectionX(), PartitionTestUtils.EPS);
493 Assertions.assertEquals(1.0, aLine.getDirectionY(), PartitionTestUtils.EPS);
494
495 GeometryTestUtils.assertNegativeInfinity(a.getStart());
496 GeometryTestUtils.assertPositiveInfinity(a.getEnd());
497 }
498
499 @Test
500 void testTransform_finite() {
501
502 final TestPoint2D p1 = new TestPoint2D(1, 0);
503 final TestPoint2D p2 = new TestPoint2D(2, 0);
504 final TestPoint2D p3 = new TestPoint2D(1, 1);
505
506 final StubRegion region = new StubRegion(Arrays.asList(
507 new TestLineSegment(p1, p2),
508 new TestLineSegment(p2, p3),
509 new TestLineSegment(p3, p1)
510 ));
511
512 final Transform<TestPoint2D> transform = new TestTransform2D(p -> new TestPoint2D(p.getX() + 1, p.getY() + 2));
513
514
515 final StubRegion transformed = region.transform(transform);
516
517
518 final List<TestLineSegment> boundaries = transformed.getBoundaries();
519
520 Assertions.assertEquals(3, boundaries.size());
521
522 final TestLineSegment a = boundaries.get(0);
523 PartitionTestUtils.assertPointsEqual(new TestPoint2D(2, 2), a.getStartPoint());
524 PartitionTestUtils.assertPointsEqual(new TestPoint2D(3, 2), a.getEndPoint());
525
526 final TestLineSegment b = boundaries.get(1);
527 PartitionTestUtils.assertPointsEqual(new TestPoint2D(3, 2), b.getStartPoint());
528 PartitionTestUtils.assertPointsEqual(new TestPoint2D(2, 3), b.getEndPoint());
529
530 final TestLineSegment c = boundaries.get(2);
531 PartitionTestUtils.assertPointsEqual(new TestPoint2D(2, 3), c.getStartPoint());
532 PartitionTestUtils.assertPointsEqual(new TestPoint2D(2, 2), c.getEndPoint());
533 }
534
535 @Test
536 void testTransform_reflection() {
537
538 final TestPoint2D p1 = new TestPoint2D(1, 0);
539 final TestPoint2D p2 = new TestPoint2D(2, 0);
540 final TestPoint2D p3 = new TestPoint2D(1, 1);
541
542 final StubRegion region = new StubRegion(Arrays.asList(
543 new TestLineSegment(p1, p2),
544 new TestLineSegment(p2, p3),
545 new TestLineSegment(p3, p1)
546 ));
547
548 final Transform<TestPoint2D> transform = new TestTransform2D(p -> new TestPoint2D(-p.getX(), p.getY()));
549
550
551 final StubRegion transformed = region.transform(transform);
552
553
554 final List<TestLineSegment> boundaries = transformed.getBoundaries();
555
556 Assertions.assertEquals(3, boundaries.size());
557
558 final TestLineSegment a = boundaries.get(0);
559 PartitionTestUtils.assertPointsEqual(new TestPoint2D(-2, 0), a.getStartPoint());
560 PartitionTestUtils.assertPointsEqual(new TestPoint2D(-1, 0), a.getEndPoint());
561
562 final TestLineSegment b = boundaries.get(1);
563 PartitionTestUtils.assertPointsEqual(new TestPoint2D(-1, 1), b.getStartPoint());
564 PartitionTestUtils.assertPointsEqual(new TestPoint2D(-2, 0), b.getEndPoint());
565
566 final TestLineSegment c = boundaries.get(2);
567 PartitionTestUtils.assertPointsEqual(new TestPoint2D(-1, 0), c.getStartPoint());
568 PartitionTestUtils.assertPointsEqual(new TestPoint2D(-1, 1), c.getEndPoint());
569 }
570
571 @Test
572 void testConvexRegionBoundaryBuilder_full() {
573
574 final StubRegion region = StubRegion.fromBounds(Collections.emptyList());
575
576
577 Assertions.assertSame(StubRegion.FULL, region);
578 }
579
580 @Test
581 void testConvexRegionBoundaryBuilder_singleLine() {
582
583 final StubRegion region = StubRegion.fromBounds(Collections.singletonList(TestLine.Y_AXIS));
584
585
586 Assertions.assertEquals(1, region.getBoundaries().size());
587
588 checkClassify(region, RegionLocation.INSIDE, new TestPoint2D(-1, 0));
589 checkClassify(region, RegionLocation.BOUNDARY, new TestPoint2D(0, 0));
590 checkClassify(region, RegionLocation.OUTSIDE, new TestPoint2D(1, 0));
591 }
592
593 @Test
594 void testConvexRegionBoundaryBuilder_multipleLines() {
595
596 final StubRegion region = StubRegion.fromBounds(Arrays.asList(
597 TestLine.X_AXIS,
598 new TestLine(new TestPoint2D(1, 0), new TestPoint2D(0, 1)),
599 TestLine.Y_AXIS.reverse()
600 ));
601
602
603 Assertions.assertEquals(3, region.getBoundaries().size());
604
605 checkClassify(region, RegionLocation.INSIDE, new TestPoint2D(0.25, 0.25));
606
607 checkClassify(region, RegionLocation.BOUNDARY,
608 TestPoint2D.ZERO, new TestPoint2D(1, 0), new TestPoint2D(1, 0), new TestPoint2D(0.5, 0.5));
609
610 checkClassify(region, RegionLocation.OUTSIDE,
611 new TestPoint2D(-1, 0.5), new TestPoint2D(1, 0.5),
612 new TestPoint2D(0.5, 1), new TestPoint2D(0.5, -1));
613 }
614
615 @Test
616 void testConvexRegionBoundaryBuilder_duplicateLines() {
617
618 final StubRegion region = StubRegion.fromBounds(Arrays.asList(
619 TestLine.Y_AXIS,
620 TestLine.Y_AXIS,
621 new TestLine(new TestPoint2D(0, 0), new TestPoint2D(0, 1)),
622 TestLine.Y_AXIS));
623
624
625 Assertions.assertEquals(1, region.getBoundaries().size());
626
627 checkClassify(region, RegionLocation.INSIDE, new TestPoint2D(-1, 0));
628 checkClassify(region, RegionLocation.BOUNDARY, new TestPoint2D(0, 0));
629 checkClassify(region, RegionLocation.OUTSIDE, new TestPoint2D(1, 0));
630 }
631
632 @Test
633 void testConvexRegionBoundaryBuilder() {
634
635 final List<TestLine> opposites = Arrays.asList(TestLine.X_AXIS, TestLine.X_AXIS.reverse());
636 final List<TestLine> nonConvex = Arrays.asList(
637 TestLine.X_AXIS,
638 TestLine.Y_AXIS,
639 new TestLine(new TestPoint2D(1, 0), new TestPoint2D(0, -1)),
640 new TestLine(new TestPoint2D(1, 0), new TestPoint2D(0, -2)));
641
642
643 Assertions.assertThrows(IllegalArgumentException.class, () -> StubRegion.fromBounds(opposites));
644 Assertions.assertThrows(IllegalArgumentException.class, () -> StubRegion.fromBounds(nonConvex));
645 }
646
647 @Test
648 void testToString() {
649
650 final StubRegion region = new StubRegion(Collections.emptyList());
651
652
653 final String str = region.toString();
654
655
656 Assertions.assertEquals("StubRegion[boundaries= []]", str);
657 }
658
659 private static void checkClassify(final Region<TestPoint2D> region, final RegionLocation loc, final TestPoint2D... pts) {
660 for (final TestPoint2D pt : pts) {
661 Assertions.assertEquals(loc, region.classify(pt), "Unexpected location for point " + pt);
662 }
663 }
664
665 private static final class StubRegion extends AbstractConvexHyperplaneBoundedRegion<TestPoint2D, TestLineSegment> {
666
667 private static final StubRegion FULL = new StubRegion(Collections.emptyList());
668
669 StubRegion(final List<TestLineSegment> boundaries) {
670 super(boundaries);
671 }
672
673 public StubRegion transform(final Transform<TestPoint2D> transform) {
674 return transformInternal(transform, this, TestLineSegment.class, StubRegion::new);
675 }
676
677 @Override
678 public Split<StubRegion> split(final Hyperplane<TestPoint2D> splitter) {
679 return splitInternal(splitter, this, TestLineSegment.class, StubRegion::new);
680 }
681
682 @Override
683 public TestLineSegment trim(final HyperplaneConvexSubset<TestPoint2D> subset) {
684 return (TestLineSegment) super.trim(subset);
685 }
686
687 @Override
688 public double getSize() {
689 throw new UnsupportedOperationException();
690 }
691
692 @Override
693 public TestPoint2D getCentroid() {
694 throw new UnsupportedOperationException();
695 }
696
697 public static StubRegion fromBounds(final Iterable<TestLine> boundingLines) {
698 final List<TestLineSegment> segments = new ConvexRegionBoundaryBuilder<>(TestLineSegment.class)
699 .build(boundingLines);
700 return segments.isEmpty() ? FULL : new StubRegion(segments);
701 }
702 }
703 }