File: test_640_bbox.py

package info (click to toggle)
ezdxf 1.4.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 104,528 kB
  • sloc: python: 182,341; makefile: 116; lisp: 20; ansic: 4
file content (539 lines) | stat: -rw-r--r-- 19,615 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
# Copyright (c) 2019-2024, Manfred Moitzi
# License: MIT License
import pytest

from ezdxf.math import BoundingBox, BoundingBox2d, Vec2, Vec3
from itertools import permutations


class TestBoundingBox:
    def test_init(self):
        bbox = BoundingBox([(0, 0, 0), (10, 10, 10)])
        assert bbox.extmin == (0, 0, 0)
        assert bbox.extmax == (10, 10, 10)

        bbox = BoundingBox([(10, 10, 10), (0, 0, 0)])
        assert bbox.extmin == (0, 0, 0)
        assert bbox.extmax == (10, 10, 10)

        bbox = BoundingBox([(7, -2, 9), (-1, 8, -3)])
        assert bbox.extmin == (-1, -2, -3)
        assert bbox.extmax == (7, 8, 9)

    def test_init_none(self):
        bbox = BoundingBox()
        assert bbox.is_empty is True
        assert bbox.has_data is False

        bbox.extend([(0, 0, 0), (10, 10, 10)])
        assert bbox.size == (10, 10, 10)
        assert bbox.is_empty is False
        assert bbox.has_data is True

    def test_init_empty_list(self):
        bbox = BoundingBox([])
        assert bbox.has_data is False

    @pytest.mark.parametrize(
        "v",
        [
            [],
            [(0, 0, 0)],
            [(1, 0, 0), (2, 0, 0)],
            [(1, 1, 0), (2, 2, 0)],
            [(1, 1, 1), (1, 1, 1)],
        ],
    )
    def test_is_empty(self, v):
        """Volume is 0."""
        assert BoundingBox(v).is_empty is True

    def test_not_is_empty(self):
        """Volume is not 0."""
        assert BoundingBox([(0, 0, 0), (-1, -1, -1)]).is_empty is False

    def test_init_with_with_empty_list(self):
        assert BoundingBox([]).is_empty is True

    def test_inside(self):
        bbox = BoundingBox([(0, 0, 0), (10, 10, 10)])
        assert bbox.inside((0, 0, 0)) is True
        assert bbox.inside((-1, 0, 0)) is False
        assert bbox.inside((0, -1, 0)) is False
        assert bbox.inside((0, 0, -1)) is False

        assert bbox.inside((5, 5, 5)) is True

        assert bbox.inside((10, 10, 10)) is True
        assert bbox.inside((11, 10, 10)) is False
        assert bbox.inside((10, 11, 10)) is False
        assert bbox.inside((10, 10, 11)) is False

    def test_all_inside(self):
        bbox1 = BoundingBox([(0, 0, 0), (10, 10, 10)])
        bbox2 = BoundingBox([(1, 1, 1), (9, 9, 9)])
        empty = BoundingBox()
        assert bbox1.all_inside(bbox2) is True
        assert bbox2.all_inside(bbox1) is False
        assert bbox1.all_inside(empty) is False
        assert empty.all_inside(bbox1) is False

    def test_any_inside(self):
        bbox1 = BoundingBox([(0, 0, 0), (7, 7, 7)])
        bbox2 = BoundingBox([(1, 1, 1), (9, 9, 9)])
        empty = BoundingBox()
        assert bbox1.any_inside(bbox2) is True
        assert bbox2.any_inside(bbox1) is True
        assert bbox1.any_inside(empty) is False
        assert empty.any_inside(bbox1) is False

    def test_has_overlap_accepts_2d_bounding_box(self):
        bbox1 = BoundingBox([(0, 0, 0), (10, 10, 10)])
        bbox2 = BoundingBox2d([(1, 1), (9, 9)])  # z-axis are 0
        assert bbox1.has_overlap(bbox2) is True

    def test_has_intersection_accepts_2d_bounding_box(self):
        bbox1 = BoundingBox([(-1, -1, -1), (10, 10, 10)])
        bbox2 = BoundingBox2d([(1, 1), (9, 9)])  # z-axis are 0
        assert bbox1.has_intersection(bbox2) is True

    def test_do_intersect_and_overlap(self):
        bbox1 = BoundingBox([(0, 0, 0), (10, 10, 10)])
        bbox2 = BoundingBox([(1, 1, 1), (9, 9, 9)])
        bbox3 = BoundingBox([(-1, -1, -1), (1.001, 1.001, 1.001)])
        for a, b in permutations([bbox1, bbox2, bbox3], 2):
            assert a.has_intersection(b) is True
            assert a.has_overlap(b) is True

    def test_do_not_intersect_or_overlap(self):
        bbox1 = BoundingBox([(0, 0, 0), (3, 3, 3)])
        bbox2 = BoundingBox([(4, 4, 4), (9, 9, 9)])
        bbox3 = BoundingBox([(-2, -2, -2), (-1, -1, -1)])
        for a, b in permutations([bbox1, bbox2, bbox3], 2):
            assert a.has_intersection(b) is False
            assert a.has_overlap(b) is False

    def test_do_not_intersect_or_overlap_empty(self):
        bbox = BoundingBox([(0, 0, 0), (3, 3, 3)])
        empty = BoundingBox()
        assert bbox.has_intersection(empty) is False
        assert bbox.has_overlap(empty) is False
        assert empty.has_intersection(bbox) is False
        assert empty.has_overlap(bbox) is False
        assert empty.has_intersection(empty) is False
        assert empty.has_overlap(empty) is False

    def test_crossing_2d_boxes(self):
        # bboxes do overlap, but do not contain corner points of the other bbox
        bbox1 = BoundingBox2d([(0, 1), (3, 2)])
        bbox2 = BoundingBox2d([(1, 0), (2, 3)])
        assert bbox1.has_intersection(bbox2) is True
        assert bbox1.has_overlap(bbox2) is True

    def test_crossing_3d_boxes(self):
        # bboxes do overlap, but do not contain corner points of the other bbox
        bbox1 = BoundingBox([(0, 1, 0), (3, 2, 1)])
        bbox2 = BoundingBox([(1, 0, 0), (2, 3, 1)])
        assert bbox1.has_intersection(bbox2) is True
        assert bbox1.has_overlap(bbox2) is True

    def test_touching_2d_boxes(self):
        bbox1 = BoundingBox2d([(0, 0), (1, 1)])
        bbox2 = BoundingBox2d([(1, 1), (2, 2)])
        bbox3 = BoundingBox2d([(-1, -1), (0, 0)])
        assert bbox1.has_intersection(bbox2) is False
        assert bbox1.has_overlap(bbox2) is True
        assert bbox2.has_intersection(bbox1) is False
        assert bbox2.has_overlap(bbox1) is True
        assert bbox1.has_intersection(bbox3) is False
        assert bbox1.has_overlap(bbox3) is True
        assert bbox3.has_intersection(bbox1) is False
        assert bbox3.has_overlap(bbox1) is True

    def test_touching_3d_boxes(self):
        bbox1 = BoundingBox([(0, 0, 0), (1, 1, 1)])
        bbox2 = BoundingBox([(1, 1, 1), (2, 2, 2)])
        bbox3 = BoundingBox([(-1, -1, -1), (0, 0, 0)])
        assert bbox1.has_intersection(bbox2) is False
        assert bbox1.has_overlap(bbox2) is True
        assert bbox2.has_intersection(bbox1) is False
        assert bbox2.has_overlap(bbox1) is True
        assert bbox1.has_intersection(bbox3) is False
        assert bbox1.has_overlap(bbox3) is True
        assert bbox3.has_intersection(bbox1) is False
        assert bbox3.has_overlap(bbox1) is True

    def test_extend(self):
        bbox = BoundingBox([(0, 0, 0), (10, 10, 10)])
        bbox.extend([(5, 5, 5)])
        assert bbox.extmin == (0, 0, 0)
        assert bbox.extmax == (10, 10, 10)

        bbox.extend([(15, 16, 17)])
        assert bbox.extmin == (0, 0, 0)
        assert bbox.extmax == (15, 16, 17)

        bbox.extend([(-15, -16, -17)])
        assert bbox.extmin == (-15, -16, -17)
        assert bbox.extmax == (15, 16, 17)

    def test_extend_by_empty_list(self):
        bbox = BoundingBox([(0, 0, 0), (10, 10, 10)])
        bbox.extend([])
        assert bbox.extmin == (0, 0, 0)
        assert bbox.extmax == (10, 10, 10)

    def test_extend_by_bbox(self):
        bbox = BoundingBox([(0, 0, 0), (10, 10, 10)])
        bbox2 = BoundingBox([(5, 5, 5), (15, 16, 17)])
        bbox.extend(bbox2)
        assert bbox.extmin == (0, 0, 0)
        assert bbox.extmax == (15, 16, 17)

    def test_size(self):
        bbox = BoundingBox([(-2, -2, -2), (8, 8, 8)])
        assert bbox.size == (10, 10, 10)

    def test_center(self):
        bbox = BoundingBox([(-1, -1, -1), (9, 9, 9)])
        assert bbox.center == (4, 4, 4)

    def test_union_of_two_bounding_boxes(self):
        bbox1 = BoundingBox([(0, 0, 0), (10, 10, 10)])
        bbox2 = BoundingBox([(5, 5, 5), (15, 16, 17)])
        bbox = bbox1.union(bbox2)
        assert bbox.extmin == (0, 0, 0)
        assert bbox.extmax == (15, 16, 17)

    def test_union_bbox_with_empty_bbox(self):
        bbox1 = BoundingBox([(0, 0, 0), (10, 10, 10)])
        bbox = bbox1.union(BoundingBox())
        assert bbox.extmin == (0, 0, 0)
        assert bbox.extmax == (10, 10, 10)

    def test_union_empty_bbox_with_bbox(self):
        bbox1 = BoundingBox([(0, 0, 0), (10, 10, 10)])
        bbox = BoundingBox().union(bbox1)
        assert bbox.extmin == (0, 0, 0)
        assert bbox.extmax == (10, 10, 10)

    def test_union_empty_bounding_boxes(self):
        bbox = BoundingBox().union(BoundingBox())
        assert bbox.has_data is False
        assert bbox.is_empty is True

    def test_union_different_bounding_boxes(self):
        bbox1 = BoundingBox([(0, 0, 0), (10, 10, 10)])
        bbox2 = BoundingBox2d([(5, 5), (15, 16)])
        bbox = bbox1.union(BoundingBox(bbox2))
        assert bbox.extmin == (0, 0, 0)
        assert bbox.extmax == (15, 16, 10)

    def test_rect_vertices_for_empty_bbox_raises_value_error(self):
        with pytest.raises(ValueError):
            BoundingBox().rect_vertices()

    def test_cube_vertices_for_empty_bbox_raises_value_error(self):
        with pytest.raises(ValueError):
            BoundingBox().cube_vertices()

    def test_rect_vertices_returns_vertices_in_counter_clockwise_order(self):
        bbox = BoundingBox([(0, 0, 0), (1, 2, 3)])
        assert bbox.rect_vertices() == Vec2.tuple([(0, 0), (1, 0), (1, 2), (0, 2)])

    def test_cube_vertices_returns_vertices_in_counter_clockwise_order(self):
        bbox = BoundingBox([(0, 0, 0), (1, 2, 3)])
        assert bbox.cube_vertices() == Vec3.tuple(
            [
                (0, 0, 0),  # bottom layer
                (1, 0, 0),
                (1, 2, 0),
                (0, 2, 0),
                (0, 0, 3),  # top layer
                (1, 0, 3),
                (1, 2, 3),
                (0, 2, 3),
            ]
        )

    def test_contains_other_bounding_box(self):
        box_a = BoundingBox([(0, 0, 0), (10, 10, 10)])
        box_b = BoundingBox([(1, 1, 1), (9, 9, 9)])
        box_c = BoundingBox([(1, 1, 1), (11, 11, 11)])
        assert box_a.contains(box_b) is True
        assert box_a.contains(box_a) is True  # self contained
        assert box_b.contains(box_a) is False
        assert box_a.contains(box_c) is False

    def test_growing_empty_bounding_box_does_nothing(self):
        box = BoundingBox()
        box.grow(1)
        assert box.has_data is False

    def test_grow_bounding_box(self):
        box = BoundingBox([(0, 0, 0), (1, 1, 1)])
        box.grow(1)
        assert box.extmin.isclose((-1, -1, -1))
        assert box.extmax.isclose((2, 2, 2))

    def test_shrinking_to_zero_or_below_raises_exception(self):
        box = BoundingBox([(0, 0, 0), (1, 1, 1)])
        with pytest.raises(ValueError):
            box.grow(-0.5)


