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}