1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.geometry.euclidean.oned;
18
19 import java.util.List;
20
21 import org.apache.commons.geometry.core.GeometryTestUtils;
22 import org.apache.commons.geometry.core.RegionLocation;
23 import org.apache.commons.geometry.core.Transform;
24 import org.apache.commons.geometry.core.partitioning.HyperplaneConvexSubset;
25 import org.apache.commons.geometry.core.partitioning.HyperplaneLocation;
26 import org.apache.commons.geometry.core.partitioning.Split;
27 import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
28 import org.apache.commons.numbers.core.Precision;
29 import org.junit.jupiter.api.Assertions;
30 import org.junit.jupiter.api.Test;
31
32 class OrientedPointTest {
33
34 private static final double TEST_EPS = 1e-15;
35
36 private static final Precision.DoubleEquivalence TEST_PRECISION =
37 Precision.doubleEquivalenceOfEpsilon(TEST_EPS);
38
39 @Test
40 void testGetDirection() {
41
42 EuclideanTestUtils.assertCoordinatesEqual(Vector1D.Unit.PLUS,
43 OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), true, TEST_PRECISION).getDirection(),
44 TEST_EPS);
45 EuclideanTestUtils.assertCoordinatesEqual(Vector1D.Unit.MINUS,
46 OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), false, TEST_PRECISION).getDirection(),
47 TEST_EPS);
48 }
49
50 @Test
51 void testReverse() {
52
53 assertOrientedPoint(OrientedPoints.fromPointAndDirection(Vector1D.of(0), true, TEST_PRECISION).reverse(),
54 0.0, false, TEST_PRECISION);
55 assertOrientedPoint(OrientedPoints.fromPointAndDirection(Vector1D.of(-1), false, TEST_PRECISION).reverse(),
56 -1.0, true, TEST_PRECISION);
57 assertOrientedPoint(OrientedPoints.fromPointAndDirection(Vector1D.of(1), true, TEST_PRECISION).reverse(),
58 1.0, false, TEST_PRECISION);
59
60 assertOrientedPoint(OrientedPoints.fromPointAndDirection(Vector1D.of(0), true, TEST_PRECISION).reverse().reverse(),
61 0.0, true, TEST_PRECISION);
62 assertOrientedPoint(OrientedPoints.fromPointAndDirection(Vector1D.of(-1), false, TEST_PRECISION).reverse().reverse(),
63 -1.0, false, TEST_PRECISION);
64 assertOrientedPoint(OrientedPoints.fromPointAndDirection(Vector1D.of(1), true, TEST_PRECISION).reverse().reverse(),
65 1.0, true, TEST_PRECISION);
66 }
67
68 @Test
69 void testTransform() {
70
71 final AffineTransformMatrix1D scaleAndTranslate = AffineTransformMatrix1D
72 .createScale(0.5)
73 .translate(-10);
74
75 final AffineTransformMatrix1D reflect = AffineTransformMatrix1D.createScale(-2);
76
77 final OrientedPoint a = OrientedPoints.createPositiveFacing(Vector1D.of(2.0), TEST_PRECISION);
78 final OrientedPoint b = OrientedPoints.createNegativeFacing(Vector1D.of(-3.0), TEST_PRECISION);
79
80
81 assertOrientedPoint(a.transform(scaleAndTranslate), -9.0, true, TEST_PRECISION);
82 assertOrientedPoint(b.transform(scaleAndTranslate), -11.5, false, TEST_PRECISION);
83
84 assertOrientedPoint(a.transform(reflect), -4.0, false, TEST_PRECISION);
85 assertOrientedPoint(b.transform(reflect), 6.0, true, TEST_PRECISION);
86 }
87
88 @Test
89 void testTransform_locationAtInfinity() {
90
91 final OrientedPoint pos = OrientedPoints.createNegativeFacing(Double.POSITIVE_INFINITY, TEST_PRECISION);
92 final OrientedPoint neg = OrientedPoints.createPositiveFacing(Double.NEGATIVE_INFINITY, TEST_PRECISION);
93
94 final Transform<Vector1D> scaleAndTranslate = AffineTransformMatrix1D.identity().scale(10.0).translate(5.0);
95 final Transform<Vector1D> negate = AffineTransformMatrix1D.from(Vector1D::negate);
96
97
98 assertOrientedPoint(pos.transform(scaleAndTranslate), Double.POSITIVE_INFINITY, false, TEST_PRECISION);
99 assertOrientedPoint(neg.transform(scaleAndTranslate), Double.NEGATIVE_INFINITY, true, TEST_PRECISION);
100
101 assertOrientedPoint(pos.transform(negate), Double.NEGATIVE_INFINITY, true, TEST_PRECISION);
102 assertOrientedPoint(neg.transform(negate), Double.POSITIVE_INFINITY, false, TEST_PRECISION);
103 }
104
105 @Test
106 void testTransform_zeroScale() {
107
108 final AffineTransformMatrix1D zeroScale = AffineTransformMatrix1D.createScale(0.0);
109
110 final OrientedPoint pt = OrientedPoints.createPositiveFacing(Vector1D.of(2.0), TEST_PRECISION);
111
112
113 GeometryTestUtils.assertThrowsWithMessage(
114 () -> pt.transform(zeroScale),
115 IllegalArgumentException.class, "Oriented point direction cannot be zero");
116 }
117
118 @Test
119 void testOffset_positiveFacing() {
120
121 final OrientedPoint pt = OrientedPoints.fromPointAndDirection(Vector1D.of(-2.0), true, TEST_PRECISION);
122
123
124 Assertions.assertEquals(-98.0, pt.offset(Vector1D.of(-100)), Precision.EPSILON);
125 Assertions.assertEquals(-0.1, pt.offset(Vector1D.of(-2.1)), Precision.EPSILON);
126 Assertions.assertEquals(0.0, pt.offset(Vector1D.of(-2)), Precision.EPSILON);
127 Assertions.assertEquals(0.99, pt.offset(Vector1D.of(-1.01)), Precision.EPSILON);
128 Assertions.assertEquals(1.0, pt.offset(Vector1D.of(-1.0)), Precision.EPSILON);
129 Assertions.assertEquals(1.01, pt.offset(Vector1D.of(-0.99)), Precision.EPSILON);
130 Assertions.assertEquals(2.0, pt.offset(Vector1D.of(0)), Precision.EPSILON);
131 Assertions.assertEquals(102, pt.offset(Vector1D.of(100)), Precision.EPSILON);
132 }
133
134 @Test
135 void testOffset_negativeFacing() {
136
137 final OrientedPoint pt = OrientedPoints.fromPointAndDirection(Vector1D.of(-2.0), false, TEST_PRECISION);
138
139
140 Assertions.assertEquals(98.0, pt.offset(Vector1D.of(-100)), Precision.EPSILON);
141 Assertions.assertEquals(0.1, pt.offset(Vector1D.of(-2.1)), Precision.EPSILON);
142 Assertions.assertEquals(0.0, pt.offset(Vector1D.of(-2)), Precision.EPSILON);
143 Assertions.assertEquals(-0.99, pt.offset(Vector1D.of(-1.01)), Precision.EPSILON);
144 Assertions.assertEquals(-1.0, pt.offset(Vector1D.of(-1.0)), Precision.EPSILON);
145 Assertions.assertEquals(-1.01, pt.offset(Vector1D.of(-0.99)), Precision.EPSILON);
146 Assertions.assertEquals(-2, pt.offset(Vector1D.of(0)), Precision.EPSILON);
147 Assertions.assertEquals(-102, pt.offset(Vector1D.of(100)), Precision.EPSILON);
148 }
149
150 @Test
151 void testOffset_infinityArguments() {
152
153 final OrientedPoint pt = OrientedPoints.fromPointAndDirection(Vector1D.of(-2.0), true, TEST_PRECISION);
154
155
156 GeometryTestUtils.assertPositiveInfinity(pt.offset(Vector1D.of(Double.POSITIVE_INFINITY)));
157 GeometryTestUtils.assertNegativeInfinity(pt.offset(Vector1D.of(Double.NEGATIVE_INFINITY)));
158 }
159
160 @Test
161 void testOffset_infinityLocation() {
162
163 final OrientedPoint pt = OrientedPoints.fromPointAndDirection(Vector1D.of(Double.POSITIVE_INFINITY), true, TEST_PRECISION);
164
165
166 Assertions.assertTrue(Double.isNaN(pt.offset(Vector1D.of(Double.POSITIVE_INFINITY))));
167 GeometryTestUtils.assertNegativeInfinity(pt.offset(Vector1D.of(Double.NEGATIVE_INFINITY)));
168
169 GeometryTestUtils.assertNegativeInfinity(pt.offset(Vector1D.of(0)));
170 }
171
172 @Test
173 void testClassify() {
174
175 final Precision.DoubleEquivalence smallPrecision = Precision.doubleEquivalenceOfEpsilon(1e-10);
176 final Precision.DoubleEquivalence largePrecision = Precision.doubleEquivalenceOfEpsilon(1e-1);
177
178 final OrientedPoint smallPosFacing = OrientedPoints.fromLocationAndDirection(1.0, true, smallPrecision);
179 final OrientedPoint largeNegFacing = OrientedPoints.fromLocationAndDirection(1.0, false, largePrecision);
180
181
182 assertClassify(HyperplaneLocation.MINUS, smallPosFacing,
183 Double.NEGATIVE_INFINITY, -10, 0, 0.9, 0.99999, 1 - 1e-9);
184 assertClassify(HyperplaneLocation.ON, smallPosFacing,
185 1 - 1e-11, 1, 1 + 1e-11);
186 assertClassify(HyperplaneLocation.PLUS, smallPosFacing,
187 1 + 1e-9, 2, 10, Double.POSITIVE_INFINITY);
188
189 assertClassify(HyperplaneLocation.PLUS, largeNegFacing,
190 Double.NEGATIVE_INFINITY, -10, 0, 0.89);
191 assertClassify(HyperplaneLocation.ON, largeNegFacing,
192 0.91, 0.9999, 1, 1.001, 1.09);
193 assertClassify(HyperplaneLocation.MINUS, largeNegFacing,
194 1.11, 2, 10, Double.POSITIVE_INFINITY);
195 }
196
197 @Test
198 void testSpan() {
199
200 final OrientedPoint pt = OrientedPoints.fromPointAndDirection(Vector1D.of(1.0), false, TEST_PRECISION);
201
202
203 final HyperplaneConvexSubset<Vector1D> result = pt.span();
204
205
206 Assertions.assertSame(pt, result.getHyperplane());
207 }
208
209 @Test
210 void testSimilarOrientation() {
211
212 final OrientedPoint negativeDir1 = OrientedPoints.fromPointAndDirection(Vector1D.of(1.0), false, TEST_PRECISION);
213 final OrientedPoint negativeDir2 = OrientedPoints.fromPointAndDirection(Vector1D.of(-1.0), false, TEST_PRECISION);
214 final OrientedPoint positiveDir1 = OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), true, TEST_PRECISION);
215 final OrientedPoint positiveDir2 = OrientedPoints.fromPointAndDirection(Vector1D.of(-2.0), true, TEST_PRECISION);
216
217
218 Assertions.assertTrue(negativeDir1.similarOrientation(negativeDir1));
219 Assertions.assertTrue(negativeDir1.similarOrientation(negativeDir2));
220 Assertions.assertTrue(negativeDir2.similarOrientation(negativeDir1));
221
222 Assertions.assertTrue(positiveDir1.similarOrientation(positiveDir1));
223 Assertions.assertTrue(positiveDir1.similarOrientation(positiveDir2));
224 Assertions.assertTrue(positiveDir2.similarOrientation(positiveDir1));
225
226 Assertions.assertFalse(negativeDir1.similarOrientation(positiveDir1));
227 Assertions.assertFalse(positiveDir1.similarOrientation(negativeDir1));
228 }
229
230 @Test
231 void testProject() {
232
233 final OrientedPoint pt = OrientedPoints.fromPointAndDirection(Vector1D.of(1.0), true, TEST_PRECISION);
234
235
236 Assertions.assertEquals(1.0, pt.project(Vector1D.of(-1.0)).getX(), Precision.EPSILON);
237 Assertions.assertEquals(1.0, pt.project(Vector1D.of(0.0)).getX(), Precision.EPSILON);
238 Assertions.assertEquals(1.0, pt.project(Vector1D.of(1.0)).getX(), Precision.EPSILON);
239 Assertions.assertEquals(1.0, pt.project(Vector1D.of(100.0)).getX(), Precision.EPSILON);
240 }
241
242
243 @Test
244 void testEq() {
245
246 final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-3);
247
248 final OrientedPoint a = OrientedPoints.createPositiveFacing(0, precision);
249 final OrientedPoint b = OrientedPoints.createPositiveFacing(0, TEST_PRECISION);
250
251 final OrientedPoint c = OrientedPoints.createPositiveFacing(2e-3, precision);
252 final OrientedPoint d = OrientedPoints.createNegativeFacing(0, precision);
253 final OrientedPoint e = OrientedPoints.createPositiveFacing(1e-4, precision);
254
255
256 Assertions.assertTrue(a.eq(a, precision));
257 Assertions.assertTrue(a.eq(b, precision));
258
259 Assertions.assertFalse(a.eq(c, precision));
260 Assertions.assertFalse(a.eq(d, precision));
261
262 Assertions.assertTrue(a.eq(e, precision));
263 Assertions.assertTrue(e.eq(a, precision));
264 }
265
266 @Test
267 void testHashCode() {
268
269 final Precision.DoubleEquivalence precisionA = Precision.doubleEquivalenceOfEpsilon(1e-10);
270 final Precision.DoubleEquivalence precisionB = Precision.doubleEquivalenceOfEpsilon(1e-15);
271
272 final OrientedPoint a = OrientedPoints.fromPointAndDirection(Vector1D.of(3.0), true, precisionA);
273 final OrientedPoint b = OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), false, precisionA);
274 final OrientedPoint c = OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), true, precisionB);
275
276 final OrientedPoint d = OrientedPoints.fromPointAndDirection(Vector1D.of(3.0), true, precisionA);
277 final OrientedPoint e = OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), false, precisionA);
278 final OrientedPoint f = OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), true, precisionB);
279
280
281 Assertions.assertNotEquals(a.hashCode(), b.hashCode());
282 Assertions.assertNotEquals(b.hashCode(), c.hashCode());
283 Assertions.assertNotEquals(c.hashCode(), a.hashCode());
284
285 Assertions.assertEquals(a.hashCode(), d.hashCode());
286 Assertions.assertEquals(b.hashCode(), e.hashCode());
287 Assertions.assertEquals(c.hashCode(), f.hashCode());
288 }
289
290 @Test
291 void testEquals() {
292
293 final Precision.DoubleEquivalence precisionA = Precision.doubleEquivalenceOfEpsilon(1e-10);
294 final Precision.DoubleEquivalence precisionB = Precision.doubleEquivalenceOfEpsilon(1e-15);
295
296 final OrientedPoint a = OrientedPoints.fromPointAndDirection(Vector1D.of(1.0), true, precisionA);
297 final OrientedPoint b = OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), true, precisionA);
298
299 final OrientedPoint c = OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), true, precisionA);
300 final OrientedPoint d = OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), false, precisionA);
301
302 final OrientedPoint e = OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), true, precisionA);
303 final OrientedPoint f = OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), true, precisionB);
304
305 final OrientedPoint g = OrientedPoints.fromPointAndDirection(Vector1D.of(1.0), true, precisionA);
306
307
308 GeometryTestUtils.assertSimpleEqualsCases(a);
309
310 Assertions.assertNotEquals(a, b);
311 Assertions.assertNotEquals(c, d);
312 Assertions.assertNotEquals(e, f);
313
314 Assertions.assertEquals(a, g);
315 Assertions.assertEquals(g, a);
316 }
317
318 @Test
319 void testToString() {
320
321 final OrientedPoint pt = OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), true, TEST_PRECISION);
322
323
324 final String str = pt.toString();
325
326
327 Assertions.assertTrue(str.contains("OrientedPoint"));
328 Assertions.assertTrue(str.contains("point= (2.0)"));
329 Assertions.assertTrue(str.contains("direction= (1.0)"));
330 }
331
332 @Test
333 void testFromLocationAndDirection() {
334
335 assertOrientedPoint(OrientedPoints.fromLocationAndDirection(3.0, true, TEST_PRECISION),
336 3.0, true, TEST_PRECISION);
337 assertOrientedPoint(OrientedPoints.fromLocationAndDirection(2.0, false, TEST_PRECISION),
338 2.0, false, TEST_PRECISION);
339 }
340
341 @Test
342 void testFromPointAndDirection_pointAndBooleanArgs() {
343
344 assertOrientedPoint(OrientedPoints.fromPointAndDirection(Vector1D.of(3.0), true, TEST_PRECISION),
345 3.0, true, TEST_PRECISION);
346 assertOrientedPoint(OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), false, TEST_PRECISION),
347 2.0, false, TEST_PRECISION);
348 }
349
350 @Test
351 void testFromPointAndDirection_pointAndVectorArgs() {
352
353 assertOrientedPoint(OrientedPoints.fromPointAndDirection(Vector1D.of(-2.0), Vector1D.of(0.1), TEST_PRECISION),
354 -2.0, true, TEST_PRECISION);
355 assertOrientedPoint(OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), Vector1D.of(-10.1), TEST_PRECISION),
356 2.0, false, TEST_PRECISION);
357 }
358
359 @Test
360 void testFromPointAndDirection_invalidDirection() {
361
362 final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(0.1);
363
364
365 GeometryTestUtils.assertThrowsWithMessage(
366 () -> OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), Vector1D.of(0.09), precision),
367 IllegalArgumentException.class, "Oriented point direction cannot be zero");
368 GeometryTestUtils.assertThrowsWithMessage(
369 () -> OrientedPoints.fromPointAndDirection(Vector1D.of(2.0), Vector1D.of(-0.09), precision),
370 IllegalArgumentException.class, "Oriented point direction cannot be zero");
371 }
372
373 @Test
374 void testCreatePositiveFacing() {
375
376 assertOrientedPoint(OrientedPoints.createPositiveFacing(Vector1D.of(-2.0), TEST_PRECISION),
377 -2.0, true, TEST_PRECISION);
378 assertOrientedPoint(OrientedPoints.createPositiveFacing(-4.0, TEST_PRECISION),
379 -4.0, true, TEST_PRECISION);
380 }
381
382 @Test
383 void testCreateNegativeFacing() {
384
385 assertOrientedPoint(OrientedPoints.createNegativeFacing(Vector1D.of(2.0), TEST_PRECISION),
386 2.0, false, TEST_PRECISION);
387 assertOrientedPoint(OrientedPoints.createNegativeFacing(4, TEST_PRECISION),
388 4.0, false, TEST_PRECISION);
389 }
390
391 @Test
392 void testSubset_split() {
393
394 final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-3);
395
396 final OrientedPoint pt = OrientedPoints.createPositiveFacing(-1.5, precision);
397 final HyperplaneConvexSubset<Vector1D> sub = pt.span();
398
399
400 checkSplit(sub, OrientedPoints.createPositiveFacing(1.0, precision), true, false);
401 checkSplit(sub, OrientedPoints.createPositiveFacing(-1.5 + 1e-2, precision), true, false);
402
403 checkSplit(sub, OrientedPoints.createNegativeFacing(1.0, precision), false, true);
404 checkSplit(sub, OrientedPoints.createNegativeFacing(-1.5 + 1e-2, precision), false, true);
405
406 checkSplit(sub, OrientedPoints.createNegativeFacing(-1.5, precision), false, false);
407 checkSplit(sub, OrientedPoints.createNegativeFacing(-1.5 + 1e-4, precision), false, false);
408 checkSplit(sub, OrientedPoints.createNegativeFacing(-1.5 - 1e-4, precision), false, false);
409 }
410
411 private void checkSplit(final HyperplaneConvexSubset<Vector1D> sub, final OrientedPoint splitter, final boolean minus, final boolean plus) {
412 final Split<? extends HyperplaneConvexSubset<Vector1D>> split = sub.split(splitter);
413
414 Assertions.assertSame(minus ? sub : null, split.getMinus());
415 Assertions.assertSame(plus ? sub : null, split.getPlus());
416 }
417
418 @Test
419 void testSubset_simpleMethods() {
420
421 final OrientedPoint pt = OrientedPoints.createPositiveFacing(2, TEST_PRECISION);
422 final HyperplaneConvexSubset<Vector1D> sub = pt.span();
423
424
425 Assertions.assertSame(pt, sub.getHyperplane());
426 Assertions.assertFalse(sub.isFull());
427 Assertions.assertFalse(sub.isEmpty());
428 Assertions.assertFalse(sub.isInfinite());
429 Assertions.assertTrue(sub.isFinite());
430 Assertions.assertEquals(0.0, sub.getSize(), TEST_EPS);
431 EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(2), sub.getCentroid(), TEST_EPS);
432
433 final List<? extends HyperplaneConvexSubset<Vector1D>> list = sub.toConvex();
434 Assertions.assertEquals(1, list.size());
435 Assertions.assertSame(sub, list.get(0));
436 }
437
438 @Test
439 void testSubset_classify() {
440
441 final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-1);
442 final OrientedPoint pt = OrientedPoints.createPositiveFacing(1, precision);
443 final HyperplaneConvexSubset<Vector1D> sub = pt.span();
444
445
446 Assertions.assertEquals(RegionLocation.BOUNDARY, sub.classify(Vector1D.of(0.95)));
447 Assertions.assertEquals(RegionLocation.BOUNDARY, sub.classify(Vector1D.of(1)));
448 Assertions.assertEquals(RegionLocation.BOUNDARY, sub.classify(Vector1D.of(1.05)));
449
450 Assertions.assertEquals(RegionLocation.OUTSIDE, sub.classify(Vector1D.of(1.11)));
451 Assertions.assertEquals(RegionLocation.OUTSIDE, sub.classify(Vector1D.of(0.89)));
452
453 Assertions.assertEquals(RegionLocation.OUTSIDE, sub.classify(Vector1D.of(-3)));
454 Assertions.assertEquals(RegionLocation.OUTSIDE, sub.classify(Vector1D.of(10)));
455
456 Assertions.assertEquals(RegionLocation.OUTSIDE, sub.classify(Vector1D.NEGATIVE_INFINITY));
457 Assertions.assertEquals(RegionLocation.OUTSIDE, sub.classify(Vector1D.POSITIVE_INFINITY));
458 }
459
460 @Test
461 void testSubset_contains() {
462
463 final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-1);
464 final OrientedPoint pt = OrientedPoints.createPositiveFacing(1, precision);
465 final HyperplaneConvexSubset<Vector1D> sub = pt.span();
466
467
468 Assertions.assertTrue(sub.contains(Vector1D.of(0.95)));
469 Assertions.assertTrue(sub.contains(Vector1D.of(1)));
470 Assertions.assertTrue(sub.contains(Vector1D.of(1.05)));
471
472 Assertions.assertFalse(sub.contains(Vector1D.of(1.11)));
473 Assertions.assertFalse(sub.contains(Vector1D.of(0.89)));
474
475 Assertions.assertFalse(sub.contains(Vector1D.of(-3)));
476 Assertions.assertFalse(sub.contains(Vector1D.of(10)));
477
478 Assertions.assertFalse(sub.contains(Vector1D.NEGATIVE_INFINITY));
479 Assertions.assertFalse(sub.contains(Vector1D.POSITIVE_INFINITY));
480 }
481
482 @Test
483 void testSubset_closestContained() {
484
485 final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-1);
486 final OrientedPoint pt = OrientedPoints.createPositiveFacing(1, precision);
487 final HyperplaneConvexSubset<Vector1D> sub = pt.span();
488
489
490 EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(1), sub.closest(Vector1D.NEGATIVE_INFINITY), TEST_EPS);
491 EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(1), sub.closest(Vector1D.of(0)), TEST_EPS);
492 EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(1), sub.closest(Vector1D.of(1)), TEST_EPS);
493 EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(1), sub.closest(Vector1D.of(2)), TEST_EPS);
494 EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(1), sub.closest(Vector1D.POSITIVE_INFINITY), TEST_EPS);
495 }
496
497 @Test
498 void testSubset_transform() {
499
500 final AffineTransformMatrix1D scaleAndTranslate = AffineTransformMatrix1D
501 .createScale(0.5)
502 .translate(-10);
503
504 final AffineTransformMatrix1D reflect = AffineTransformMatrix1D.createScale(-2);
505
506 final HyperplaneConvexSubset<Vector1D> a =
507 OrientedPoints.createPositiveFacing(Vector1D.of(2.0), TEST_PRECISION).span();
508 final HyperplaneConvexSubset<Vector1D> b =
509 OrientedPoints.createNegativeFacing(Vector1D.of(-3.0), TEST_PRECISION).span();
510
511
512 assertOrientedPoint((OrientedPoint) a.transform(scaleAndTranslate).getHyperplane(),
513 -9.0, true, TEST_PRECISION);
514 assertOrientedPoint((OrientedPoint) b.transform(scaleAndTranslate).getHyperplane(),
515 -11.5, false, TEST_PRECISION);
516
517 assertOrientedPoint((OrientedPoint) a.transform(reflect).getHyperplane(), -4.0, false, TEST_PRECISION);
518 assertOrientedPoint((OrientedPoint) b.transform(reflect).getHyperplane(), 6.0, true, TEST_PRECISION);
519 }
520
521 @Test
522 void testSubset_reverse() {
523
524 final OrientedPoint pt = OrientedPoints.createPositiveFacing(2.0, TEST_PRECISION);
525 final HyperplaneConvexSubset<Vector1D> sub = pt.span();
526
527
528 final HyperplaneConvexSubset<Vector1D> result = sub.reverse();
529
530
531 Assertions.assertEquals(2.0, ((OrientedPoint) result.getHyperplane()).getLocation(), TEST_EPS);
532 Assertions.assertFalse(((OrientedPoint) result.getHyperplane()).isPositiveFacing());
533
534 Assertions.assertEquals(sub.getHyperplane(), result.reverse().getHyperplane());
535 }
536
537 @Test
538 void testSubset_toString() {
539
540 final OrientedPoint pt = OrientedPoints.createPositiveFacing(2, TEST_PRECISION);
541 final HyperplaneConvexSubset<Vector1D> sub = pt.span();
542
543
544 final String str = sub.toString();
545
546
547 Assertions.assertTrue(str.contains("OrientedPointConvexSubset"));
548 Assertions.assertTrue(str.contains("point= (2.0)"));
549 Assertions.assertTrue(str.contains("direction= (1.0)"));
550 }
551
552 private static void assertOrientedPoint(final OrientedPoint pt, final double location, final boolean positiveFacing,
553 final Precision.DoubleEquivalence precision) {
554 Assertions.assertEquals(location, pt.getPoint().getX(), TEST_EPS);
555 Assertions.assertEquals(location, pt.getLocation(), TEST_EPS);
556 Assertions.assertEquals(positiveFacing ? 1.0 : -1.0, pt.getDirection().getX(), TEST_EPS);
557 Assertions.assertEquals(positiveFacing, pt.isPositiveFacing());
558 Assertions.assertSame(precision, pt.getPrecision());
559 }
560
561 private static void assertClassify(final HyperplaneLocation expected, final OrientedPoint pt, final double... locations) {
562 for (final double location : locations) {
563 final String msg = "Unexpected classification for location " + location;
564
565 Assertions.assertEquals(expected, pt.classify(location), msg);
566 Assertions.assertEquals(expected, pt.classify(Vector1D.of(location)), msg);
567 }
568 }
569 }