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