Skip to main content

conspire/geometry/bbox/base/
mod.rs

1#[cfg(test)]
2mod test;
3
4use crate::{
5    geometry::{Coordinate, bbox::BoundingBox},
6    math::{Scalar, Tensor},
7};
8use std::array::from_fn;
9
10impl<const D: usize> BoundingBox<D> {
11    pub fn minimum(&self) -> &Coordinate<D> {
12        &self.minimum
13    }
14    pub fn maximum(&self) -> &Coordinate<D> {
15        &self.maximum
16    }
17    pub fn overlaps(&self, other: &Self) -> bool {
18        (0..D).all(|d| self.minimum[d] <= other.maximum[d] && other.minimum[d] <= self.maximum[d])
19    }
20    pub fn longest_axis(&self) -> usize {
21        self.maximum
22            .iter()
23            .zip(self.minimum.iter())
24            .enumerate()
25            .map(|(i, (&max, &min))| (i, max - min))
26            .max_by(|(_, length_a), (_, length_b)| length_a.partial_cmp(length_b).unwrap())
27            .unwrap()
28            .0
29    }
30    pub fn shortest_axis(&self) -> usize {
31        self.maximum
32            .iter()
33            .zip(self.minimum.iter())
34            .enumerate()
35            .map(|(i, (&max, &min))| (i, max - min))
36            .min_by(|(_, length_a), (_, length_b)| length_a.partial_cmp(length_b).unwrap())
37            .unwrap()
38            .0
39    }
40}
41
42impl BoundingBox<3> {
43    pub fn overlaps_triangle(
44        &self,
45        a: &Coordinate<3>,
46        b: &Coordinate<3>,
47        c: &Coordinate<3>,
48    ) -> bool {
49        let center: [Scalar; 3] = from_fn(|k| (self.minimum[k] + self.maximum[k]) * 0.5);
50        let half: [Scalar; 3] = from_fn(|k| (self.maximum[k] - self.minimum[k]) * 0.5);
51        let v: [[Scalar; 3]; 3] = [a, b, c].map(|p| from_fn(|k| p[k] - center[k]));
52        let edges: [[Scalar; 3]; 3] = [
53            from_fn(|k| v[1][k] - v[0][k]),
54            from_fn(|k| v[2][k] - v[1][k]),
55            from_fn(|k| v[0][k] - v[2][k]),
56        ];
57        for k in 0..3 {
58            for e in &edges {
59                let axis = match k {
60                    0 => [0.0, -e[2], e[1]],
61                    1 => [e[2], 0.0, -e[0]],
62                    _ => [-e[1], e[0], 0.0],
63                };
64                let radius = (0..3).map(|i| half[i] * axis[i].abs()).sum();
65                let projection: [Scalar; 3] = from_fn(|i| (0..3).map(|j| axis[j] * v[i][j]).sum());
66                let low = projection[0].min(projection[1]).min(projection[2]);
67                let high = projection[0].max(projection[1]).max(projection[2]);
68                if low > radius || high < -radius {
69                    return false;
70                }
71            }
72        }
73        for k in 0..3 {
74            let low = v[0][k].min(v[1][k]).min(v[2][k]);
75            let high = v[0][k].max(v[1][k]).max(v[2][k]);
76            if low > half[k] || high < -half[k] {
77                return false;
78            }
79        }
80        let normal: [Scalar; 3] = from_fn(|k| {
81            let (i, j) = ((k + 1) % 3, (k + 2) % 3);
82            edges[0][i] * edges[1][j] - edges[0][j] * edges[1][i]
83        });
84        let radius = (0..3).map(|i| half[i] * normal[i].abs()).sum();
85        let distance: Scalar = (0..3).map(|i| normal[i] * v[0][i]).sum();
86        distance.abs() <= radius
87    }
88}