1use crate::{
4 bounding::{Bounded2d, BoundingCircle, BoundingVolume},
5 ops,
6 primitives::{
7 Capsule3d, Cone, ConicalFrustum, Cuboid, Cylinder, InfinitePlane3d, Line3d, Polyline3d,
8 Segment3d, Sphere, Torus, Triangle2d, Triangle3d,
9 },
10 Isometry2d, Isometry3d, Mat3, Vec2, Vec3, Vec3A,
11};
12
13#[cfg(feature = "alloc")]
14use crate::primitives::BoxedPolyline3d;
15
16use super::{Aabb3d, Bounded3d, BoundingSphere};
17
18impl Bounded3d for Sphere {
19 fn aabb_3d(&self, isometry: impl Into<Isometry3d>) -> Aabb3d {
20 let isometry = isometry.into();
21 Aabb3d::new(isometry.translation, Vec3::splat(self.radius))
22 }
23
24 fn bounding_sphere(&self, isometry: impl Into<Isometry3d>) -> BoundingSphere {
25 let isometry = isometry.into();
26 BoundingSphere::new(isometry.translation, self.radius)
27 }
28}
29
30impl Bounded3d for InfinitePlane3d {
31 fn aabb_3d(&self, isometry: impl Into<Isometry3d>) -> Aabb3d {
32 let isometry = isometry.into();
33
34 let normal = isometry.rotation * *self.normal;
35 let facing_x = normal == Vec3::X || normal == Vec3::NEG_X;
36 let facing_y = normal == Vec3::Y || normal == Vec3::NEG_Y;
37 let facing_z = normal == Vec3::Z || normal == Vec3::NEG_Z;
38
39 let half_width = if facing_x { 0.0 } else { f32::MAX / 2.0 };
42 let half_height = if facing_y { 0.0 } else { f32::MAX / 2.0 };
43 let half_depth = if facing_z { 0.0 } else { f32::MAX / 2.0 };
44 let half_size = Vec3A::new(half_width, half_height, half_depth);
45
46 Aabb3d::new(isometry.translation, half_size)
47 }
48
49 fn bounding_sphere(&self, isometry: impl Into<Isometry3d>) -> BoundingSphere {
50 let isometry = isometry.into();
51 BoundingSphere::new(isometry.translation, f32::MAX / 2.0)
52 }
53}
54
55impl Bounded3d for Line3d {
56 fn aabb_3d(&self, isometry: impl Into<Isometry3d>) -> Aabb3d {
57 let isometry = isometry.into();
58 let direction = isometry.rotation * *self.direction;
59
60 let max = f32::MAX / 2.0;
63 let half_width = if direction.x == 0.0 { 0.0 } else { max };
64 let half_height = if direction.y == 0.0 { 0.0 } else { max };
65 let half_depth = if direction.z == 0.0 { 0.0 } else { max };
66 let half_size = Vec3A::new(half_width, half_height, half_depth);
67
68 Aabb3d::new(isometry.translation, half_size)
69 }
70
71 fn bounding_sphere(&self, isometry: impl Into<Isometry3d>) -> BoundingSphere {
72 let isometry = isometry.into();
73 BoundingSphere::new(isometry.translation, f32::MAX / 2.0)
74 }
75}
76
77impl Bounded3d for Segment3d {
78 fn aabb_3d(&self, isometry: impl Into<Isometry3d>) -> Aabb3d {
79 Aabb3d::from_point_cloud(isometry, [self.point1(), self.point2()].iter().copied())
80 }
81
82 fn bounding_sphere(&self, isometry: impl Into<Isometry3d>) -> BoundingSphere {
83 let isometry = isometry.into();
84 let local_sphere = BoundingSphere::new(self.center(), self.length() / 2.);
85 local_sphere.transformed_by(isometry.translation, isometry.rotation)
86 }
87}
88
89impl<const N: usize> Bounded3d for Polyline3d<N> {
90 fn aabb_3d(&self, isometry: impl Into<Isometry3d>) -> Aabb3d {
91 Aabb3d::from_point_cloud(isometry, self.vertices.iter().copied())
92 }
93
94 fn bounding_sphere(&self, isometry: impl Into<Isometry3d>) -> BoundingSphere {
95 BoundingSphere::from_point_cloud(isometry, &self.vertices)
96 }
97}
98
99#[cfg(feature = "alloc")]
100impl Bounded3d for BoxedPolyline3d {
101 fn aabb_3d(&self, isometry: impl Into<Isometry3d>) -> Aabb3d {
102 Aabb3d::from_point_cloud(isometry, self.vertices.iter().copied())
103 }
104
105 fn bounding_sphere(&self, isometry: impl Into<Isometry3d>) -> BoundingSphere {
106 BoundingSphere::from_point_cloud(isometry, &self.vertices)
107 }
108}
109
110impl Bounded3d for Cuboid {
111 fn aabb_3d(&self, isometry: impl Into<Isometry3d>) -> Aabb3d {
112 let isometry = isometry.into();
113
114 let rot_mat = Mat3::from_quat(isometry.rotation);
117 let abs_rot_mat = Mat3::from_cols(
118 rot_mat.x_axis.abs(),
119 rot_mat.y_axis.abs(),
120 rot_mat.z_axis.abs(),
121 );
122 let half_size = abs_rot_mat * self.half_size;
123
124 Aabb3d::new(isometry.translation, half_size)
125 }
126
127 fn bounding_sphere(&self, isometry: impl Into<Isometry3d>) -> BoundingSphere {
128 let isometry = isometry.into();
129 BoundingSphere::new(isometry.translation, self.half_size.length())
130 }
131}
132
133impl Bounded3d for Cylinder {
134 fn aabb_3d(&self, isometry: impl Into<Isometry3d>) -> Aabb3d {
135 let isometry = isometry.into();
138
139 let segment_dir = isometry.rotation * Vec3A::Y;
140 let top = segment_dir * self.half_height;
141 let bottom = -top;
142
143 let e = (Vec3A::ONE - segment_dir * segment_dir).max(Vec3A::ZERO);
144 let half_size = self.radius * Vec3A::new(ops::sqrt(e.x), ops::sqrt(e.y), ops::sqrt(e.z));
145
146 Aabb3d {
147 min: isometry.translation + (top - half_size).min(bottom - half_size),
148 max: isometry.translation + (top + half_size).max(bottom + half_size),
149 }
150 }
151
152 fn bounding_sphere(&self, isometry: impl Into<Isometry3d>) -> BoundingSphere {
153 let isometry = isometry.into();
154 let radius = ops::hypot(self.radius, self.half_height);
155 BoundingSphere::new(isometry.translation, radius)
156 }
157}
158
159impl Bounded3d for Capsule3d {
160 fn aabb_3d(&self, isometry: impl Into<Isometry3d>) -> Aabb3d {
161 let isometry = isometry.into();
162
163 let segment_dir = isometry.rotation * Vec3A::Y;
165 let top = segment_dir * self.half_length;
166 let bottom = -top;
167
168 let min = bottom.min(top) - Vec3A::splat(self.radius);
170 let max = bottom.max(top) + Vec3A::splat(self.radius);
171
172 Aabb3d {
173 min: min + isometry.translation,
174 max: max + isometry.translation,
175 }
176 }
177
178 fn bounding_sphere(&self, isometry: impl Into<Isometry3d>) -> BoundingSphere {
179 let isometry = isometry.into();
180 BoundingSphere::new(isometry.translation, self.radius + self.half_length)
181 }
182}
183
184impl Bounded3d for Cone {
185 fn aabb_3d(&self, isometry: impl Into<Isometry3d>) -> Aabb3d {
186 let isometry = isometry.into();
189
190 let segment_dir = isometry.rotation * Vec3A::Y;
191 let top = segment_dir * 0.5 * self.height;
192 let bottom = -top;
193
194 let e = (Vec3A::ONE - segment_dir * segment_dir).max(Vec3A::ZERO);
195 let half_extents = Vec3A::new(ops::sqrt(e.x), ops::sqrt(e.y), ops::sqrt(e.z));
196
197 Aabb3d {
198 min: isometry.translation + top.min(bottom - self.radius * half_extents),
199 max: isometry.translation + top.max(bottom + self.radius * half_extents),
200 }
201 }
202
203 fn bounding_sphere(&self, isometry: impl Into<Isometry3d>) -> BoundingSphere {
204 let isometry = isometry.into();
205
206 let half_height = 0.5 * self.height;
208 let triangle = Triangle2d::new(
209 half_height * Vec2::Y,
210 Vec2::new(-self.radius, -half_height),
211 Vec2::new(self.radius, -half_height),
212 );
213
214 let BoundingCircle { circle, center } = triangle.bounding_circle(Isometry2d::IDENTITY);
217
218 BoundingSphere::new(
219 isometry.rotation * Vec3A::from(center.extend(0.0)) + isometry.translation,
220 circle.radius,
221 )
222 }
223}
224
225impl Bounded3d for ConicalFrustum {
226 fn aabb_3d(&self, isometry: impl Into<Isometry3d>) -> Aabb3d {
227 let isometry = isometry.into();
230
231 let segment_dir = isometry.rotation * Vec3A::Y;
232 let top = segment_dir * 0.5 * self.height;
233 let bottom = -top;
234
235 let e = (Vec3A::ONE - segment_dir * segment_dir).max(Vec3A::ZERO);
236 let half_extents = Vec3A::new(ops::sqrt(e.x), ops::sqrt(e.y), ops::sqrt(e.z));
237
238 Aabb3d {
239 min: isometry.translation
240 + (top - self.radius_top * half_extents)
241 .min(bottom - self.radius_bottom * half_extents),
242 max: isometry.translation
243 + (top + self.radius_top * half_extents)
244 .max(bottom + self.radius_bottom * half_extents),
245 }
246 }
247
248 fn bounding_sphere(&self, isometry: impl Into<Isometry3d>) -> BoundingSphere {
249 let isometry = isometry.into();
250 let half_height = 0.5 * self.height;
251
252 let a = Vec2::new(-self.radius_top, half_height);
272 let b = Vec2::new(-self.radius_bottom, -half_height);
273 let ab = a - b;
274 let ab_midpoint = b + 0.5 * ab;
275 let bisector = ab.perp();
276
277 let circumcenter_y = -ab_midpoint.x / bisector.x * bisector.y;
291
292 let (center, radius) = if circumcenter_y <= -half_height {
295 (Vec2::new(0.0, -half_height), self.radius_bottom)
296 } else if circumcenter_y >= half_height {
297 (Vec2::new(0.0, half_height), self.radius_top)
298 } else {
299 let circumcenter = Vec2::new(0.0, circumcenter_y);
300 (circumcenter, a.distance(circumcenter))
302 };
303
304 BoundingSphere::new(
305 isometry.translation + isometry.rotation * Vec3A::from(center.extend(0.0)),
306 radius,
307 )
308 }
309}
310
311impl Bounded3d for Torus {
312 fn aabb_3d(&self, isometry: impl Into<Isometry3d>) -> Aabb3d {
313 let isometry = isometry.into();
314
315 let normal = isometry.rotation * Vec3A::Y;
318 let e = (Vec3A::ONE - normal * normal).max(Vec3A::ZERO);
319 let disc_half_size =
320 self.major_radius * Vec3A::new(ops::sqrt(e.x), ops::sqrt(e.y), ops::sqrt(e.z));
321
322 let half_size = disc_half_size + Vec3A::splat(self.minor_radius);
324
325 Aabb3d::new(isometry.translation, half_size)
326 }
327
328 fn bounding_sphere(&self, isometry: impl Into<Isometry3d>) -> BoundingSphere {
329 let isometry = isometry.into();
330 BoundingSphere::new(isometry.translation, self.outer_radius())
331 }
332}
333
334impl Bounded3d for Triangle3d {
335 fn aabb_3d(&self, isometry: impl Into<Isometry3d>) -> Aabb3d {
337 let isometry = isometry.into();
338 let [a, b, c] = self.vertices;
339
340 let a = isometry.rotation * a;
341 let b = isometry.rotation * b;
342 let c = isometry.rotation * c;
343
344 let min = Vec3A::from(a.min(b).min(c));
345 let max = Vec3A::from(a.max(b).max(c));
346
347 let bounding_center = (max + min) / 2.0 + isometry.translation;
348 let half_extents = (max - min) / 2.0;
349
350 Aabb3d::new(bounding_center, half_extents)
351 }
352
353 fn bounding_sphere(&self, isometry: impl Into<Isometry3d>) -> BoundingSphere {
359 let isometry = isometry.into();
360
361 if self.is_degenerate() || self.is_obtuse() {
362 let (p1, p2) = self.largest_side();
363 let (p1, p2) = (Vec3A::from(p1), Vec3A::from(p2));
364 let mid_point = (p1 + p2) / 2.0;
365 let radius = mid_point.distance(p1);
366 BoundingSphere::new(mid_point + isometry.translation, radius)
367 } else {
368 let [a, _, _] = self.vertices;
369
370 let circumcenter = self.circumcenter();
371 let radius = circumcenter.distance(a);
372 BoundingSphere::new(Vec3A::from(circumcenter) + isometry.translation, radius)
373 }
374 }
375}
376
377#[cfg(test)]
378mod tests {
379 use crate::{bounding::BoundingVolume, ops, Isometry3d};
380 use glam::{Quat, Vec3, Vec3A};
381
382 use crate::{
383 bounding::Bounded3d,
384 primitives::{
385 Capsule3d, Cone, ConicalFrustum, Cuboid, Cylinder, InfinitePlane3d, Line3d, Polyline3d,
386 Segment3d, Sphere, Torus, Triangle3d,
387 },
388 Dir3,
389 };
390
391 #[test]
392 fn sphere() {
393 let sphere = Sphere { radius: 1.0 };
394 let translation = Vec3::new(2.0, 1.0, 0.0);
395
396 let aabb = sphere.aabb_3d(translation);
397 assert_eq!(aabb.min, Vec3A::new(1.0, 0.0, -1.0));
398 assert_eq!(aabb.max, Vec3A::new(3.0, 2.0, 1.0));
399
400 let bounding_sphere = sphere.bounding_sphere(translation);
401 assert_eq!(bounding_sphere.center, translation.into());
402 assert_eq!(bounding_sphere.radius(), 1.0);
403 }
404
405 #[test]
406 fn plane() {
407 let translation = Vec3::new(2.0, 1.0, 0.0);
408
409 let aabb1 = InfinitePlane3d::new(Vec3::X).aabb_3d(translation);
410 assert_eq!(aabb1.min, Vec3A::new(2.0, -f32::MAX / 2.0, -f32::MAX / 2.0));
411 assert_eq!(aabb1.max, Vec3A::new(2.0, f32::MAX / 2.0, f32::MAX / 2.0));
412
413 let aabb2 = InfinitePlane3d::new(Vec3::Y).aabb_3d(translation);
414 assert_eq!(aabb2.min, Vec3A::new(-f32::MAX / 2.0, 1.0, -f32::MAX / 2.0));
415 assert_eq!(aabb2.max, Vec3A::new(f32::MAX / 2.0, 1.0, f32::MAX / 2.0));
416
417 let aabb3 = InfinitePlane3d::new(Vec3::Z).aabb_3d(translation);
418 assert_eq!(aabb3.min, Vec3A::new(-f32::MAX / 2.0, -f32::MAX / 2.0, 0.0));
419 assert_eq!(aabb3.max, Vec3A::new(f32::MAX / 2.0, f32::MAX / 2.0, 0.0));
420
421 let aabb4 = InfinitePlane3d::new(Vec3::ONE).aabb_3d(translation);
422 assert_eq!(aabb4.min, Vec3A::splat(-f32::MAX / 2.0));
423 assert_eq!(aabb4.max, Vec3A::splat(f32::MAX / 2.0));
424
425 let bounding_sphere = InfinitePlane3d::new(Vec3::Y).bounding_sphere(translation);
426 assert_eq!(bounding_sphere.center, translation.into());
427 assert_eq!(bounding_sphere.radius(), f32::MAX / 2.0);
428 }
429
430 #[test]
431 fn line() {
432 let translation = Vec3::new(2.0, 1.0, 0.0);
433
434 let aabb1 = Line3d { direction: Dir3::Y }.aabb_3d(translation);
435 assert_eq!(aabb1.min, Vec3A::new(2.0, -f32::MAX / 2.0, 0.0));
436 assert_eq!(aabb1.max, Vec3A::new(2.0, f32::MAX / 2.0, 0.0));
437
438 let aabb2 = Line3d { direction: Dir3::X }.aabb_3d(translation);
439 assert_eq!(aabb2.min, Vec3A::new(-f32::MAX / 2.0, 1.0, 0.0));
440 assert_eq!(aabb2.max, Vec3A::new(f32::MAX / 2.0, 1.0, 0.0));
441
442 let aabb3 = Line3d { direction: Dir3::Z }.aabb_3d(translation);
443 assert_eq!(aabb3.min, Vec3A::new(2.0, 1.0, -f32::MAX / 2.0));
444 assert_eq!(aabb3.max, Vec3A::new(2.0, 1.0, f32::MAX / 2.0));
445
446 let aabb4 = Line3d {
447 direction: Dir3::from_xyz(1.0, 1.0, 1.0).unwrap(),
448 }
449 .aabb_3d(translation);
450 assert_eq!(aabb4.min, Vec3A::splat(-f32::MAX / 2.0));
451 assert_eq!(aabb4.max, Vec3A::splat(f32::MAX / 2.0));
452
453 let bounding_sphere = Line3d { direction: Dir3::Y }.bounding_sphere(translation);
454 assert_eq!(bounding_sphere.center, translation.into());
455 assert_eq!(bounding_sphere.radius(), f32::MAX / 2.0);
456 }
457
458 #[test]
459 fn segment() {
460 let segment = Segment3d::new(Vec3::new(-1.0, -0.5, 0.0), Vec3::new(1.0, 0.5, 0.0));
461 let translation = Vec3::new(2.0, 1.0, 0.0);
462
463 let aabb = segment.aabb_3d(translation);
464 assert_eq!(aabb.min, Vec3A::new(1.0, 0.5, 0.0));
465 assert_eq!(aabb.max, Vec3A::new(3.0, 1.5, 0.0));
466
467 let bounding_sphere = segment.bounding_sphere(translation);
468 assert_eq!(bounding_sphere.center, translation.into());
469 assert_eq!(bounding_sphere.radius(), ops::hypot(1.0, 0.5));
470 }
471
472 #[test]
473 fn polyline() {
474 let polyline = Polyline3d::<4>::new([
475 Vec3::ONE,
476 Vec3::new(-1.0, 1.0, 1.0),
477 Vec3::NEG_ONE,
478 Vec3::new(1.0, -1.0, -1.0),
479 ]);
480 let translation = Vec3::new(2.0, 1.0, 0.0);
481
482 let aabb = polyline.aabb_3d(translation);
483 assert_eq!(aabb.min, Vec3A::new(1.0, 0.0, -1.0));
484 assert_eq!(aabb.max, Vec3A::new(3.0, 2.0, 1.0));
485
486 let bounding_sphere = polyline.bounding_sphere(translation);
487 assert_eq!(bounding_sphere.center, translation.into());
488 assert_eq!(
489 bounding_sphere.radius(),
490 ops::hypot(ops::hypot(1.0, 1.0), 1.0)
491 );
492 }
493
494 #[test]
495 fn cuboid() {
496 let cuboid = Cuboid::new(2.0, 1.0, 1.0);
497 let translation = Vec3::new(2.0, 1.0, 0.0);
498
499 let aabb = cuboid.aabb_3d(Isometry3d::new(
500 translation,
501 Quat::from_rotation_z(core::f32::consts::FRAC_PI_4),
502 ));
503 let expected_half_size = Vec3A::new(1.0606601, 1.0606601, 0.5);
504 assert_eq!(aabb.min, Vec3A::from(translation) - expected_half_size);
505 assert_eq!(aabb.max, Vec3A::from(translation) + expected_half_size);
506
507 let bounding_sphere = cuboid.bounding_sphere(translation);
508 assert_eq!(bounding_sphere.center, translation.into());
509 assert_eq!(
510 bounding_sphere.radius(),
511 ops::hypot(ops::hypot(1.0, 0.5), 0.5)
512 );
513 }
514
515 #[test]
516 fn cylinder() {
517 let cylinder = Cylinder::new(0.5, 2.0);
518 let translation = Vec3::new(2.0, 1.0, 0.0);
519
520 let aabb = cylinder.aabb_3d(translation);
521 assert_eq!(
522 aabb.min,
523 Vec3A::from(translation) - Vec3A::new(0.5, 1.0, 0.5)
524 );
525 assert_eq!(
526 aabb.max,
527 Vec3A::from(translation) + Vec3A::new(0.5, 1.0, 0.5)
528 );
529
530 let bounding_sphere = cylinder.bounding_sphere(translation);
531 assert_eq!(bounding_sphere.center, translation.into());
532 assert_eq!(bounding_sphere.radius(), ops::hypot(1.0, 0.5));
533 }
534
535 #[test]
536 fn capsule() {
537 let capsule = Capsule3d::new(0.5, 2.0);
538 let translation = Vec3::new(2.0, 1.0, 0.0);
539
540 let aabb = capsule.aabb_3d(translation);
541 assert_eq!(
542 aabb.min,
543 Vec3A::from(translation) - Vec3A::new(0.5, 1.5, 0.5)
544 );
545 assert_eq!(
546 aabb.max,
547 Vec3A::from(translation) + Vec3A::new(0.5, 1.5, 0.5)
548 );
549
550 let bounding_sphere = capsule.bounding_sphere(translation);
551 assert_eq!(bounding_sphere.center, translation.into());
552 assert_eq!(bounding_sphere.radius(), 1.5);
553 }
554
555 #[test]
556 fn cone() {
557 let cone = Cone {
558 radius: 1.0,
559 height: 2.0,
560 };
561 let translation = Vec3::new(2.0, 1.0, 0.0);
562
563 let aabb = cone.aabb_3d(translation);
564 assert_eq!(aabb.min, Vec3A::new(1.0, 0.0, -1.0));
565 assert_eq!(aabb.max, Vec3A::new(3.0, 2.0, 1.0));
566
567 let bounding_sphere = cone.bounding_sphere(translation);
568 assert_eq!(
569 bounding_sphere.center,
570 Vec3A::from(translation) + Vec3A::NEG_Y * 0.25
571 );
572 assert_eq!(bounding_sphere.radius(), 1.25);
573 }
574
575 #[test]
576 fn conical_frustum() {
577 let conical_frustum = ConicalFrustum {
578 radius_top: 0.5,
579 radius_bottom: 1.0,
580 height: 2.0,
581 };
582 let translation = Vec3::new(2.0, 1.0, 0.0);
583
584 let aabb = conical_frustum.aabb_3d(translation);
585 assert_eq!(aabb.min, Vec3A::new(1.0, 0.0, -1.0));
586 assert_eq!(aabb.max, Vec3A::new(3.0, 2.0, 1.0));
587
588 let bounding_sphere = conical_frustum.bounding_sphere(translation);
589 assert_eq!(
590 bounding_sphere.center,
591 Vec3A::from(translation) + Vec3A::NEG_Y * 0.1875
592 );
593 assert_eq!(bounding_sphere.radius(), 1.2884705);
594 }
595
596 #[test]
597 fn wide_conical_frustum() {
598 let conical_frustum = ConicalFrustum {
599 radius_top: 0.5,
600 radius_bottom: 5.0,
601 height: 1.0,
602 };
603 let translation = Vec3::new(2.0, 1.0, 0.0);
604
605 let aabb = conical_frustum.aabb_3d(translation);
606 assert_eq!(aabb.min, Vec3A::new(-3.0, 0.5, -5.0));
607 assert_eq!(aabb.max, Vec3A::new(7.0, 1.5, 5.0));
608
609 let bounding_sphere = conical_frustum.bounding_sphere(translation);
612 assert_eq!(
613 bounding_sphere.center,
614 Vec3A::from(translation) + Vec3A::NEG_Y * 0.5
615 );
616 assert_eq!(bounding_sphere.radius(), 5.0);
617 }
618
619 #[test]
620 fn torus() {
621 let torus = Torus {
622 minor_radius: 0.5,
623 major_radius: 1.0,
624 };
625 let translation = Vec3::new(2.0, 1.0, 0.0);
626
627 let aabb = torus.aabb_3d(translation);
628 assert_eq!(aabb.min, Vec3A::new(0.5, 0.5, -1.5));
629 assert_eq!(aabb.max, Vec3A::new(3.5, 1.5, 1.5));
630
631 let bounding_sphere = torus.bounding_sphere(translation);
632 assert_eq!(bounding_sphere.center, translation.into());
633 assert_eq!(bounding_sphere.radius(), 1.5);
634 }
635
636 #[test]
637 fn triangle3d() {
638 let zero_degenerate_triangle = Triangle3d::new(Vec3::ZERO, Vec3::ZERO, Vec3::ZERO);
639
640 let br = zero_degenerate_triangle.aabb_3d(Isometry3d::IDENTITY);
641 assert_eq!(
642 br.center(),
643 Vec3::ZERO.into(),
644 "incorrect bounding box center"
645 );
646 assert_eq!(
647 br.half_size(),
648 Vec3::ZERO.into(),
649 "incorrect bounding box half extents"
650 );
651
652 let bs = zero_degenerate_triangle.bounding_sphere(Isometry3d::IDENTITY);
653 assert_eq!(
654 bs.center,
655 Vec3::ZERO.into(),
656 "incorrect bounding sphere center"
657 );
658 assert_eq!(bs.sphere.radius, 0.0, "incorrect bounding sphere radius");
659
660 let dup_degenerate_triangle = Triangle3d::new(Vec3::ZERO, Vec3::X, Vec3::X);
661 let bs = dup_degenerate_triangle.bounding_sphere(Isometry3d::IDENTITY);
662 assert_eq!(
663 bs.center,
664 Vec3::new(0.5, 0.0, 0.0).into(),
665 "incorrect bounding sphere center"
666 );
667 assert_eq!(bs.sphere.radius, 0.5, "incorrect bounding sphere radius");
668 let br = dup_degenerate_triangle.aabb_3d(Isometry3d::IDENTITY);
669 assert_eq!(
670 br.center(),
671 Vec3::new(0.5, 0.0, 0.0).into(),
672 "incorrect bounding box center"
673 );
674 assert_eq!(
675 br.half_size(),
676 Vec3::new(0.5, 0.0, 0.0).into(),
677 "incorrect bounding box half extents"
678 );
679
680 let collinear_degenerate_triangle = Triangle3d::new(Vec3::NEG_X, Vec3::ZERO, Vec3::X);
681 let bs = collinear_degenerate_triangle.bounding_sphere(Isometry3d::IDENTITY);
682 assert_eq!(
683 bs.center,
684 Vec3::ZERO.into(),
685 "incorrect bounding sphere center"
686 );
687 assert_eq!(bs.sphere.radius, 1.0, "incorrect bounding sphere radius");
688 let br = collinear_degenerate_triangle.aabb_3d(Isometry3d::IDENTITY);
689 assert_eq!(
690 br.center(),
691 Vec3::ZERO.into(),
692 "incorrect bounding box center"
693 );
694 assert_eq!(
695 br.half_size(),
696 Vec3::new(1.0, 0.0, 0.0).into(),
697 "incorrect bounding box half extents"
698 );
699 }
700}