1use crate::bounding_volume::{BoundingSphere, BoundingVolume};
4use crate::math::{Isometry, Point, Real, UnitVector, Vector, DIM, TWO_DIM};
5use crate::shape::{Cuboid, SupportMap};
6use crate::utils::IsometryOps;
7use arrayvec::ArrayVec;
8use na;
9use num::Bounded;
10
11#[cfg(all(feature = "dim3", not(feature = "std")))]
12use na::ComplexField; use crate::query::{Ray, RayCast};
15#[cfg(feature = "rkyv")]
16use rkyv::{bytecheck, CheckBytes};
17
18#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
20#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
21#[cfg_attr(
22 feature = "rkyv",
23 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes),
24 archive(as = "Self")
25)]
26#[derive(Debug, PartialEq, Copy, Clone)]
27#[repr(C)]
28pub struct Aabb {
29 pub mins: Point<Real>,
30 pub maxs: Point<Real>,
31}
32
33impl Aabb {
34 #[cfg(feature = "dim3")]
49 pub const EDGES_VERTEX_IDS: [(usize, usize); 12] = [
50 (0, 1),
51 (1, 2),
52 (3, 2),
53 (0, 3),
54 (4, 5),
55 (5, 6),
56 (7, 6),
57 (4, 7),
58 (0, 4),
59 (1, 5),
60 (2, 6),
61 (3, 7),
62 ];
63
64 #[cfg(feature = "dim3")]
79 pub const FACES_VERTEX_IDS: [(usize, usize, usize, usize); 6] = [
80 (1, 2, 6, 5),
82 (0, 3, 7, 4),
84 (2, 3, 7, 6),
86 (1, 0, 4, 5),
88 (4, 5, 6, 7),
90 (0, 1, 2, 3),
92 ];
93
94 #[cfg(feature = "dim2")]
107 pub const FACES_VERTEX_IDS: [(usize, usize); 4] = [
108 (1, 2),
110 (3, 0),
112 (2, 3),
114 (0, 1),
116 ];
117
118 #[inline]
125 pub fn new(mins: Point<Real>, maxs: Point<Real>) -> Aabb {
126 Aabb { mins, maxs }
127 }
128
129 #[inline]
133 pub fn new_invalid() -> Self {
134 Self::new(
135 Vector::repeat(Real::max_value()).into(),
136 Vector::repeat(-Real::max_value()).into(),
137 )
138 }
139
140 #[inline]
142 pub fn from_half_extents(center: Point<Real>, half_extents: Vector<Real>) -> Self {
143 Self::new(center - half_extents, center + half_extents)
144 }
145
146 pub fn from_points<'a, I>(pts: I) -> Self
148 where
149 I: IntoIterator<Item = &'a Point<Real>>,
150 {
151 super::aabb_utils::local_point_cloud_aabb(pts)
152 }
153
154 #[inline]
156 pub fn center(&self) -> Point<Real> {
157 na::center(&self.mins, &self.maxs)
158 }
159
160 #[inline]
162 pub fn half_extents(&self) -> Vector<Real> {
163 let half: Real = na::convert::<f64, Real>(0.5);
164 (self.maxs - self.mins) * half
165 }
166
167 #[inline]
169 pub fn volume(&self) -> Real {
170 let extents = self.extents();
171 #[cfg(feature = "dim2")]
172 return extents.x * extents.y;
173 #[cfg(feature = "dim3")]
174 return extents.x * extents.y * extents.z;
175 }
176
177 #[inline]
179 pub fn extents(&self) -> Vector<Real> {
180 self.maxs - self.mins
181 }
182
183 pub fn take_point(&mut self, pt: Point<Real>) {
185 self.mins = self.mins.coords.inf(&pt.coords).into();
186 self.maxs = self.maxs.coords.sup(&pt.coords).into();
187 }
188
189 #[inline]
191 pub fn transform_by(&self, m: &Isometry<Real>) -> Self {
192 let ls_center = self.center();
193 let center = m * ls_center;
194 let ws_half_extents = m.absolute_transform_vector(&self.half_extents());
195
196 Aabb::new(center + (-ws_half_extents), center + ws_half_extents)
197 }
198
199 #[inline]
201 pub fn translated(mut self, translation: &Vector<Real>) -> Self {
202 self.mins += translation;
203 self.maxs += translation;
204 self
205 }
206
207 #[inline]
208 pub fn scaled(self, scale: &Vector<Real>) -> Self {
209 let a = self.mins.coords.component_mul(scale);
210 let b = self.maxs.coords.component_mul(scale);
211 Self {
212 mins: a.inf(&b).into(),
213 maxs: a.sup(&b).into(),
214 }
215 }
216
217 #[inline]
224 #[must_use]
225 pub fn scaled_wrt_center(self, scale: &Vector<Real>) -> Self {
226 let center = self.center();
227 let half_extents = self.half_extents().component_mul(scale).abs();
231 Self::from_half_extents(center, half_extents)
232 }
233
234 #[inline]
236 pub fn bounding_sphere(&self) -> BoundingSphere {
237 let center = self.center();
238 let radius = na::distance(&self.mins, &self.maxs) * 0.5;
239 BoundingSphere::new(center, radius)
240 }
241
242 #[inline]
244 pub fn contains_local_point(&self, point: &Point<Real>) -> bool {
245 for i in 0..DIM {
246 if point[i] < self.mins[i] || point[i] > self.maxs[i] {
247 return false;
248 }
249 }
250
251 true
252 }
253
254 #[inline]
256 pub fn intersects_moving_aabb(&self, aabb2: &Self, vel12: Vector<Real>) -> bool {
257 let msum = Aabb {
259 mins: self.mins - aabb2.maxs.coords,
260 maxs: self.maxs - aabb2.mins.coords,
261 };
262 let ray = Ray::new(Point::origin(), vel12);
263
264 msum.intersects_local_ray(&ray, 1.0)
265 }
266
267 pub fn intersection(&self, other: &Aabb) -> Option<Aabb> {
269 let result = Aabb {
270 mins: Point::from(self.mins.coords.sup(&other.mins.coords)),
271 maxs: Point::from(self.maxs.coords.inf(&other.maxs.coords)),
272 };
273
274 for i in 0..DIM {
275 if result.mins[i] > result.maxs[i] {
276 return None;
277 }
278 }
279
280 Some(result)
281 }
282
283 pub fn aligned_intersections(
288 &self,
289 pos12: &Isometry<Real>,
290 aabb2: &Self,
291 ) -> Option<(Aabb, Aabb)> {
292 let pos21 = pos12.inverse();
293
294 let aabb2_1 = aabb2.transform_by(pos12);
295 let inter1_1 = self.intersection(&aabb2_1)?;
296 let inter1_2 = inter1_1.transform_by(&pos21);
297
298 let aabb1_2 = self.transform_by(&pos21);
299 let inter2_2 = aabb2.intersection(&aabb1_2)?;
300 let inter2_1 = inter2_2.transform_by(pos12);
301
302 Some((
303 inter1_1.intersection(&inter2_1)?,
304 inter1_2.intersection(&inter2_2)?,
305 ))
306 }
307
308 pub fn difference(&self, rhs: &Aabb) -> ArrayVec<Self, TWO_DIM> {
313 self.difference_with_cut_sequence(rhs).0
314 }
315
316 pub fn difference_with_cut_sequence(
335 &self,
336 rhs: &Aabb,
337 ) -> (ArrayVec<Self, TWO_DIM>, ArrayVec<(i8, Real), TWO_DIM>) {
338 let mut result = ArrayVec::new();
339 let mut cut_sequence = ArrayVec::new();
340
341 for i in 0..DIM {
345 if self.mins[i] >= rhs.maxs[i] || self.maxs[i] <= rhs.mins[i] {
346 result.push(*self);
347 return (result, cut_sequence);
348 }
349 }
350
351 let mut rest = *self;
352
353 for i in 0..DIM {
354 if rhs.mins[i] > rest.mins[i] {
355 let mut fragment = rest;
356 fragment.maxs[i] = rhs.mins[i];
357 rest.mins[i] = rhs.mins[i];
358 result.push(fragment);
359 cut_sequence.push((i as i8 + 1, rhs.mins[i]));
360 }
361
362 if rhs.maxs[i] < rest.maxs[i] {
363 let mut fragment = rest;
364 fragment.mins[i] = rhs.maxs[i];
365 rest.maxs[i] = rhs.maxs[i];
366 result.push(fragment);
367 cut_sequence.push((-(i as i8 + 1), -rhs.maxs[i]));
368 }
369 }
370
371 (result, cut_sequence)
372 }
373
374 #[inline]
383 #[cfg(feature = "dim2")]
384 pub fn vertices(&self) -> [Point<Real>; 4] {
385 [
386 Point::new(self.mins.x, self.mins.y),
387 Point::new(self.maxs.x, self.mins.y),
388 Point::new(self.maxs.x, self.maxs.y),
389 Point::new(self.mins.x, self.maxs.y),
390 ]
391 }
392
393 #[inline]
404 #[cfg(feature = "dim3")]
405 pub fn vertices(&self) -> [Point<Real>; 8] {
406 [
407 Point::new(self.mins.x, self.mins.y, self.mins.z),
408 Point::new(self.maxs.x, self.mins.y, self.mins.z),
409 Point::new(self.maxs.x, self.maxs.y, self.mins.z),
410 Point::new(self.mins.x, self.maxs.y, self.mins.z),
411 Point::new(self.mins.x, self.mins.y, self.maxs.z),
412 Point::new(self.maxs.x, self.mins.y, self.maxs.z),
413 Point::new(self.maxs.x, self.maxs.y, self.maxs.z),
414 Point::new(self.mins.x, self.maxs.y, self.maxs.z),
415 ]
416 }
417
418 #[inline]
420 #[cfg(feature = "dim2")]
421 pub fn split_at_center(&self) -> [Aabb; 4] {
422 let center = self.center();
423
424 [
425 Aabb::new(self.mins, center),
426 Aabb::new(
427 Point::new(center.x, self.mins.y),
428 Point::new(self.maxs.x, center.y),
429 ),
430 Aabb::new(center, self.maxs),
431 Aabb::new(
432 Point::new(self.mins.x, center.y),
433 Point::new(center.x, self.maxs.y),
434 ),
435 ]
436 }
437
438 #[inline]
440 #[cfg(feature = "dim3")]
441 pub fn split_at_center(&self) -> [Aabb; 8] {
442 let center = self.center();
443
444 [
445 Aabb::new(
446 Point::new(self.mins.x, self.mins.y, self.mins.z),
447 Point::new(center.x, center.y, center.z),
448 ),
449 Aabb::new(
450 Point::new(center.x, self.mins.y, self.mins.z),
451 Point::new(self.maxs.x, center.y, center.z),
452 ),
453 Aabb::new(
454 Point::new(center.x, center.y, self.mins.z),
455 Point::new(self.maxs.x, self.maxs.y, center.z),
456 ),
457 Aabb::new(
458 Point::new(self.mins.x, center.y, self.mins.z),
459 Point::new(center.x, self.maxs.y, center.z),
460 ),
461 Aabb::new(
462 Point::new(self.mins.x, self.mins.y, center.z),
463 Point::new(center.x, center.y, self.maxs.z),
464 ),
465 Aabb::new(
466 Point::new(center.x, self.mins.y, center.z),
467 Point::new(self.maxs.x, center.y, self.maxs.z),
468 ),
469 Aabb::new(
470 Point::new(center.x, center.y, center.z),
471 Point::new(self.maxs.x, self.maxs.y, self.maxs.z),
472 ),
473 Aabb::new(
474 Point::new(self.mins.x, center.y, center.z),
475 Point::new(center.x, self.maxs.y, self.maxs.z),
476 ),
477 ]
478 }
479
480 pub fn project_on_axis(&self, axis: &UnitVector<Real>) -> (Real, Real) {
482 let cuboid = Cuboid::new(self.half_extents());
483 let shift = cuboid
484 .local_support_point_toward(axis)
485 .coords
486 .dot(axis)
487 .abs();
488 let center = self.center().coords.dot(axis);
489 (center - shift, center + shift)
490 }
491
492 #[cfg(feature = "dim3")]
493 #[cfg(feature = "alloc")]
494 pub fn intersects_spiral(
495 &self,
496 point: &Point<Real>,
497 center: &Point<Real>,
498 axis: &UnitVector<Real>,
499 linvel: &Vector<Real>,
500 angvel: Real,
501 ) -> bool {
502 use crate::utils::WBasis;
503 use crate::utils::{Interval, IntervalFunction};
504 use alloc::vec;
505
506 struct SpiralPlaneDistance {
507 center: Point<Real>,
508 tangents: [Vector<Real>; 2],
509 linvel: Vector<Real>,
510 angvel: Real,
511 point: na::Vector2<Real>,
512 plane: Vector<Real>,
513 bias: Real,
514 }
515
516 impl SpiralPlaneDistance {
517 fn spiral_pt_at(&self, t: Real) -> Point<Real> {
518 let angle = t * self.angvel;
519
520 let (sin, cos) = angle.sin_cos();
524 let rotmat = na::Matrix2::new(cos, -sin, sin, cos);
525
526 let rotated_pt = rotmat * self.point;
527 let shift = self.tangents[0] * rotated_pt.x + self.tangents[1] * rotated_pt.y;
528 self.center + self.linvel * t + shift
529 }
530 }
531
532 impl IntervalFunction<Real> for SpiralPlaneDistance {
533 fn eval(&self, t: Real) -> Real {
534 let point_pos = self.spiral_pt_at(t);
535 point_pos.coords.dot(&self.plane) - self.bias
536 }
537
538 fn eval_interval(&self, t: Interval<Real>) -> Interval<Real> {
539 let angle = t * self.angvel;
541 let (sin, cos) = angle.sin_cos();
542 let rotmat = na::Matrix2::new(cos, -sin, sin, cos);
543
544 let rotated_pt = rotmat * self.point.map(Interval::splat);
545 let shift = self.tangents[0].map(Interval::splat) * rotated_pt.x
546 + self.tangents[1].map(Interval::splat) * rotated_pt.y;
547 let point_pos =
548 self.center.map(Interval::splat) + self.linvel.map(Interval::splat) * t + shift;
549 point_pos.coords.dot(&self.plane.map(Interval::splat)) - Interval::splat(self.bias)
550 }
551
552 fn eval_interval_gradient(&self, t: Interval<Real>) -> Interval<Real> {
553 let angle = t * self.angvel;
554 let (sin, cos) = angle.sin_cos();
555 let rotmat = na::Matrix2::new(-sin, -cos, cos, -sin) * Interval::splat(self.angvel);
556
557 let rotated_pt = rotmat * self.point.map(Interval::splat);
558 let shift = self.tangents[0].map(Interval::splat) * rotated_pt.x
559 + self.tangents[1].map(Interval::splat) * rotated_pt.y;
560 let point_vel = shift + self.linvel.map(Interval::splat);
561 point_vel.dot(&self.plane.map(Interval::splat))
562 }
563 }
564
565 let tangents = axis.orthonormal_basis();
566 let dpos = point - center;
567 let mut distance_fn = SpiralPlaneDistance {
568 center: *center,
569 tangents,
570 linvel: *linvel,
571 angvel,
572 point: na::Vector2::new(dpos.dot(&tangents[0]), dpos.dot(&tangents[1])),
573 plane: Vector::x(),
574 bias: 0.0,
575 };
576
577 let mut roots = vec![];
579 let mut candidates = vec![];
580
581 let planes = [
582 (-self.mins[0], -Vector::x(), 0),
583 (self.maxs[0], Vector::x(), 0),
584 (-self.mins[1], -Vector::y(), 1),
585 (self.maxs[1], Vector::y(), 1),
586 (-self.mins[2], -Vector::z(), 2),
587 (self.maxs[2], Vector::z(), 2),
588 ];
589
590 let range = self.project_on_axis(axis);
591 let range_bias = center.coords.dot(axis);
592 let interval = Interval::sort(range.0, range.1) - range_bias;
593
594 for (bias, axis, i) in &planes {
595 distance_fn.plane = *axis;
596 distance_fn.bias = *bias;
597
598 crate::utils::find_root_intervals_to(
599 &distance_fn,
600 interval,
601 1.0e-5,
602 1.0e-5,
603 100,
604 &mut roots,
605 &mut candidates,
606 );
607
608 for root in roots.drain(..) {
609 let point = distance_fn.spiral_pt_at(root.midpoint());
610 let (j, k) = ((i + 1) % 3, (i + 2) % 3);
611 if point[j] >= self.mins[j]
612 && point[j] <= self.maxs[j]
613 && point[k] >= self.mins[k]
614 && point[k] <= self.maxs[k]
615 {
616 return true;
617 }
618 }
619 }
620
621 false
622 }
623}
624
625impl BoundingVolume for Aabb {
626 #[inline]
627 fn center(&self) -> Point<Real> {
628 self.center()
629 }
630
631 #[inline]
632 fn intersects(&self, other: &Aabb) -> bool {
633 na::partial_le(&self.mins, &other.maxs) && na::partial_ge(&self.maxs, &other.mins)
634 }
635
636 #[inline]
637 fn contains(&self, other: &Aabb) -> bool {
638 na::partial_le(&self.mins, &other.mins) && na::partial_ge(&self.maxs, &other.maxs)
639 }
640
641 #[inline]
642 fn merge(&mut self, other: &Aabb) {
643 self.mins = self.mins.inf(&other.mins);
644 self.maxs = self.maxs.sup(&other.maxs);
645 }
646
647 #[inline]
648 fn merged(&self, other: &Aabb) -> Aabb {
649 Aabb {
650 mins: self.mins.inf(&other.mins),
651 maxs: self.maxs.sup(&other.maxs),
652 }
653 }
654
655 #[inline]
656 fn loosen(&mut self, amount: Real) {
657 assert!(amount >= 0.0, "The loosening margin must be positive.");
658 self.mins += Vector::repeat(-amount);
659 self.maxs += Vector::repeat(amount);
660 }
661
662 #[inline]
663 fn loosened(&self, amount: Real) -> Aabb {
664 assert!(amount >= 0.0, "The loosening margin must be positive.");
665 Aabb {
666 mins: self.mins + Vector::repeat(-amount),
667 maxs: self.maxs + Vector::repeat(amount),
668 }
669 }
670
671 #[inline]
672 fn tighten(&mut self, amount: Real) {
673 assert!(amount >= 0.0, "The tightening margin must be positive.");
674 self.mins += Vector::repeat(amount);
675 self.maxs += Vector::repeat(-amount);
676 assert!(
677 na::partial_le(&self.mins, &self.maxs),
678 "The tightening margin is to large."
679 );
680 }
681
682 #[inline]
683 fn tightened(&self, amount: Real) -> Aabb {
684 assert!(amount >= 0.0, "The tightening margin must be positive.");
685
686 Aabb::new(
687 self.mins + Vector::repeat(amount),
688 self.maxs + Vector::repeat(-amount),
689 )
690 }
691}