three_d_asset/prelude/
aabb.rs1use super::math::*;
2
3#[derive(Debug, Copy, Clone)]
7pub struct AxisAlignedBoundingBox {
8 min: Vec3,
9 max: Vec3,
10}
11
12impl AxisAlignedBoundingBox {
13 pub const EMPTY: Self = Self {
15 min: Vec3::new(std::f32::INFINITY, std::f32::INFINITY, std::f32::INFINITY),
16 max: Vec3::new(
17 std::f32::NEG_INFINITY,
18 std::f32::NEG_INFINITY,
19 std::f32::NEG_INFINITY,
20 ),
21 };
22
23 pub const INFINITE: Self = Self {
25 min: Vec3::new(
26 std::f32::NEG_INFINITY,
27 std::f32::NEG_INFINITY,
28 std::f32::NEG_INFINITY,
29 ),
30 max: Vec3::new(std::f32::INFINITY, std::f32::INFINITY, std::f32::INFINITY),
31 };
32
33 pub fn new_with_positions(positions: &[Vec3]) -> Self {
37 let mut aabb = Self::EMPTY;
38 aabb.expand(positions);
39 aabb
40 }
41
42 pub fn new_with_transformed_positions(positions: &[Vec3], transformation: Mat4) -> Self {
47 let mut aabb = Self::EMPTY;
48 aabb.expand_with_transformation(positions, transformation);
49 aabb
50 }
51
52 pub fn is_empty(&self) -> bool {
56 self.max.x == f32::NEG_INFINITY
57 }
58
59 pub fn is_infinite(&self) -> bool {
63 self.max.x == f32::INFINITY
64 }
65
66 pub fn min(&self) -> Vec3 {
70 self.min
71 }
72
73 pub fn max(&self) -> Vec3 {
77 self.max
78 }
79
80 pub fn center(&self) -> Vec3 {
84 if self.is_infinite() {
85 Vec3::new(0.0, 0.0, 0.0)
86 } else {
87 0.5 * self.max + 0.5 * self.min
88 }
89 }
90
91 pub fn size(&self) -> Vec3 {
95 self.max - self.min
96 }
97
98 pub fn ensure_size(&mut self, min_size: Vec3) {
100 if !self.is_empty() && !self.is_infinite() {
101 let size = self.size();
102 if size.x < min_size.x {
103 let diff = min_size.x - size.x;
104 self.min.x -= 0.5 * diff;
105 self.max.x += 0.5 * diff;
106 }
107 if size.y < min_size.y {
108 let diff = min_size.y - size.y;
109 self.min.y -= 0.5 * diff;
110 self.max.y += 0.5 * diff;
111 }
112 if size.z < min_size.z {
113 let diff = min_size.z - size.z;
114 self.min.z -= 0.5 * diff;
115 self.max.z += 0.5 * diff;
116 }
117 }
118 }
119
120 pub fn intersection(self, other: Self) -> Self {
122 let min_a = self.min();
123 let max_a = self.max();
124 let min_b = other.min();
125 let max_b = other.max();
126
127 if min_a.x >= max_b.x || min_a.y >= max_b.y || min_b.x >= max_a.x || min_b.y >= max_a.y {
128 return Self::EMPTY;
129 }
130
131 let min = vec3(
132 min_a.x.max(min_b.x),
133 min_a.y.max(min_b.y),
134 min_a.z.max(min_b.z),
135 );
136 let max = vec3(
137 max_a.x.min(max_b.x),
138 max_a.y.min(max_b.y),
139 max_a.z.min(max_b.z),
140 );
141
142 Self::new_with_positions(&[min, max])
143 }
144
145 pub fn expand(&mut self, positions: &[Vec3]) {
149 for p in positions {
150 self.min.x = self.min.x.min(p.x);
151 self.min.y = self.min.y.min(p.y);
152 self.min.z = self.min.z.min(p.z);
153
154 self.max.x = self.max.x.max(p.x);
155 self.max.y = self.max.y.max(p.y);
156 self.max.z = self.max.z.max(p.z);
157 }
158 }
159
160 pub fn expand_with_transformation(&mut self, positions: &[Vec3], transformation: Mat4) {
164 self.expand(
165 &positions
166 .iter()
167 .map(|p| (transformation * p.extend(1.0)).truncate())
168 .collect::<Vec<_>>(),
169 )
170 }
171
172 pub fn expand_with_aabb(&mut self, other: AxisAlignedBoundingBox) {
176 if self.is_empty() {
177 *self = other;
178 } else if !other.is_empty() {
179 self.expand(&[other.min(), other.max()]);
180 }
181 }
182
183 pub fn transform(&mut self, transformation: Mat4) {
187 if !self.is_empty() && !self.is_infinite() {
188 *self = Self::new_with_transformed_positions(
189 &[
190 self.min,
191 vec3(self.max.x, self.min.y, self.min.z),
192 vec3(self.min.x, self.max.y, self.min.z),
193 vec3(self.min.x, self.min.y, self.max.z),
194 vec3(self.min.x, self.max.y, self.max.z),
195 vec3(self.max.x, self.min.y, self.max.z),
196 vec3(self.max.x, self.max.y, self.min.z),
197 self.max,
198 ],
199 transformation,
200 );
201 }
202 }
203
204 pub fn transformed(mut self, transformation: Mat4) -> AxisAlignedBoundingBox {
208 self.transform(transformation);
209 self
210 }
211
212 pub fn contains(&self, aabb: AxisAlignedBoundingBox) -> bool {
214 !self.is_empty()
215 && !aabb.is_empty()
216 && self.is_inside(aabb.min())
217 && self.is_inside(aabb.max())
218 }
219
220 pub fn is_inside(&self, position: Vec3) -> bool {
222 self.min.x <= position.x
223 && position.x <= self.max.x
224 && self.min.y <= position.y
225 && position.y <= self.max.y
226 && self.min.z <= position.z
227 && position.z <= self.max.z
228 }
229
230 pub fn distance(&self, position: Vec3) -> f32 {
234 let x = (self.min.x - position.x)
235 .max(position.x - self.max.x)
236 .max(0.0);
237 let y = (self.min.y - position.y)
238 .max(position.y - self.max.y)
239 .max(0.0);
240 let z = (self.min.z - position.z)
241 .max(position.z - self.max.z)
242 .max(0.0);
243 let d2 = x * x + y * y + z * z;
244 if d2 > 0.001 {
245 d2.sqrt()
246 } else {
247 d2
248 }
249 }
250
251 pub fn distance_max(&self, position: Vec3) -> f32 {
255 let x = (position.x - self.min.x)
256 .abs()
257 .max((self.max.x - position.x).abs());
258 let y = (position.y - self.min.y)
259 .abs()
260 .max((self.max.y - position.y).abs());
261 let z = (position.z - self.min.z)
262 .abs()
263 .max((self.max.z - position.z).abs());
264 let d2 = x * x + y * y + z * z;
265 if d2 > 0.001 {
266 d2.sqrt()
267 } else {
268 d2
269 }
270 }
271}