1use crate::Vec3;
2use serde::{Deserialize, Serialize};
3
4#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
6pub struct Aabb {
7 pub min: Vec3,
8 pub max: Vec3,
9}
10
11impl Aabb {
12 #[inline]
14 pub fn new(min: Vec3, max: Vec3) -> Self {
15 Self { min, max }
16 }
17
18 pub fn from_points(points: impl IntoIterator<Item = Vec3>) -> Option<Self> {
21 let mut iter = points.into_iter();
22 let first = iter.next()?;
23 let mut min = first;
24 let mut max = first;
25 for p in iter {
26 min = Vec3::new(min.x.min(p.x), min.y.min(p.y), min.z.min(p.z));
27 max = Vec3::new(max.x.max(p.x), max.y.max(p.y), max.z.max(p.z));
28 }
29 Some(Self { min, max })
30 }
31
32 #[inline]
34 pub fn center(self) -> Vec3 {
35 (self.min + self.max) * 0.5
36 }
37
38 #[inline]
40 pub fn extents(self) -> Vec3 {
41 (self.max - self.min) * 0.5
42 }
43
44 #[inline]
46 pub fn size(self) -> Vec3 {
47 self.max - self.min
48 }
49
50 #[inline]
52 pub fn contains_point(self, point: Vec3) -> bool {
53 point.x >= self.min.x
54 && point.x <= self.max.x
55 && point.y >= self.min.y
56 && point.y <= self.max.y
57 && point.z >= self.min.z
58 && point.z <= self.max.z
59 }
60
61 #[inline]
63 pub fn intersects(self, other: Self) -> bool {
64 self.min.x <= other.max.x
65 && self.max.x >= other.min.x
66 && self.min.y <= other.max.y
67 && self.max.y >= other.min.y
68 && self.min.z <= other.max.z
69 && self.max.z >= other.min.z
70 }
71
72 #[inline]
74 pub fn union(self, other: Self) -> Self {
75 Self {
76 min: Vec3::new(
77 self.min.x.min(other.min.x),
78 self.min.y.min(other.min.y),
79 self.min.z.min(other.min.z),
80 ),
81 max: Vec3::new(
82 self.max.x.max(other.max.x),
83 self.max.y.max(other.max.y),
84 self.max.z.max(other.max.z),
85 ),
86 }
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn contains_point() {
96 let aabb = Aabb::new(Vec3::new(-1.0, -1.0, -1.0), Vec3::new(1.0, 1.0, 1.0));
97 assert!(aabb.contains_point(Vec3::ZERO));
98 assert!(aabb.contains_point(Vec3::new(1.0, 1.0, 1.0)));
99 assert!(!aabb.contains_point(Vec3::new(2.0, 0.0, 0.0)));
100 }
101
102 #[test]
103 fn intersects() {
104 let a = Aabb::new(Vec3::new(0.0, 0.0, 0.0), Vec3::new(2.0, 2.0, 2.0));
105 let b = Aabb::new(Vec3::new(1.0, 1.0, 1.0), Vec3::new(3.0, 3.0, 3.0));
106 let c = Aabb::new(Vec3::new(5.0, 5.0, 5.0), Vec3::new(6.0, 6.0, 6.0));
107
108 assert!(a.intersects(b));
109 assert!(!a.intersects(c));
110 }
111
112 #[test]
113 fn from_points() {
114 let points = vec![
115 Vec3::new(1.0, -2.0, 3.0),
116 Vec3::new(-1.0, 4.0, 0.0),
117 Vec3::new(2.0, 0.0, -1.0),
118 ];
119 let aabb = Aabb::from_points(points).unwrap();
120 assert_eq!(aabb.min, Vec3::new(-1.0, -2.0, -1.0));
121 assert_eq!(aabb.max, Vec3::new(2.0, 4.0, 3.0));
122 }
123
124 #[test]
125 fn center_and_extents() {
126 let aabb = Aabb::new(Vec3::new(0.0, 0.0, 0.0), Vec3::new(4.0, 6.0, 8.0));
127 assert_eq!(aabb.center(), Vec3::new(2.0, 3.0, 4.0));
128 assert_eq!(aabb.extents(), Vec3::new(2.0, 3.0, 4.0));
129 assert_eq!(aabb.size(), Vec3::new(4.0, 6.0, 8.0));
130 }
131
132 #[test]
133 fn from_empty_points() {
134 let result = Aabb::from_points(std::iter::empty());
135 assert!(result.is_none());
136 }
137}