1use phyz_math::Vec3;
4
5#[derive(Clone, Debug)]
7pub struct BoundingBox {
8 pub min: Vec3,
9 pub max: Vec3,
10}
11
12impl BoundingBox {
13 pub fn new(min: Vec3, max: Vec3) -> Self {
15 Self { min, max }
16 }
17
18 pub fn contains(&self, point: &Vec3) -> bool {
20 point.x >= self.min.x
21 && point.x <= self.max.x
22 && point.y >= self.min.y
23 && point.y <= self.max.y
24 && point.z >= self.min.z
25 && point.z <= self.max.z
26 }
27
28 pub fn volume(&self) -> f64 {
30 let size = self.max - self.min;
31 size.x * size.y * size.z
32 }
33
34 pub fn center(&self) -> Vec3 {
36 (self.min + self.max) * 0.5
37 }
38
39 pub fn expand(&self, margin: f64) -> Self {
41 Self {
42 min: self.min - Vec3::new(margin, margin, margin),
43 max: self.max + Vec3::new(margin, margin, margin),
44 }
45 }
46
47 pub fn overlaps(&self, other: &BoundingBox) -> bool {
49 self.min.x <= other.max.x
50 && self.max.x >= other.min.x
51 && self.min.y <= other.max.y
52 && self.max.y >= other.min.y
53 && self.min.z <= other.max.z
54 && self.max.z >= other.min.z
55 }
56
57 pub fn intersection(&self, other: &BoundingBox) -> Option<BoundingBox> {
59 if !self.overlaps(other) {
60 return None;
61 }
62
63 Some(BoundingBox {
64 min: Vec3::new(
65 self.min.x.max(other.min.x),
66 self.min.y.max(other.min.y),
67 self.min.z.max(other.min.z),
68 ),
69 max: Vec3::new(
70 self.max.x.min(other.max.x),
71 self.max.y.min(other.max.y),
72 self.max.z.min(other.max.z),
73 ),
74 })
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81 use approx::assert_relative_eq;
82
83 #[test]
84 fn test_contains() {
85 let bbox = BoundingBox::new(Vec3::new(-1.0, -1.0, -1.0), Vec3::new(1.0, 1.0, 1.0));
86
87 assert!(bbox.contains(&Vec3::new(0.0, 0.0, 0.0)));
88 assert!(bbox.contains(&Vec3::new(0.5, 0.5, 0.5)));
89 assert!(bbox.contains(&Vec3::new(-1.0, -1.0, -1.0)));
90 assert!(bbox.contains(&Vec3::new(1.0, 1.0, 1.0)));
91 assert!(!bbox.contains(&Vec3::new(2.0, 0.0, 0.0)));
92 assert!(!bbox.contains(&Vec3::new(0.0, 2.0, 0.0)));
93 }
94
95 #[test]
96 fn test_volume() {
97 let bbox = BoundingBox::new(Vec3::new(0.0, 0.0, 0.0), Vec3::new(2.0, 3.0, 4.0));
98 assert_relative_eq!(bbox.volume(), 24.0);
99 }
100
101 #[test]
102 fn test_center() {
103 let bbox = BoundingBox::new(Vec3::new(-1.0, -1.0, -1.0), Vec3::new(1.0, 1.0, 1.0));
104 let center = bbox.center();
105 assert_relative_eq!(center.x, 0.0);
106 assert_relative_eq!(center.y, 0.0);
107 assert_relative_eq!(center.z, 0.0);
108 }
109
110 #[test]
111 fn test_expand() {
112 let bbox = BoundingBox::new(Vec3::new(-1.0, -1.0, -1.0), Vec3::new(1.0, 1.0, 1.0));
113 let expanded = bbox.expand(0.5);
114
115 assert_relative_eq!(expanded.min.x, -1.5);
116 assert_relative_eq!(expanded.max.x, 1.5);
117 }
118
119 #[test]
120 fn test_overlaps() {
121 let bbox1 = BoundingBox::new(Vec3::new(0.0, 0.0, 0.0), Vec3::new(2.0, 2.0, 2.0));
122 let bbox2 = BoundingBox::new(Vec3::new(1.0, 1.0, 1.0), Vec3::new(3.0, 3.0, 3.0));
123 let bbox3 = BoundingBox::new(Vec3::new(3.0, 3.0, 3.0), Vec3::new(5.0, 5.0, 5.0));
124
125 assert!(bbox1.overlaps(&bbox2));
126 assert!(bbox2.overlaps(&bbox1));
127 assert!(!bbox1.overlaps(&bbox3));
128 }
129
130 #[test]
131 fn test_intersection() {
132 let bbox1 = BoundingBox::new(Vec3::new(0.0, 0.0, 0.0), Vec3::new(2.0, 2.0, 2.0));
133 let bbox2 = BoundingBox::new(Vec3::new(1.0, 1.0, 1.0), Vec3::new(3.0, 3.0, 3.0));
134
135 let intersection = bbox1.intersection(&bbox2).unwrap();
136 assert_relative_eq!(intersection.min.x, 1.0);
137 assert_relative_eq!(intersection.max.x, 2.0);
138
139 let bbox3 = BoundingBox::new(Vec3::new(3.0, 3.0, 3.0), Vec3::new(5.0, 5.0, 5.0));
140 assert!(bbox1.intersection(&bbox3).is_none());
141 }
142}