1use crate::bounding_volume::Aabb;
2use crate::math::{Isometry, Point, Real, SimdBool, SimdReal, Vector, DIM, SIMD_WIDTH};
3use crate::query::SimdRay;
4use crate::utils::{self, IsometryOps};
5use num::{One, Zero};
6use simba::simd::{SimdPartialOrd, SimdValue};
7
8#[derive(Debug, Copy, Clone)]
10#[cfg_attr(
11 feature = "rkyv",
12 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize),
13 archive(check_bytes)
14)]
15pub struct SimdAabb {
16 pub mins: Point<SimdReal>,
18 pub maxs: Point<SimdReal>,
20}
21
22#[cfg(feature = "serde-serialize")]
23impl serde::Serialize for SimdAabb {
24 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
25 where
26 S: serde::Serializer,
27 {
28 use serde::ser::SerializeStruct;
29
30 let mins: Point<[Real; SIMD_WIDTH]> = Point::from(
31 self.mins
32 .coords
33 .map(|e| array![|ii| e.extract(ii); SIMD_WIDTH]),
34 );
35 let maxs: Point<[Real; SIMD_WIDTH]> = Point::from(
36 self.maxs
37 .coords
38 .map(|e| array![|ii| e.extract(ii); SIMD_WIDTH]),
39 );
40
41 let mut simd_aabb = serializer.serialize_struct("SimdAabb", 2)?;
42 simd_aabb.serialize_field("mins", &mins)?;
43 simd_aabb.serialize_field("maxs", &maxs)?;
44 simd_aabb.end()
45 }
46}
47
48#[cfg(feature = "serde-serialize")]
49impl<'de> serde::Deserialize<'de> for SimdAabb {
50 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
51 where
52 D: serde::Deserializer<'de>,
53 {
54 struct Visitor {}
55
56 #[derive(Deserialize)]
57 #[serde(field_identifier, rename_all = "lowercase")]
58 enum Field {
59 Mins,
60 Maxs,
61 }
62
63 impl<'de> serde::de::Visitor<'de> for Visitor {
64 type Value = SimdAabb;
65 fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
66 write!(
67 formatter,
68 "two arrays containing at least {} floats",
69 SIMD_WIDTH * DIM * 2
70 )
71 }
72
73 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
74 where
75 A: serde::de::MapAccess<'de>,
76 {
77 let mut mins: Option<Point<[Real; SIMD_WIDTH]>> = None;
78 let mut maxs: Option<Point<[Real; SIMD_WIDTH]>> = None;
79
80 while let Some(key) = map.next_key()? {
81 match key {
82 Field::Mins => {
83 if mins.is_some() {
84 return Err(serde::de::Error::duplicate_field("mins"));
85 }
86 mins = Some(map.next_value()?);
87 }
88 Field::Maxs => {
89 if maxs.is_some() {
90 return Err(serde::de::Error::duplicate_field("maxs"));
91 }
92 maxs = Some(map.next_value()?);
93 }
94 }
95 }
96
97 let mins = mins.ok_or_else(|| serde::de::Error::missing_field("mins"))?;
98 let maxs = maxs.ok_or_else(|| serde::de::Error::missing_field("maxs"))?;
99 let mins = mins.map(SimdReal::from);
100 let maxs = maxs.map(SimdReal::from);
101 Ok(SimdAabb { mins, maxs })
102 }
103
104 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
105 where
106 A: serde::de::SeqAccess<'de>,
107 {
108 let mins: Point<[Real; SIMD_WIDTH]> = seq
109 .next_element()?
110 .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
111 let maxs: Point<[Real; SIMD_WIDTH]> = seq
112 .next_element()?
113 .ok_or_else(|| serde::de::Error::invalid_length(1, &self))?;
114 let mins = mins.map(SimdReal::from);
115 let maxs = maxs.map(SimdReal::from);
116 Ok(SimdAabb { mins, maxs })
117 }
118 }
119
120 deserializer.deserialize_struct("SimdAabb", &["mins", "maxs"], Visitor {})
121 }
122}
123
124impl SimdAabb {
125 pub fn new_invalid() -> Self {
127 Self::splat(Aabb::new_invalid())
128 }
129
130 pub fn splat(aabb: Aabb) -> Self {
132 Self {
133 mins: Point::splat(aabb.mins),
134 maxs: Point::splat(aabb.maxs),
135 }
136 }
137
138 pub fn center(&self) -> Point<SimdReal> {
140 na::center(&self.mins, &self.maxs)
141 }
142
143 pub fn half_extents(&self) -> Vector<SimdReal> {
145 (self.maxs - self.mins) * SimdReal::splat(0.5)
146 }
147
148 pub fn radius(&self) -> SimdReal {
150 (self.maxs - self.mins).norm()
151 }
152
153 pub fn transform_by(&self, transform: &Isometry<SimdReal>) -> Self {
155 let ls_center = self.center();
156 let center = transform * ls_center;
157 let ws_half_extents = transform.absolute_transform_vector(&self.half_extents());
158 Self {
159 mins: center + (-ws_half_extents),
160 maxs: center + ws_half_extents,
161 }
162 }
163
164 #[inline]
166 pub fn scaled(self, scale: &Vector<SimdReal>) -> Self {
167 let a = self.mins.coords.component_mul(scale);
168 let b = self.maxs.coords.component_mul(scale);
169 Self {
170 mins: a.inf(&b).into(),
171 maxs: a.sup(&b).into(),
172 }
173 }
174
175 pub fn loosen(&mut self, margin: SimdReal) {
177 self.mins -= Vector::repeat(margin);
178 self.maxs += Vector::repeat(margin);
179 }
180
181 pub fn dilate_by_factor(&mut self, factor: SimdReal) {
184 let is_valid = self.mins.x.simd_le(self.maxs.x);
187 let factor = factor.select(is_valid, SimdReal::zero());
188
189 let dilation = self.maxs * factor - self.mins * factor;
194 self.mins -= dilation;
195 self.maxs += dilation;
196 }
197
198 pub fn replace(&mut self, i: usize, aabb: Aabb) {
200 self.mins.replace(i, aabb.mins);
201 self.maxs.replace(i, aabb.maxs);
202 }
203
204 pub fn cast_local_ray(
206 &self,
207 ray: &SimdRay,
208 max_time_of_impact: SimdReal,
209 ) -> (SimdBool, SimdReal) {
210 let zero = SimdReal::zero();
211 let one = SimdReal::one();
212 let infinity = SimdReal::splat(Real::MAX);
213
214 let mut hit = SimdBool::splat(true);
215 let mut tmin = SimdReal::zero();
216 let mut tmax = max_time_of_impact;
217
218 for i in 0usize..DIM {
220 let is_not_zero = ray.dir[i].simd_ne(zero);
221 let is_zero_test =
222 ray.origin[i].simd_ge(self.mins[i]) & ray.origin[i].simd_le(self.maxs[i]);
223 let is_not_zero_test = {
224 let denom = one / ray.dir[i];
225 let mut inter_with_near_plane =
226 ((self.mins[i] - ray.origin[i]) * denom).select(is_not_zero, -infinity);
227 let mut inter_with_far_plane =
228 ((self.maxs[i] - ray.origin[i]) * denom).select(is_not_zero, infinity);
229
230 let gt = inter_with_near_plane.simd_gt(inter_with_far_plane);
231 utils::simd_swap(gt, &mut inter_with_near_plane, &mut inter_with_far_plane);
232
233 tmin = tmin.simd_max(inter_with_near_plane);
234 tmax = tmax.simd_min(inter_with_far_plane);
235
236 tmin.simd_le(tmax)
237 };
238
239 hit = hit & is_not_zero_test.select(is_not_zero, is_zero_test);
240 }
241
242 (hit, tmin)
243 }
244
245 pub fn distance_to_local_point(&self, point: &Point<SimdReal>) -> SimdReal {
247 let mins_point = self.mins - point;
248 let point_maxs = point - self.maxs;
249 let shift = mins_point.sup(&point_maxs).sup(&na::zero());
250 shift.norm()
251 }
252
253 pub fn distance_to_origin(&self) -> SimdReal {
255 self.mins
256 .coords
257 .sup(&-self.maxs.coords)
258 .sup(&Vector::zeros())
259 .norm()
260 }
261
262 pub fn contains_local_point(&self, point: &Point<SimdReal>) -> SimdBool {
264 #[cfg(feature = "dim2")]
265 return self.mins.x.simd_le(point.x)
266 & self.mins.y.simd_le(point.y)
267 & self.maxs.x.simd_ge(point.x)
268 & self.maxs.y.simd_ge(point.y);
269
270 #[cfg(feature = "dim3")]
271 return self.mins.x.simd_le(point.x)
272 & self.mins.y.simd_le(point.y)
273 & self.mins.z.simd_le(point.z)
274 & self.maxs.x.simd_ge(point.x)
275 & self.maxs.y.simd_ge(point.y)
276 & self.maxs.z.simd_ge(point.z);
277 }
278
279 #[cfg(feature = "dim2")]
282 pub fn contains(&self, other: &SimdAabb) -> SimdBool {
283 self.mins.x.simd_le(other.mins.x)
284 & self.mins.y.simd_le(other.mins.y)
285 & self.maxs.x.simd_ge(other.maxs.x)
286 & self.maxs.y.simd_ge(other.maxs.y)
287 }
288
289 #[cfg(feature = "dim3")]
292 pub fn contains(&self, other: &SimdAabb) -> SimdBool {
293 self.mins.x.simd_le(other.mins.x)
294 & self.mins.y.simd_le(other.mins.y)
295 & self.mins.z.simd_le(other.mins.z)
296 & self.maxs.x.simd_ge(other.maxs.x)
297 & self.maxs.y.simd_ge(other.maxs.y)
298 & self.maxs.z.simd_ge(other.maxs.z)
299 }
300
301 #[cfg(feature = "dim2")]
304 pub fn intersects(&self, other: &SimdAabb) -> SimdBool {
305 self.mins.x.simd_le(other.maxs.x)
306 & other.mins.x.simd_le(self.maxs.x)
307 & self.mins.y.simd_le(other.maxs.y)
308 & other.mins.y.simd_le(self.maxs.y)
309 }
310
311 #[cfg(feature = "dim3")]
314 pub fn intersects(&self, other: &SimdAabb) -> SimdBool {
315 self.mins.x.simd_le(other.maxs.x)
316 & other.mins.x.simd_le(self.maxs.x)
317 & self.mins.y.simd_le(other.maxs.y)
318 & other.mins.y.simd_le(self.maxs.y)
319 & self.mins.z.simd_le(other.maxs.z)
320 & other.mins.z.simd_le(self.maxs.z)
321 }
322
323 pub fn intersects_permutations(&self, other: &SimdAabb) -> [SimdBool; SIMD_WIDTH] {
328 let mut result = [SimdBool::splat(false); SIMD_WIDTH];
329 for (ii, result) in result.iter_mut().enumerate() {
330 let extracted = SimdAabb::splat(self.extract(ii));
332 *result = extracted.intersects(other);
333 }
334
335 result
336 }
337
338 pub fn to_merged_aabb(&self) -> Aabb {
340 Aabb::new(
341 self.mins.coords.map(|e| e.simd_horizontal_min()).into(),
342 self.maxs.coords.map(|e| e.simd_horizontal_max()).into(),
343 )
344 }
345
346 pub fn extract(&self, lane: usize) -> Aabb {
348 Aabb::new(self.mins.extract(lane), self.maxs.extract(lane))
349 }
350}
351
352impl From<[Aabb; SIMD_WIDTH]> for SimdAabb {
353 fn from(aabbs: [Aabb; SIMD_WIDTH]) -> Self {
354 let mins = array![|ii| aabbs[ii].mins; SIMD_WIDTH];
355 let maxs = array![|ii| aabbs[ii].maxs; SIMD_WIDTH];
356
357 SimdAabb {
358 mins: Point::from(mins),
359 maxs: Point::from(maxs),
360 }
361 }
362}