class TestBoundingBox2d:
    def test_init(self):
        bbox = BoundingBox2d([(0, 0), (10, 10)])
        assert bbox.extmin == (0, 0)
        assert bbox.extmax == (10, 10)

        bbox = BoundingBox2d([(7, -2), (-1, 8)])
        assert bbox.extmin == (-1, -2)
        assert bbox.extmax == (7, 8)

    def test_init_with_with_empty_list(self):
        assert BoundingBox2d([]).is_empty is True

    def test_init_none(self):
        bbox = BoundingBox2d()
        assert bbox.has_data is False
        bbox.extend([(0, 0), (10, 10)])
        assert bbox.size == (10, 10)
        assert bbox.has_data is True

    @pytest.mark.parametrize(
        "v",
        [
            [],
            [(0, 0)],
            [(1, 0), (2, 0)],
            [(0, 1), (0, 2)],
            [(1, 1), (1, 1)],
        ],
    )
    def test_is_empty(self, v):
        """Area is 0."""
        assert BoundingBox2d(v).is_empty is True

    def test_not_is_empty(self):
        """Area is not 0."""
        assert BoundingBox2d([(0, 0), (-1, -1)]).is_empty is False

    def test_inside(self):
        bbox = BoundingBox2d([(0, 0), (10, 10)])
        assert bbox.inside((0, 0)) is True
        assert bbox.inside((-1, 0)) is False
        assert bbox.inside((0, -1)) is False

        assert bbox.inside((5, 5)) is True

        assert bbox.inside((10, 10)) is True
        assert bbox.inside((11, 10)) is False
        assert bbox.inside((10, 11)) is False

    def test_extend(self):
        bbox = BoundingBox2d([(0, 0), (10, 10)])
        bbox.extend([(5, 5)])
        assert bbox.extmin == (0, 0)
        assert bbox.extmax == (10, 10)

        bbox.extend([(15, 16)])
        assert bbox.extmin == (0, 0)
        assert bbox.extmax == (15, 16)

        bbox.extend([(-15, -16)])
        assert bbox.extmin == (-15, -16)
        assert bbox.extmax == (15, 16)

    def test_size(self):
        bbox = BoundingBox2d([(-2, -2), (8, 8)])
        assert bbox.size == (10, 10)

    def test_center(self):
        bbox = BoundingBox2d([(-1, -1), (9, 9)])
        assert bbox.center == (4, 4)

    def test_rect_vertices_for_empty_bbox_raises_value_error(self):
        with pytest.raises(ValueError):
            BoundingBox2d().rect_vertices()

    def test_rect_vertices_returns_vertices_in_counter_clockwise_order(self):
        bbox = BoundingBox2d([(0, 0, 0), (1, 2, 3)])
        assert bbox.rect_vertices() == Vec2.tuple([(0, 0), (1, 0), (1, 2), (0, 2)])

    def test_contains_other_bounding_box(self):
        box_a = BoundingBox2d([(0, 0), (10, 10)])
        box_b = BoundingBox2d([(1, 1), (9, 9)])
        box_c = BoundingBox2d([(1, 1), (11, 11)])
        assert box_a.contains(box_b) is True
        assert box_a.contains(box_a) is True  # self contained!
        assert box_b.contains(box_a) is False
        assert box_a.contains(box_c) is False

    def test_2d_box_contains_3d_box(self):
        # casting is required since v1.2 for valid type-checking
        box_a = BoundingBox2d(
            [(0, 0), (10, 10)]
        )  # this is flat-land, z-axis does not exist
        box_b = BoundingBox([(1, 1, 1), (9, 9, 9)])
        assert box_a.contains(BoundingBox2d(box_b)) is True, "z-axis should be ignored"

    def test_3d_box_contains_2d_box(self):
        # casting is required since v1.2 for valid type-checking
        box_a = BoundingBox2d([(1, 1), (9, 9)])  # lives in the xy-plane, z-axis is 0
        box_b = BoundingBox([(0, 0, 0), (10, 10, 10)])
        assert box_b.contains(BoundingBox(box_a)) is True, "xy-plane is included"
        box_c = BoundingBox([(0, 0, 1), (10, 10, 10)])
        assert box_c.contains(BoundingBox(box_a)) is False, "xy-plane is not included"

    def test_grow_bounding_box(self):
        box = BoundingBox2d([(0, 0), (1, 1)])
        box.grow(1)
        assert box.extmin.isclose((-1, -1))
        assert box.extmax.isclose((2, 2))

    def test_has_overlap_accepts_3d_bounding_box(self):
        bbox1 = BoundingBox([(0, 0, 10), (10, 10, 10)])  # z-axis are ignored
        bbox2 = BoundingBox2d([(1, 1), (9, 9)])
        assert bbox2.has_overlap(bbox1) is True

    def test_has_intersection_accepts_3d_bounding_box(self):
        bbox1 = BoundingBox([(0, 0, 10), (10, 10, 10)])  # z-axis are ignored
        bbox2 = BoundingBox2d([(1, 1), (9, 9)])
        assert bbox2.has_intersection(bbox1) is True


