1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.geometry.euclidean.threed;
18
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.Collections;
22 import java.util.function.BiFunction;
23 import java.util.function.ToDoubleFunction;
24 import java.util.regex.Pattern;
25
26 import org.apache.commons.geometry.core.GeometryTestUtils;
27 import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
28 import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
29 import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
30 import org.apache.commons.geometry.euclidean.threed.shape.Parallelepiped;
31 import org.junit.Assert;
32 import org.junit.Test;
33
34 public class Bounds3DTest {
35
36 private static final double TEST_EPS = 1e-10;
37
38 private static final DoublePrecisionContext TEST_PRECISION =
39 new EpsilonDoublePrecisionContext(TEST_EPS);
40
41 private static final String NO_POINTS_MESSAGE = "Cannot construct bounds: no points given";
42
43 private static final Pattern INVALID_BOUNDS_PATTERN =
44 Pattern.compile("^Invalid bounds: min= \\([^\\)]+\\), max= \\([^\\)]+\\)");
45
46 @Test
47 public void testFrom_varargs_singlePoint() {
48
49 final Vector3D p1 = Vector3D.of(-1, 2, -3);
50
51
52 final Bounds3D b = Bounds3D.from(p1);
53
54
55 EuclideanTestUtils.assertCoordinatesEqual(p1, b.getMin(), TEST_EPS);
56 EuclideanTestUtils.assertCoordinatesEqual(p1, b.getMax(), TEST_EPS);
57 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.ZERO, b.getDiagonal(), TEST_EPS);
58 EuclideanTestUtils.assertCoordinatesEqual(p1, b.getCentroid(), TEST_EPS);
59 }
60
61 @Test
62 public void testFrom_varargs_multiplePoints() {
63
64 final Vector3D p1 = Vector3D.of(1, 6, 7);
65 final Vector3D p2 = Vector3D.of(0, 5, 11);
66 final Vector3D p3 = Vector3D.of(3, 6, 8);
67
68
69 final Bounds3D b = Bounds3D.from(p1, p2, p3);
70
71
72 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(0, 5, 7), b.getMin(), TEST_EPS);
73 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(3, 6, 11), b.getMax(), TEST_EPS);
74 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(3, 1, 4), b.getDiagonal(), TEST_EPS);
75 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(1.5, 5.5, 9), b.getCentroid(), TEST_EPS);
76 }
77
78 @Test
79 public void testFrom_iterable_singlePoint() {
80
81 final Vector3D p1 = Vector3D.of(-1, 2, -3);
82
83
84 final Bounds3D b = Bounds3D.from(Collections.singletonList(p1));
85
86
87 EuclideanTestUtils.assertCoordinatesEqual(p1, b.getMin(), TEST_EPS);
88 EuclideanTestUtils.assertCoordinatesEqual(p1, b.getMax(), TEST_EPS);
89 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.ZERO, b.getDiagonal(), TEST_EPS);
90 EuclideanTestUtils.assertCoordinatesEqual(p1, b.getCentroid(), TEST_EPS);
91 }
92
93 @Test
94 public void testFrom_iterable_multiplePoints() {
95
96 final Vector3D p1 = Vector3D.of(1, 6, 7);
97 final Vector3D p2 = Vector3D.of(2, 5, 9);
98 final Vector3D p3 = Vector3D.of(3, 4, 8);
99
100
101 final Bounds3D b = Bounds3D.from(Arrays.asList(p1, p2, p3));
102
103
104 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(1, 4, 7), b.getMin(), TEST_EPS);
105 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(3, 6, 9), b.getMax(), TEST_EPS);
106 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(2, 2, 2), b.getDiagonal(), TEST_EPS);
107 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(2, 5, 8), b.getCentroid(), TEST_EPS);
108 }
109
110 @Test
111 public void testFrom_iterable_noPoints() {
112
113 GeometryTestUtils.assertThrows(() -> {
114 Bounds3D.from(new ArrayList<>());
115 }, IllegalStateException.class, NO_POINTS_MESSAGE);
116 }
117
118 @Test
119 public void testFrom_invalidBounds() {
120
121 final Vector3D good = Vector3D.of(1, 1, 1);
122
123 final Vector3D nan = Vector3D.of(Double.NaN, 1, 1);
124 final Vector3D posInf = Vector3D.of(1, Double.POSITIVE_INFINITY, 1);
125 final Vector3D negInf = Vector3D.of(1, 1, Double.NEGATIVE_INFINITY);
126
127
128 GeometryTestUtils.assertThrows(() -> {
129 Bounds3D.from(Vector3D.NaN);
130 }, IllegalStateException.class, INVALID_BOUNDS_PATTERN);
131
132 GeometryTestUtils.assertThrows(() -> {
133 Bounds3D.from(Vector3D.POSITIVE_INFINITY);
134 }, IllegalStateException.class, INVALID_BOUNDS_PATTERN);
135
136 GeometryTestUtils.assertThrows(() -> {
137 Bounds3D.from(Vector3D.NEGATIVE_INFINITY);
138 }, IllegalStateException.class, INVALID_BOUNDS_PATTERN);
139
140 GeometryTestUtils.assertThrows(() -> {
141 Bounds3D.from(good, nan);
142 }, IllegalStateException.class, INVALID_BOUNDS_PATTERN);
143
144 GeometryTestUtils.assertThrows(() -> {
145 Bounds3D.from(posInf, good);
146 }, IllegalStateException.class, INVALID_BOUNDS_PATTERN);
147
148 GeometryTestUtils.assertThrows(() -> {
149 Bounds3D.from(good, negInf, good);
150 }, IllegalStateException.class, INVALID_BOUNDS_PATTERN);
151 }
152
153 @Test
154 public void testHasSize() {
155
156 final DoublePrecisionContext low = new EpsilonDoublePrecisionContext(1e-2);
157 final DoublePrecisionContext high = new EpsilonDoublePrecisionContext(1e-10);
158
159 final Vector3D p1 = Vector3D.ZERO;
160
161 final Vector3D p2 = Vector3D.of(1e-5, 1, 1);
162 final Vector3D p3 = Vector3D.of(1, 1e-5, 1);
163 final Vector3D p4 = Vector3D.of(1, 1, 1e-5);
164
165 final Vector3D p5 = Vector3D.of(1, 1, 1);
166
167
168 Assert.assertFalse(Bounds3D.from(p1).hasSize(high));
169 Assert.assertFalse(Bounds3D.from(p1).hasSize(low));
170
171 Assert.assertTrue(Bounds3D.from(p1, p2).hasSize(high));
172 Assert.assertFalse(Bounds3D.from(p1, p2).hasSize(low));
173
174 Assert.assertTrue(Bounds3D.from(p1, p3).hasSize(high));
175 Assert.assertFalse(Bounds3D.from(p1, p3).hasSize(low));
176
177 Assert.assertTrue(Bounds3D.from(p1, p4).hasSize(high));
178 Assert.assertFalse(Bounds3D.from(p1, p4).hasSize(low));
179
180 Assert.assertTrue(Bounds3D.from(p1, p5).hasSize(high));
181 Assert.assertTrue(Bounds3D.from(p1, p5).hasSize(low));
182 }
183
184 @Test
185 public void testContains_strict() {
186
187 final Bounds3D b = Bounds3D.from(
188 Vector3D.of(0, 4, 8),
189 Vector3D.of(2, 6, 10));
190
191
192 assertContainsStrict(b, true,
193 b.getCentroid(),
194 Vector3D.of(0, 4, 8), Vector3D.of(2, 6, 10),
195 Vector3D.of(1, 5, 9),
196 Vector3D.of(0, 5, 9), Vector3D.of(2, 5, 9),
197 Vector3D.of(1, 4, 9), Vector3D.of(1, 6, 9),
198 Vector3D.of(1, 5, 8), Vector3D.of(1, 5, 10));
199
200 assertContainsStrict(b, false,
201 Vector3D.ZERO,
202 Vector3D.of(-1, 5, 9), Vector3D.of(3, 5, 9),
203 Vector3D.of(1, 3, 9), Vector3D.of(1, 7, 9),
204 Vector3D.of(1, 5, 7), Vector3D.of(1, 5, 11),
205 Vector3D.of(-1e-15, 4, 8), Vector3D.of(2, 6 + 1e-15, 10), Vector3D.of(0, 4, 10 + 1e-15));
206 }
207
208 @Test
209 public void testContains_precision() {
210
211 final Bounds3D b = Bounds3D.from(
212 Vector3D.of(0, 4, 8),
213 Vector3D.of(2, 6, 10));
214
215
216 assertContainsWithPrecision(b, true,
217 b.getCentroid(),
218 Vector3D.of(0, 4, 8), Vector3D.of(2, 6, 10),
219 Vector3D.of(1, 5, 9),
220 Vector3D.of(0, 5, 9), Vector3D.of(2, 5, 9),
221 Vector3D.of(1, 4, 9), Vector3D.of(1, 6, 9),
222 Vector3D.of(1, 5, 8), Vector3D.of(1, 5, 10),
223 Vector3D.of(-1e-15, 4, 8), Vector3D.of(2, 6 + 1e-15, 10), Vector3D.of(0, 4, 10 + 1e-15));
224
225 assertContainsWithPrecision(b, false,
226 Vector3D.ZERO,
227 Vector3D.of(-1, 5, 9), Vector3D.of(3, 5, 9),
228 Vector3D.of(1, 3, 9), Vector3D.of(1, 7, 9),
229 Vector3D.of(1, 5, 7), Vector3D.of(1, 5, 11));
230 }
231
232 @Test
233 public void testIntersects() {
234
235 final Bounds3D b = Bounds3D.from(Vector3D.ZERO, Vector3D.of(1, 1, 1));
236
237
238 checkIntersects(b, Vector3D::getX, (v, x) -> Vector3D.of(x, v.getY(), v.getZ()));
239 checkIntersects(b, Vector3D::getY, (v, y) -> Vector3D.of(v.getX(), y, v.getZ()));
240 checkIntersects(b, Vector3D::getZ, (v, z) -> Vector3D.of(v.getX(), v.getY(), z));
241 }
242
243 private void checkIntersects(final Bounds3D b, final ToDoubleFunction<Vector3D> getter,
244 final BiFunction<Vector3D, Double, Vector3D> setter) {
245
246 final Vector3D min = b.getMin();
247 final Vector3D max = b.getMax();
248
249 final double minValue = getter.applyAsDouble(min);
250 final double maxValue = getter.applyAsDouble(max);
251 final double midValue = (0.5 * (maxValue - minValue)) + minValue;
252
253
254
255
256 Assert.assertFalse(b.intersects(Bounds3D.from(
257 setter.apply(min, minValue - 2), setter.apply(max, minValue - 1))));
258
259 Assert.assertTrue(b.intersects(Bounds3D.from(
260 setter.apply(min, minValue - 2), setter.apply(max, minValue))));
261 Assert.assertTrue(b.intersects(Bounds3D.from(
262 setter.apply(min, minValue - 2), setter.apply(max, midValue))));
263 Assert.assertTrue(b.intersects(Bounds3D.from(
264 setter.apply(min, minValue - 2), setter.apply(max, maxValue))));
265 Assert.assertTrue(b.intersects(Bounds3D.from(
266 setter.apply(min, minValue - 2), setter.apply(max, maxValue + 1))));
267
268
269 Assert.assertTrue(b.intersects(Bounds3D.from(
270 setter.apply(min, minValue), setter.apply(max, minValue))));
271 Assert.assertTrue(b.intersects(Bounds3D.from(
272 setter.apply(min, minValue), setter.apply(max, midValue))));
273 Assert.assertTrue(b.intersects(Bounds3D.from(
274 setter.apply(min, minValue), setter.apply(max, maxValue))));
275 Assert.assertTrue(b.intersects(Bounds3D.from(
276 setter.apply(min, minValue), setter.apply(max, maxValue + 1))));
277
278
279 Assert.assertTrue(b.intersects(Bounds3D.from(
280 setter.apply(min, midValue), setter.apply(max, midValue))));
281 Assert.assertTrue(b.intersects(Bounds3D.from(
282 setter.apply(min, midValue), setter.apply(max, maxValue))));
283 Assert.assertTrue(b.intersects(Bounds3D.from(
284 setter.apply(min, midValue), setter.apply(max, maxValue + 1))));
285
286
287 Assert.assertTrue(b.intersects(Bounds3D.from(
288 setter.apply(min, maxValue), setter.apply(max, maxValue))));
289 Assert.assertTrue(b.intersects(Bounds3D.from(
290 setter.apply(min, maxValue), setter.apply(max, maxValue + 1))));
291
292
293 Assert.assertFalse(b.intersects(Bounds3D.from(
294 setter.apply(min, maxValue + 1), setter.apply(max, maxValue + 2))));
295 }
296
297 @Test
298 public void testIntersection() {
299
300 final Bounds3D b = Bounds3D.from(Vector3D.ZERO, Vector3D.of(1, 1, 1));
301
302
303
304
305 Assert.assertNull(b.intersection(Bounds3D.from(Vector3D.of(-2, 0, 0), Vector3D.of(-1, 1, 1))));
306 checkIntersection(b, Vector3D.of(-1, 0, 0), Vector3D.of(0, 1, 1),
307 Vector3D.of(0, 0, 0), Vector3D.of(0, 1, 1));
308 checkIntersection(b, Vector3D.of(-1, 0, 0), Vector3D.of(0.5, 1, 1),
309 Vector3D.of(0, 0, 0), Vector3D.of(0.5, 1, 1));
310 checkIntersection(b, Vector3D.of(-1, 0, 0), Vector3D.of(1, 1, 1),
311 Vector3D.of(0, 0, 0), Vector3D.of(1, 1, 1));
312 checkIntersection(b, Vector3D.of(-1, 0, 0), Vector3D.of(2, 1, 1),
313 Vector3D.of(0, 0, 0), Vector3D.of(1, 1, 1));
314 checkIntersection(b, Vector3D.of(0, 0, 0), Vector3D.of(2, 1, 1),
315 Vector3D.of(0, 0, 0), Vector3D.of(1, 1, 1));
316 checkIntersection(b, Vector3D.of(0.5, 0, 0), Vector3D.of(2, 1, 1),
317 Vector3D.of(0.5, 0, 0), Vector3D.of(1, 1, 1));
318 checkIntersection(b, Vector3D.of(1, 0, 0), Vector3D.of(2, 1, 1),
319 Vector3D.of(1, 0, 0), Vector3D.of(1, 1, 1));
320 Assert.assertNull(b.intersection(Bounds3D.from(Vector3D.of(2, 0, 0), Vector3D.of(3, 1, 1))));
321
322
323 Assert.assertNull(b.intersection(Bounds3D.from(Vector3D.of(0, -2, 0), Vector3D.of(1, -1, 1))));
324 checkIntersection(b, Vector3D.of(0, -1, 0), Vector3D.of(1, 0, 1),
325 Vector3D.of(0, 0, 0), Vector3D.of(1, 0, 1));
326 checkIntersection(b, Vector3D.of(0, -1, 0), Vector3D.of(1, 0.5, 1),
327 Vector3D.of(0, 0, 0), Vector3D.of(1, 0.5, 1));
328 checkIntersection(b, Vector3D.of(0, -1, 0), Vector3D.of(1, 1, 1),
329 Vector3D.of(0, 0, 0), Vector3D.of(1, 1, 1));
330 checkIntersection(b, Vector3D.of(0, -1, 0), Vector3D.of(1, 2, 1),
331 Vector3D.of(0, 0, 0), Vector3D.of(1, 1, 1));
332 checkIntersection(b, Vector3D.of(0, 0, 0), Vector3D.of(1, 2, 1),
333 Vector3D.of(0, 0, 0), Vector3D.of(1, 1, 1));
334 checkIntersection(b, Vector3D.of(0, 0.5, 0), Vector3D.of(1, 2, 1),
335 Vector3D.of(0, 0.5, 0), Vector3D.of(1, 1, 1));
336 checkIntersection(b, Vector3D.of(0, 1, 0), Vector3D.of(1, 2, 1),
337 Vector3D.of(0, 1, 0), Vector3D.of(1, 1, 1));
338 Assert.assertNull(b.intersection(Bounds3D.from(Vector3D.of(0, 2, 0), Vector3D.of(1, 3, 1))));
339
340
341 Assert.assertNull(b.intersection(Bounds3D.from(Vector3D.of(0, 0, -2), Vector3D.of(1, 1, -1))));
342 checkIntersection(b, Vector3D.of(0, 0, -1), Vector3D.of(1, 1, 0),
343 Vector3D.of(0, 0, 0), Vector3D.of(1, 1, 0));
344 checkIntersection(b, Vector3D.of(0, 0, -1), Vector3D.of(1, 1, 0.5),
345 Vector3D.of(0, 0, 0), Vector3D.of(1, 1, 0.5));
346 checkIntersection(b, Vector3D.of(0, 0, -1), Vector3D.of(1, 1, 1),
347 Vector3D.of(0, 0, 0), Vector3D.of(1, 1, 1));
348 checkIntersection(b, Vector3D.of(0, 0, -1), Vector3D.of(1, 1, 2),
349 Vector3D.of(0, 0, 0), Vector3D.of(1, 1, 1));
350 checkIntersection(b, Vector3D.of(0, 0, 0), Vector3D.of(1, 1, 2),
351 Vector3D.of(0, 0, 0), Vector3D.of(1, 1, 1));
352 checkIntersection(b, Vector3D.of(0, 0, 0.5), Vector3D.of(1, 1, 2),
353 Vector3D.of(0, 0, 0.5), Vector3D.of(1, 1, 1));
354 checkIntersection(b, Vector3D.of(0, 0, 1), Vector3D.of(1, 1, 2),
355 Vector3D.of(0, 0, 1), Vector3D.of(1, 1, 1));
356 Assert.assertNull(b.intersection(Bounds3D.from(Vector3D.of(0, 0, 2), Vector3D.of(1, 1, 3))));
357 }
358
359 private void checkIntersection(final Bounds3D b, final Vector3D a1, final Vector3D a2, final Vector3D r1, final Vector3D r2) {
360 final Bounds3D a = Bounds3D.from(a1, a2);
361 final Bounds3D result = b.intersection(a);
362
363 checkBounds(result, r1, r2);
364 }
365
366 @Test
367 public void toRegion() {
368
369 final Bounds3D b = Bounds3D.from(
370 Vector3D.of(0, 4, 8),
371 Vector3D.of(2, 6, 10));
372
373
374 final Parallelepiped p = b.toRegion(TEST_PRECISION);
375
376
377 Assert.assertEquals(8, p.getSize(), TEST_EPS);
378 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(1, 5, 9), p.getCentroid(), TEST_EPS);
379 }
380
381 @Test
382 public void toRegion_boundingBoxTooSmall() {
383
384 GeometryTestUtils.assertThrows(() -> {
385 Bounds3D.from(Vector3D.ZERO, Vector3D.of(1e-12, 1e-12, 1e-12))
386 .toRegion(TEST_PRECISION);
387 }, IllegalArgumentException.class);
388 }
389
390 @Test
391 public void testEq() {
392
393 final DoublePrecisionContext low = new EpsilonDoublePrecisionContext(1e-2);
394 final DoublePrecisionContext high = new EpsilonDoublePrecisionContext(1e-10);
395
396 final Bounds3D b1 = Bounds3D.from(Vector3D.of(1, 1, 1), Vector3D.of(2, 2, 2));
397
398 final Bounds3D b2 = Bounds3D.from(Vector3D.of(1.1, 1, 1), Vector3D.of(2, 2, 2));
399 final Bounds3D b3 = Bounds3D.from(Vector3D.of(1, 1, 1), Vector3D.of(1.9, 2, 2));
400
401 final Bounds3D b4 = Bounds3D.from(Vector3D.of(1.001, 1.001, 1.001), Vector3D.of(2.001, 2.001, 2.001));
402
403
404 Assert.assertTrue(b1.eq(b1, low));
405
406 Assert.assertFalse(b1.eq(b2, low));
407 Assert.assertFalse(b1.eq(b3, low));
408
409 Assert.assertTrue(b1.eq(b4, low));
410 Assert.assertTrue(b4.eq(b1, low));
411
412 Assert.assertFalse(b1.eq(b4, high));
413 Assert.assertFalse(b4.eq(b1, high));
414 }
415
416 @Test
417 public void testHashCode() {
418
419 final Bounds3D b1 = Bounds3D.from(Vector3D.of(1, 1, 1), Vector3D.of(2, 2, 2));
420
421 final Bounds3D b2 = Bounds3D.from(Vector3D.of(-2, 1, 1), Vector3D.of(2, 2, 2));
422 final Bounds3D b3 = Bounds3D.from(Vector3D.of(1, 1, 1), Vector3D.of(3, 2, 2));
423 final Bounds3D b4 = Bounds3D.from(Vector3D.of(1 + 1e-15, 1, 1), Vector3D.of(2, 2, 2));
424 final Bounds3D b5 = Bounds3D.from(Vector3D.of(1, 1, 1), Vector3D.of(2 + 1e-15, 2, 2));
425
426 final Bounds3D b6 = Bounds3D.from(Vector3D.of(1, 1, 1), Vector3D.of(2, 2, 2));
427
428
429 final int hash = b1.hashCode();
430
431
432 Assert.assertEquals(hash, b1.hashCode());
433
434 Assert.assertNotEquals(hash, b2.hashCode());
435 Assert.assertNotEquals(hash, b3.hashCode());
436 Assert.assertNotEquals(hash, b4.hashCode());
437 Assert.assertNotEquals(hash, b5.hashCode());
438
439 Assert.assertEquals(hash, b6.hashCode());
440 }
441
442 @Test
443 public void testEquals() {
444
445 final Bounds3D b1 = Bounds3D.from(Vector3D.of(1, 1, 1), Vector3D.of(2, 2, 2));
446
447 final Bounds3D b2 = Bounds3D.from(Vector3D.of(-1, 1, 1), Vector3D.of(2, 2, 2));
448 final Bounds3D b3 = Bounds3D.from(Vector3D.of(1, 1, 1), Vector3D.of(3, 2, 2));
449 final Bounds3D b4 = Bounds3D.from(Vector3D.of(1 + 1e-15, 1, 1), Vector3D.of(2, 2, 2));
450 final Bounds3D b5 = Bounds3D.from(Vector3D.of(1, 1, 1), Vector3D.of(2 + 1e-15, 2, 2));
451
452 final Bounds3D b6 = Bounds3D.from(Vector3D.of(1, 1, 1), Vector3D.of(2, 2, 2));
453
454
455 Assert.assertEquals(b1, b1);
456
457 Assert.assertFalse(b1.equals(null));
458 Assert.assertFalse(b1.equals(new Object()));
459
460 Assert.assertNotEquals(b1, b2);
461 Assert.assertNotEquals(b1, b3);
462 Assert.assertNotEquals(b1, b4);
463 Assert.assertNotEquals(b1, b5);
464
465 Assert.assertEquals(b1, b6);
466 }
467
468 @Test
469 public void testToString() {
470
471 final Bounds3D b = Bounds3D.from(Vector3D.of(1, 1, 1), Vector3D.of(2, 2, 2));
472
473
474 final String str = b.toString();
475
476
477 GeometryTestUtils.assertContains("Bounds3D[min= (1", str);
478 GeometryTestUtils.assertContains(", max= (2", str);
479 }
480
481 @Test
482 public void testBuilder_addMethods() {
483
484 final Vector3D p1 = Vector3D.of(1, 10, 11);
485 final Vector3D p2 = Vector3D.of(2, 9, 12);
486 final Vector3D p3 = Vector3D.of(3, 8, 13);
487 final Vector3D p4 = Vector3D.of(4, 7, 14);
488 final Vector3D p5 = Vector3D.of(5, 6, 15);
489
490
491 final Bounds3D b = Bounds3D.builder()
492 .add(p1)
493 .addAll(Arrays.asList(p2, p3))
494 .add(Bounds3D.from(p4, p5))
495 .build();
496
497
498 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(1, 6, 11), b.getMin(), TEST_EPS);
499 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(5, 10, 15), b.getMax(), TEST_EPS);
500 EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(3, 8, 13), b.getCentroid(), TEST_EPS);
501 }
502
503 @Test
504 public void testBuilder_hasBounds() {
505
506 Assert.assertFalse(Bounds3D.builder().hasBounds());
507
508 Assert.assertFalse(Bounds3D.builder().add(Vector3D.of(Double.NaN, 1, 1)).hasBounds());
509 Assert.assertFalse(Bounds3D.builder().add(Vector3D.of(1, Double.NaN, 1)).hasBounds());
510 Assert.assertFalse(Bounds3D.builder().add(Vector3D.of(1, 1, Double.NaN)).hasBounds());
511
512 Assert.assertFalse(Bounds3D.builder().add(Vector3D.of(Double.POSITIVE_INFINITY, 1, 1)).hasBounds());
513 Assert.assertFalse(Bounds3D.builder().add(Vector3D.of(1, Double.POSITIVE_INFINITY, 1)).hasBounds());
514 Assert.assertFalse(Bounds3D.builder().add(Vector3D.of(1, 1, Double.POSITIVE_INFINITY)).hasBounds());
515
516 Assert.assertFalse(Bounds3D.builder().add(Vector3D.of(Double.NEGATIVE_INFINITY, 1, 1)).hasBounds());
517 Assert.assertFalse(Bounds3D.builder().add(Vector3D.of(1, Double.NEGATIVE_INFINITY, 1)).hasBounds());
518 Assert.assertFalse(Bounds3D.builder().add(Vector3D.of(1, 1, Double.NEGATIVE_INFINITY)).hasBounds());
519
520 Assert.assertTrue(Bounds3D.builder().add(Vector3D.ZERO).hasBounds());
521 }
522
523 private static void checkBounds(final Bounds3D b, final Vector3D min, final Vector3D max) {
524 EuclideanTestUtils.assertCoordinatesEqual(min, b.getMin(), TEST_EPS);
525 EuclideanTestUtils.assertCoordinatesEqual(max, b.getMax(), TEST_EPS);
526 }
527
528 private static void assertContainsStrict(final Bounds3D bounds, final boolean contains, final Vector3D... pts) {
529 for (final Vector3D pt : pts) {
530 Assert.assertEquals("Unexpected location for point " + pt, contains, bounds.contains(pt));
531 }
532 }
533
534 private static void assertContainsWithPrecision(final Bounds3D bounds, final boolean contains, final Vector3D... pts) {
535 for (final Vector3D pt : pts) {
536 Assert.assertEquals("Unexpected location for point " + pt, contains, bounds.contains(pt, TEST_PRECISION));
537 }
538 }
539 }