generic_octree/
aabb.rs

1use crate::Orientation;
2use std::fmt::Debug;
3
4pub enum PlaneAxis {
5    X,
6    Y,
7    Z,
8}
9
10pub struct Plane(f64, PlaneAxis);
11
12#[derive(Debug, Clone)]
13pub struct AABB {
14    x1: f64,
15    y1: f64,
16    z1: f64,
17    x2: f64,
18    y2: f64,
19    z2: f64,
20    pub orientation: Orientation,
21}
22
23#[inline]
24pub fn min<T: PartialOrd>(a: T, b: T) -> T {
25    if a > b {
26        b
27    } else {
28        a
29    }
30}
31
32#[inline]
33pub fn max<T: PartialOrd>(a: T, b: T) -> T {
34    if a < b {
35        b
36    } else {
37        a
38    }
39}
40
41impl AABB {
42    pub fn new(x1: f64, y1: f64, z1: f64, x2: f64, y2: f64, z2: f64) -> Self {
43        Self {
44            x1: min(x1, x2),
45            y1: min(y1, y2),
46            z1: min(z1, z2),
47            x2: max(x2, x1),
48            y2: max(y1, y2),
49            z2: max(z1, z2),
50            orientation: Orientation::N,
51        }
52    }
53
54    pub fn with_orientation(mut self, orientation: Orientation) -> Self {
55        self.orientation = orientation;
56        self
57    }
58
59    pub fn slice(self, plane: Plane) -> Vec<Self> {
60        let orientation = self.orientation;
61        match plane.1 {
62            PlaneAxis::X => {
63                if self.x1 < plane.0 && self.x2 > plane.0 {
64                    vec![
65                        Self::new(self.x1, self.y1, self.z1, plane.0, self.y2, self.z2)
66                            .with_orientation(orientation | Orientation::L),
67                        Self::new(plane.0, self.y1, self.z1, self.x2, self.y2, self.z2)
68                            .with_orientation(orientation | Orientation::R),
69                    ]
70                } else if self.x2 <= plane.0 {
71                    vec![self.with_orientation(orientation | Orientation::L)]
72                } else {
73                    vec![self.with_orientation(orientation | Orientation::R)]
74                }
75            }
76            PlaneAxis::Y => {
77                if self.y1 < plane.0 && self.y2 > plane.0 {
78                    vec![
79                        Self::new(self.x1, self.y1, self.z1, self.x2, plane.0, self.z2)
80                            .with_orientation(orientation | Orientation::D),
81                        Self::new(self.x1, plane.0, self.z1, self.x2, self.y2, self.z2)
82                            .with_orientation(orientation | Orientation::U),
83                    ]
84                } else if self.y2 <= plane.0 {
85                    vec![self.with_orientation(orientation | Orientation::D)]
86                } else {
87                    vec![self.with_orientation(orientation | Orientation::U)]
88                }
89            }
90            PlaneAxis::Z => {
91                if self.z1 < plane.0 && self.z2 > plane.0 {
92                    vec![
93                        Self::new(self.x1, self.y1, self.z1, self.x2, self.y2, plane.0)
94                            .with_orientation(orientation | Orientation::B),
95                        Self::new(self.x1, self.y1, plane.0, self.x2, self.y2, self.z2)
96                            .with_orientation(orientation | Orientation::F),
97                    ]
98                } else if self.z2 <= plane.0 {
99                    vec![self.with_orientation(orientation | Orientation::B)]
100                } else {
101                    vec![self.with_orientation(orientation | Orientation::F)]
102                }
103            }
104        }
105    }
106
107    pub fn explode(self, center: (f64, f64, f64)) -> Vec<Self> {
108        self.slice(Plane(center.0, PlaneAxis::X))
109            .into_iter()
110            .map(|aabb| aabb.slice(Plane(center.1, PlaneAxis::Y)))
111            .flatten()
112            .map(|aabb| aabb.slice(Plane(center.2, PlaneAxis::Z)))
113            .flatten()
114            .collect()
115    }
116
117    pub fn fit_in(&self, depth: u32, max_depth: u32) -> bool {
118        let edge_size = 1_f64 / (2_usize.pow(depth) as f64);
119        (((self.x1 - self.x2).abs() - edge_size).abs() < std::f64::EPSILON
120            && ((self.y1 - self.y2).abs() - edge_size).abs() < std::f64::EPSILON
121            && ((self.z1 - self.z2).abs() - edge_size).abs() < std::f64::EPSILON)
122            || depth == max_depth
123    }
124
125    pub fn offset(mut self, offset: (f64, f64, f64)) -> Self {
126        self.x1 += offset.0;
127        self.y1 += offset.1;
128        self.z1 += offset.2;
129        self.x2 += offset.0;
130        self.y2 += offset.1;
131        self.z2 += offset.2;
132        self
133    }
134
135    pub fn normalize(self) -> Self {
136        let max_x = max(self.x1, self.x2);
137        let max_y = max(self.x1, self.x2);
138        let max_z = max(self.x1, self.x2);
139        Self::new(
140            self.x1 / max_x,
141            self.y1 / max_y,
142            self.z1 / max_z,
143            self.x2 / max_x,
144            self.y2 / max_y,
145            self.z2 / max_z,
146        )
147    }
148
149    pub fn normalize_with(self, normalization_vector: (f64, f64, f64)) -> Self {
150        Self::new(
151            self.x1 / normalization_vector.0,
152            self.y1 / normalization_vector.1,
153            self.z1 / normalization_vector.2,
154            self.x2 / normalization_vector.0,
155            self.y2 / normalization_vector.1,
156            self.z2 / normalization_vector.2,
157        )
158    }
159}