class Test2DIntersection:
    def test_accept_3d_box(self):
        b1 = BoundingBox2d([(1, 1), (9, 9)])
        b2 = BoundingBox([(0, 0, 10), (10, 10, 10)])  # z-axis are ignored
        b = b1.intersection(b2)
        assert b.size.isclose((8, 8))

    def test_empty_box_intersection(self):
        b = BoundingBox2d().intersection(BoundingBox2d())
        assert b.is_empty is True

    def test_no_intersection(self):
        b1 = BoundingBox2d([(0, 0), (1, 1)])
        b2 = BoundingBox2d([(2, 2), (3, 3)])
        b = b1.intersection(b2)
        assert b.is_empty is True

    def test_touches_at_one_corner(self):
        b1 = BoundingBox2d([(0, 0), (1, 1)])
        b2 = BoundingBox2d([(1, 1), (2, 2)])
        b = b1.intersection(b2)
        assert b.is_empty is True

    def test_half_intersection(self):
        b1 = BoundingBox2d([(0, 0), (2, 2)])
        b2 = BoundingBox2d([(1, 1), (3, 3)])
        b = b1.intersection(b2)
        assert b.size.isclose((1, 1))
        assert b.extmin.isclose((1, 1))
        assert b.extmax.isclose((2, 2))

    @pytest.mark.parametrize(
        "v1, v2",
        [
            ([(0, 0), (2, 2)], [(1, 1), (3, 3)]),
            ([(-1, -1), (1, 1)], [(0, 0), (2, 2)]),
            ([(-2, -2), (0, 0)], [(-3, -3), (-1, -1)]),
        ],
    )
    def test_multiple_intersections(self, v1, v2):
        b1 = BoundingBox2d(v1)
        b2 = BoundingBox2d(v2)
        b = b1.intersection(b2)
        assert b.size.isclose((1, 1))

    def test_full_intersection(self):
        b1 = BoundingBox2d([(0, 0), (2, 2)])
        b = b1.intersection(b1)
        assert b.size.isclose((2, 2))
        assert b.extmin.isclose((0, 0))
        assert b.extmax.isclose((2, 2))

    def test_smaller_inside_bigger_intersection(self):
        b1 = BoundingBox2d([(0, 0), (3, 3)])
        b2 = BoundingBox2d([(1, 1), (2, 2)])
        b = b1.intersection(b2)
        assert b.size.isclose((1, 1))
        assert b.extmin.isclose((1, 1))
        assert b.extmax.isclose((2, 2))

    def test_intersection_box_without_an_area_is_empty(self):
        b1 = BoundingBox2d([(0, 0), (0, 3)])  # has no area
        b2 = BoundingBox2d([(-1, 1), (1, 1)])  # has no area

        b = b1.intersection(b2)
        assert b.is_empty is True  # intersection has no area


