1use std::ops::{Add, AddAssign, Sub, SubAssign};
84
85use na::point;
86
87use super::Interval;
88use crate::aabb2::Aabb2;
89use crate::math::{Isometry3, Point3, Real, Vec3};
90use crate::shape::*;
91use crate::Ray;
92
93#[derive(Copy, Clone, Default, Debug, PartialEq)]
130#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
131#[repr(C)]
132pub struct Aabb3 {
133 min: Point3,
135 max: Point3,
137}
138
139impl Aabb3 {
140 pub const ANTI_INFINITE: Self = Self {
159 min: point![Real::MAX, Real::MAX, Real::MAX],
160 max: point![Real::MIN, Real::MIN, Real::MIN],
161 };
162 pub const ZERO: Aabb3 = Self {
168 min: point![0.0, 0.0, 0.0],
169 max: point![0.0, 0.0, 0.0],
170 };
171
172 #[inline]
173 #[must_use]
174 pub fn new(p1: impl Into<[Real; 3]>, p2: impl Into<[Real; 3]>) -> Aabb3 {
175 let p1: Point3 = p1.into().into();
176 let p2: Point3 = p2.into().into();
177 Aabb3 {
178 min: Point3::new(
179 Real::min(p1.x, p2.x),
180 Real::min(p1.y, p2.y),
181 Real::min(p1.z, p2.z),
182 ),
183 max: Point3::new(
184 Real::max(p1.x, p2.x),
185 Real::max(p1.y, p2.y),
186 Real::max(p1.z, p2.z),
187 ),
188 }
189 }
190
191 #[inline]
196 #[must_use]
197 pub fn new_unchecked(min: impl Into<Point3>, max: impl Into<Point3>) -> Self {
198 let min = min.into();
199 let max = max.into();
200 #[cfg(debug_assertions)]
201 if min != Self::ANTI_INFINITE.min || max != Self::ANTI_INFINITE.max {
202 let error_msg = format!("min > max, min = {min}, max = {max}");
204 debug_assert!(min.x <= max.x, "{}", error_msg);
205 debug_assert!(min.y <= max.y, "{}", error_msg);
206 debug_assert!(min.z <= max.z, "{}", error_msg);
207 }
208 Self { min, max }
209 }
210
211 #[inline]
213 #[must_use]
214 pub fn from_array_unchecked(values: [Real; 6]) -> Self {
215 Aabb3 {
216 min: Point3::new(values[0], values[1], values[2]),
217 max: Point3::new(values[3], values[4], values[5]),
218 }
219 }
220
221 #[inline]
223 #[must_use]
224 pub fn from_center_extents(center: impl Into<Point3>, extents: impl Into<Vec3>) -> Self {
225 let center = center.into();
226 let extents = extents.into();
227 Aabb3::new_unchecked(center - extents, center + extents)
228 }
229
230 #[inline]
232 #[must_use]
233 pub fn min(&self) -> Point3 {
234 self.min
235 }
236
237 #[inline]
239 #[must_use]
240 pub fn max(&self) -> Point3 {
241 self.max
242 }
243
244 #[inline]
250 #[must_use]
251 pub fn get_interval(&self, axis: usize) -> Interval {
252 debug_assert!(axis < 3);
253 Interval::new(self.min[axis], self.max[axis])
254 }
255
256 #[inline]
262 pub fn set_min_at(&mut self, axis: usize, value: Real) {
263 debug_assert!(axis < 3);
264 assert!(value <= self.max[axis]);
265 self.min[axis] = value;
266 }
267
268 #[inline]
274 pub fn set_max_at(&mut self, axis: usize, value: Real) {
275 debug_assert!(axis < 3);
276 assert!(self.min[axis] <= value);
277 self.max[axis] = value;
278 }
279
280 #[inline]
282 pub fn grow(&mut self, p: impl Into<Point3>) {
283 let p = p.into();
284 self.min = self.min.inf(&p);
285 self.max = self.max.sup(&p);
286 }
287
288 #[inline]
289 pub fn merge(&mut self, other: &Self) {
290 self.min = self.min.inf(&other.min);
291 self.max = self.max.sup(&other.max);
292 }
293
294 #[inline]
295 pub fn expand(&mut self, margin: Real) {
296 self.min -= Vec3::new(margin, margin, margin);
297 self.max += Vec3::new(margin, margin, margin);
298 }
299
300 #[inline]
302 pub fn offset(&mut self, offset: impl Into<[Real; 3]>) {
303 let offset = Vec3::from(offset.into());
304 self.min += offset;
305 self.max += offset;
306 }
307
308 #[inline]
310 pub fn with_offset(mut self, offset: impl Into<[Real; 3]>) -> Self {
311 self.offset(offset);
312 self
313 }
314
315 #[inline]
316 #[must_use]
317 pub fn corners(&self) -> [Point3; 8] {
318 let min = self.min;
319 let max = self.max;
320
321 [
323 min, Point3::new(min.x, min.y, max.z), Point3::new(min.x, max.y, min.z), Point3::new(min.x, max.y, max.z), Point3::new(max.x, min.y, min.z), Point3::new(max.x, min.y, max.z), Point3::new(max.x, max.y, min.z), max, ]
332 }
333
334 #[inline]
336 #[must_use]
337 pub fn with_margin(&self, margin: impl Into<[Real; 3]>) -> Self {
338 let margin = Vec3::from(margin.into());
339 let min = self.min - margin;
340 let max = self.max + margin;
341 Self::new_unchecked(min, max)
342 }
343
344 #[inline]
346 #[must_use]
347 pub fn transform(&self, transform: impl Into<Isometry3>) -> Self {
348 let transform = transform.into();
349 let corners = self.corners();
350 let c0 = transform * corners[0];
351 let c1 = transform * corners[1];
352 let mut aabb = Aabb3::new(c0, c1);
353 for corner in corners.iter().skip(2) {
354 aabb.grow(transform * *corner);
355 }
356 aabb
357 }
358
359 #[inline]
361 #[must_use]
362 pub fn center(&self) -> Point3 {
363 const HALF: Real = 0.5;
364 Point3::from((self.min.coords + self.max.coords) * HALF)
365 }
366
367 #[inline]
369 #[must_use]
370 pub fn size(&self) -> Vec3 {
371 self.max - self.min
372 }
373
374 #[inline]
375 #[must_use]
376 pub fn get_extents(&self) -> Vec3 {
377 const HALF: Real = 0.5;
378 self.size() * HALF
379 }
380
381 #[inline]
383 #[must_use]
384 pub fn overlap_test(&self, rhs: &Aabb3) -> bool {
385 Self::overlap_test_1d(self.min[0], self.max[0], rhs.min[0], rhs.max[0])
386 && Self::overlap_test_1d(self.min[1], self.max[1], rhs.min[1], rhs.max[1])
387 && Self::overlap_test_1d(self.min[2], self.max[2], rhs.min[2], rhs.max[2])
388 }
389
390 #[inline]
391 fn overlap_test_1d(min0: Real, max0: Real, min1: Real, max1: Real) -> bool {
392 max0 > min1 && min0 < max1
393 }
394
395 #[inline]
396 #[must_use]
397 pub fn raycast(&self, ray: Ray, max_distance: Real) -> bool {
398 self.raycast_by_one_over_direction(ray.origin, ray.one_over_direction(), max_distance)
399 }
400
401 #[inline]
410 #[must_use]
411 pub fn raycast_by_one_over_direction(
412 &self,
413 origin: impl Into<[Real; 3]>,
414 one_over_direction: impl Into<[Real; 3]>,
415 max_distance: Real,
416 ) -> bool {
417 self.raycast_by_one_over_direction_impl(origin, one_over_direction, max_distance)
418 .is_some()
419 }
420
421 #[inline]
426 pub fn raycast_by_one_over_direction_impl(
427 &self,
428 origin: impl Into<[Real; 3]>,
429 one_over_direction: impl Into<[Real; 3]>,
430 max_distance: Real,
431 ) -> Option<(Vec3, Real)> {
432 let origin = Point3::from(origin.into());
433 let one_over_direction = Vec3::from(one_over_direction.into());
434 let t0 = (self.min - origin).component_mul(&one_over_direction);
435 let t1 = (self.max - origin).component_mul(&one_over_direction);
436 let term_exit = t0.sup(&t1);
437 let term_entry = t0.inf(&t1);
438 let exit = Real::min(max_distance, term_exit.min());
439 let max_entry = term_entry.max();
440 let term = Real::max(0.0, max_entry);
441 if term <= exit {
442 Some((term_entry, max_entry))
443 } else {
444 None
445 }
446 }
447
448 #[inline]
449 #[must_use]
450 pub fn xz(&self) -> Aabb2 {
451 Aabb2::new(self.min.xz(), self.max.xz())
452 }
453
454 #[inline]
455 #[must_use]
456 pub fn xy(&self) -> Aabb2 {
457 Aabb2::new(self.min.xy(), self.max.xy())
458 }
459
460 #[inline]
461 #[must_use]
462 pub fn yz(&self) -> Aabb2 {
463 Aabb2::new(self.min.yz(), self.max.yz())
464 }
465}
466
467impl Add<Vec3> for Aabb3 {
468 type Output = Aabb3;
469
470 #[inline]
471 fn add(self, rhs: Vec3) -> Self::Output {
472 let mut aabb = self;
473 aabb.offset(rhs);
474 aabb
475 }
476}
477
478impl Sub<Vec3> for Aabb3 {
479 type Output = Aabb3;
480
481 #[inline]
482 fn sub(self, rhs: Vec3) -> Self::Output {
483 let min = self.min - rhs;
484 let max = self.max - rhs;
485 Aabb3::new_unchecked(min, max)
486 }
487}
488
489impl AddAssign<Vec3> for Aabb3 {
490 #[inline]
491 fn add_assign(&mut self, rhs: Vec3) {
492 self.min += rhs;
493 self.max += rhs;
494 }
495}
496
497impl SubAssign<Vec3> for Aabb3 {
498 #[inline]
499 fn sub_assign(&mut self, rhs: Vec3) {
500 self.min -= rhs;
501 self.max -= rhs;
502 }
503}
504
505pub trait ComputeAabb3 {
506 fn compute_aabb(&self) -> Aabb3;
508}
509
510impl ComputeAabb3 for Sphere {
511 #[inline]
512 fn compute_aabb(&self) -> Aabb3 {
513 let r = self.radius();
514 Aabb3::new_unchecked(Point3::new(-r, -r, -r), Point3::new(r, r, r))
515 }
516}
517
518impl ComputeAabb3 for Cuboid {
519 #[inline]
520 fn compute_aabb(&self) -> Aabb3 {
521 let [hx, hy, hz] = self.half_length();
522 Aabb3 {
523 min: Point3::new(-hx, -hy, -hz),
524 max: Point3::new(hx, hy, hz),
525 }
526 }
527}
528
529impl ComputeAabb3 for Capsule {
530 #[inline]
531 fn compute_aabb(&self) -> Aabb3 {
532 let r = self.radius();
533 let hh = self.half_height();
534 Aabb3::new_unchecked(Point3::new(-r, -hh - r, -r), Point3::new(r, hh + r, r))
535 }
536}
537
538impl ComputeAabb3 for Cylinder {
539 #[inline]
540 fn compute_aabb(&self) -> Aabb3 {
541 let radius = self.radius();
542 let half_height = self.half_height();
543 Aabb3::new_unchecked(
544 Point3::new(-radius, -half_height, -radius),
545 Point3::new(radius, half_height, radius),
546 )
547 }
548}
549
550impl ComputeAabb3 for InfinitePlane {
553 fn compute_aabb(&self) -> Aabb3 {
554 let max_aabb = Real::MAX * 0.25;
556 let min_aabb = Real::MIN * 0.25;
557 Aabb3::new_unchecked(
558 Point3::new(min_aabb, min_aabb, min_aabb),
559 Point3::new(max_aabb, 0.0, max_aabb),
560 )
561 }
562}
563
564#[cfg(test)]
565mod tests {
566 use approx::assert_relative_eq;
567
568 use super::*;
569 use crate::math::UnitVec3;
570 use crate::Ray;
571
572 #[test]
573 fn test_aabb_grow() {
574 let mut aabb = Aabb3::new(Point3::new(0.0, 0.0, 0.0), Point3::new(1.0, 1.0, 1.0));
575 aabb.grow(Point3::new(-1.0, 2.0, 3.0));
576 assert_relative_eq!(aabb.min(), Point3::new(-1.0, 0.0, 0.0));
577 assert_relative_eq!(aabb.max(), Point3::new(1.0, 2.0, 3.0));
578 }
579
580 #[test]
581 fn test_aabb_corners() {
582 let aabb = Aabb3::new(Point3::new(-1.0, -2.0, -3.0), Point3::new(1.0, 2.0, 3.0));
583 let corners = aabb.corners();
584 assert_relative_eq!(corners[0], Point3::new(-1.0, -2.0, -3.0));
585 assert_relative_eq!(corners[1], Point3::new(-1.0, -2.0, 3.0));
586 assert_relative_eq!(corners[2], Point3::new(-1.0, 2.0, -3.0));
587 assert_relative_eq!(corners[3], Point3::new(-1.0, 2.0, 3.0));
588
589 assert_relative_eq!(corners[4], Point3::new(1.0, -2.0, -3.0));
590 assert_relative_eq!(corners[5], Point3::new(1.0, -2.0, 3.0));
591 assert_relative_eq!(corners[6], Point3::new(1.0, 2.0, -3.0));
592 assert_relative_eq!(corners[7], Point3::new(1.0, 2.0, 3.0));
593 }
594
595 #[test]
596 fn test_raycast() {
597 let aabb = Aabb3::new(Point3::new(0.0, 0.0, 0.0), Point3::new(1.0, 1.0, 1.0));
598
599 let ray_origin_0 = Point3::new(0.5, 0.5, -0.5);
600 let ray_direction_0 = UnitVec3::new_normalize(Vec3::new(0.0, 0.0, 1.0));
601 let max_distance_0 = 1.0;
602 assert!(aabb.raycast_by_one_over_direction(
603 ray_origin_0,
604 Ray::compute_one_over_direction(ray_direction_0),
605 max_distance_0
606 ));
607
608 {
609 let ray_origin_1 = Point3::new(0.5, 1.1, -0.5);
610 assert!(!aabb.raycast_by_one_over_direction(
611 ray_origin_1,
612 Ray::compute_one_over_direction(ray_direction_0),
613 max_distance_0
614 ));
615 }
616
617 {
618 let ray_direction_2 = UnitVec3::new_normalize(Vec3::new(0.0, 0.0, -1.0));
619 assert!(!aabb.raycast_by_one_over_direction(
620 ray_origin_0,
621 Ray::compute_one_over_direction(ray_direction_2),
622 max_distance_0
623 ));
624 }
625
626 {
627 let max_distance_3 = 0.3;
628 assert!(!aabb.raycast_by_one_over_direction(
629 ray_origin_0,
630 Ray::compute_one_over_direction(ray_direction_0),
631 max_distance_3
632 ));
633 }
634
635 {
636 let ray_direction_4 = UnitVec3::new_normalize(Vec3::new(0.0, 0.4, 0.5));
637 assert!(aabb.raycast_by_one_over_direction(
638 ray_origin_0,
639 Ray::compute_one_over_direction(ray_direction_4),
640 max_distance_0
641 ));
642 }
643
644 {
646 let ray_origin_5 = Point3::new(0.5, 0.5, 0.5);
647 assert!(aabb.raycast_by_one_over_direction(
648 ray_origin_5,
649 Ray::compute_one_over_direction(ray_direction_0),
650 max_distance_0
651 ));
652 }
653 }
654}