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