class Test3DIntersection:
    def test_accept_3d_box(self):
        b1 = BoundingBox([(0, 0, -1), (10, 10, 10)])
        b2 = BoundingBox2d([(1, 1), (9, 9)])  # z-axis is 0
        b = b1.intersection(b2)
        assert b.is_empty is True  # has no volume!

    def test_empty_box_intersection(self):
        b = BoundingBox().intersection(BoundingBox())
        assert b.is_empty is True

    def test_no_intersection(self):
        b1 = BoundingBox([(0, 0, 0), (1, 1, 1)])
        b2 = BoundingBox([(2, 2, 2), (3, 3, 3)])
        b = b1.intersection(b2)
        assert b.is_empty is True

    def test_touches_at_one_corner(self):
        b1 = BoundingBox([(0, 0, 0), (1, 1, 1)])
        b2 = BoundingBox([(1, 1, 1), (2, 2, 2)])
        b = b1.intersection(b2)
        assert b.is_empty is True

    def test_half_intersection(self):
        b1 = BoundingBox([(0, 0, 0), (2, 2, 2)])
        b2 = BoundingBox([(1, 1, 1), (3, 3, 3)])
        b = b1.intersection(b2)
        assert b.size.isclose((1, 1, 1))
        assert b.extmin.isclose((1, 1, 1))
        assert b.extmax.isclose((2, 2, 2))

    @pytest.mark.parametrize(
        "v1, v2",
        [
            ([(0, 0, 0), (2, 2, 2)], [(1, 1, 1), (3, 3, 3)]),
            ([(-1, -1, -1), (1, 1, 1)], [(0, 0, 0), (2, 2, 2)]),
            ([(-2, -2, -2), (0, 0, 0)], [(-3, -3, -3), (-1, -1, -1)]),
        ],
    )
    def test_multiple_intersections(self, v1, v2):
        b1 = BoundingBox(v1)
        b2 = BoundingBox(v2)
        b = b1.intersection(b2)
        assert b.size.isclose((1, 1, 1))

    def test_full_intersection(self):
        b1 = BoundingBox([(0, 0, 0), (2, 2, 2)])
        b = b1.intersection(b1)
        assert b.size.isclose((2, 2, 2))
        assert b.extmin.isclose((0, 0, 0))
        assert b.extmax.isclose((2, 2, 2))

    def test_smaller_inside_bigger_intersection(self):
        b1 = BoundingBox([(0, 0, 0), (3, 3, 3)])
        b2 = BoundingBox([(1, 1, 1), (2, 2, 2)])
        b = b1.intersection(b2)
        assert b.size.isclose((1, 1, 1))
        assert b.extmin.isclose((1, 1, 1))
        assert b.extmax.isclose((2, 2, 2))

    def test_intersection_box_without_a_volume_is_empty(self):
        b1 = BoundingBox2d([(0, 0, 0), (0, 3, 0)])  # has no volume
        b2 = BoundingBox2d([(-1, 1, 0), (1, 1, 0)])  # has no volume
        b = b1.intersection(b2)
        assert b.is_empty is True  # intersection has no volume