1use std::mem;
2
3use crate::{interval::Interval, ray::Ray, Point3};
4
5#[derive(Debug, Clone)]
6pub struct AABB {
7 x: Interval,
8 y: Interval,
9 z: Interval,
10}
11
12impl AABB {
13 pub fn new(x: Interval, y: Interval, z: Interval) -> Self {
14 Self { x, y, z }
15 }
16
17 pub fn from_points(a: Point3, b: Point3) -> Self {
18 Self {
19 x: Interval::new(a.x.min(b.x), a.x.max(b.x)),
20 y: Interval::new(a.y.min(b.y), a.y.max(b.y)),
21 z: Interval::new(a.z.min(b.z), a.z.max(b.z)),
22 }
23 }
24
25 pub fn from_boxes(a: &Self, b: &Self) -> Self {
26 Self {
27 x: Interval::from_intervals(&a.x, &b.x),
28 y: Interval::from_intervals(&a.y, &b.y),
29 z: Interval::from_intervals(&a.z, &b.z),
30 }
31 }
32
33 pub fn axis(&self, n: usize) -> &Interval {
34 match n {
35 0 => &self.x,
36 1 => &self.y,
37 2 => &self.z,
38 _ => {
39 panic!("invalid interval index passed into aabb {}", n);
40 }
41 }
42 }
43
44 pub fn hit(&self, r: &Ray, ray_t: &Interval) -> bool {
45 for i in 0..3 {
46 let inv_d = 1. / r.direction[i];
47 let mut t0 = (self.axis(i).min - r.origin[i]) * inv_d;
48 let mut t1 = (self.axis(i).max - r.origin[i]) * inv_d;
49 if inv_d < 0. {
50 mem::swap(&mut t0, &mut t1);
51 }
52
53 let ray_tmin = t0.max(ray_t.min);
54 let ray_tmax = t1.min(ray_t.max);
55
56 if ray_tmax <= ray_tmin {
57 return false;
58 }
59 }
60 true
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use crate::{interval, ray::Ray, vec3::Vec3, Point3};
67
68 use super::AABB;
69
70 #[test]
71 fn hit_bb_linear() {
72 let p1 = Point3::new(3., 0., 0.);
73 let p2 = Point3::new(4., 1., 0.);
74
75 let bb = AABB::from_points(p1, p2);
76
77 let ray_origin = Point3::new(0., 0.5, 0.);
78 let ray_direction = Vec3::new(1., 0., 0.);
79 let r = Ray::new(ray_origin, ray_direction, 0.);
80
81 assert!(bb.hit(&r, &interval::UNIVERSE));
82 }
83
84 #[test]
85 fn miss_bb_linear() {
86 let p1 = Point3::new(3., 0., 0.);
87 let p2 = Point3::new(4., 1., 1.);
88
89 let bb = AABB::from_points(p1, p2);
90
91 dbg!(&bb);
92
93 let ray_origin = Point3::new(0., -0.5, 0.);
94 let ray_direction = Vec3::new(1., 0., 0.);
95 let r = Ray::new(ray_origin, ray_direction, 0.);
96
97 assert!(!bb.hit(&r, &interval::UNIVERSE));
98 }
99
100 #[test]
101 fn bb_join() {
102 let p0_0 = Point3::new(-1., -1., -1.);
103 let p0_1 = Point3::new(1., 1., 1.);
104 let p1_0 = Point3::new(-0.3, -0.3, 0.7);
105 let p1_1 = Point3::new(0.3, 0.3, 1.3);
106
107 let bb_0 = AABB::from_points(p0_0, p0_1);
108 let bb_1 = AABB::from_points(p1_0, p1_1);
109
110 let _bb = AABB::from_boxes(&bb_0, &bb_1);
111 todo!();
112 }
113}