1use std::cmp::{Eq, Ordering};
26
27use crate::*;
28
29#[derive(Debug, PartialEq, PartialOrd, Clone, Hash, Default)]
32pub struct Box3D {
34 pub center: Point3D,
35 pub size_x: Positive,
36 pub size_y: Positive,
37 pub size_z: Positive,
38}
39
40impl Box3D {
41 pub fn min_p(&self) -> Point3D {
43 Point3D::new(
44 self.center.x() - 0.5 * self.size_x.get(),
45 self.center.y() - 0.5 * self.size_y.get(),
46 self.center.z() - 0.5 * self.size_z.get(),
47 )
48 }
49 pub fn max_p(&self) -> Point3D {
51 Point3D::new(
52 self.center.x() + 0.5 * self.size_x.get(),
53 self.center.y() + 0.5 * self.size_y.get(),
54 self.center.z() + 0.5 * self.size_z.get(),
55 )
56 }
57 pub fn sizes(&self) -> [Positive; 3] {
59 [self.size_x, self.size_y, self.size_z]
60 }
61}
62
63impl Eq for Box3D {}
66
67impl Ord for Box3D {
68 fn cmp(&self, other: &Self) -> Ordering {
69 let origin = Point3D::default();
70 match sqr_dist_3d(&origin, &self.center).partial_cmp(&sqr_dist_3d(&origin, &other.center)) {
71 Some(x) => x,
72 None => match self.size_x.partial_cmp(&other.size_x) {
73 Some(x) => x,
74 None => match self.size_y.partial_cmp(&other.size_y) {
75 Some(x) => x,
76 None => self
77 .size_z
78 .partial_cmp(&other.size_z)
79 .unwrap_or(Ordering::Equal),
80 },
81 },
82 }
83 }
84}
85
86impl IsND for Box3D {
87 fn n_dimensions() -> usize {
88 Point3D::n_dimensions()
89 }
90
91 fn position_nd(&self, dimension: usize) -> Result<f64> {
92 self.center.position_nd(dimension)
93 }
94}
95
96impl Is3D for Box3D {
97 #[inline(always)]
98 fn x(&self) -> f64 {
99 self.center.x()
100 }
101
102 #[inline(always)]
103 fn y(&self) -> f64 {
104 self.center.y()
105 }
106
107 #[inline(always)]
108 fn z(&self) -> f64 {
109 self.center.z()
110 }
111}
112
113impl IsBuildableND for Box3D {
114 #[inline(always)]
115 fn new_nd(coords: &[f64]) -> Result<Self> {
116 Ok(Box3D {
117 center: Point3D::new_nd(coords)?,
118 size_x: Positive::one(),
119 size_y: Positive::one(),
120 size_z: Positive::one(),
121 })
122 }
123
124 #[inline(always)]
125 fn from_nd<P>(&mut self, other: P) -> Result<()>
126 where
127 P: IsBuildableND,
128 {
129 self.center.from_nd(other)
130 }
131}
132
133impl IsBuildable3D for Box3D {
134 #[inline(always)]
135 fn new(x: f64, y: f64, z: f64) -> Self {
136 Box3D {
137 center: Point3D { x, y, z },
138 size_x: Positive::one(),
139 size_y: Positive::one(),
140 size_z: Positive::one(),
141 }
142 }
143
144 #[inline(always)]
145 fn from<P>(&mut self, other: &P)
146 where
147 P: Is3D,
148 {
149 self.center.from(other)
150 }
151}
152
153impl IsEditableND for Box3D {
154 fn set_position(&mut self, dimension: usize, val: f64) -> Result<()> {
155 self.center.set_position(dimension, val)
156 }
157}
158
159impl IsEditable3D for Box3D {
160 #[inline(always)]
161 fn set_x(&mut self, val: f64) {
162 self.center.set_x(val);
163 }
164
165 #[inline(always)]
166 fn set_y(&mut self, val: f64) {
167 self.center.set_y(val);
168 }
169
170 #[inline(always)]
171 fn set_z(&mut self, val: f64) {
172 self.center.set_z(val);
173 }
174}
175
176impl HasBoundingBox3D for Box3D {
177 fn bounding_box(&self) -> BoundingBox3D {
178 let p_min = Point3D {
179 x: self.center.x() - self.size_x.get() / 2.0,
180 y: self.center.y() - self.size_y.get() / 2.0,
181 z: self.center.z() - self.size_z.get() / 2.0,
182 };
183 let p_max = Point3D {
184 x: self.center.x() + self.size_x.get() / 2.0,
185 y: self.center.y() + self.size_y.get() / 2.0,
186 z: self.center.z() + self.size_z.get() / 2.0,
187 };
188 BoundingBox3D::new(&p_min, &p_max).unwrap() }
190}
191
192impl HasBoundingBox3DMaybe for Box3D {
193 fn bounding_box_maybe(&self) -> Result<BoundingBox3D> {
194 Ok(self.bounding_box())
195 }
196}
197
198impl IsScalable for Box3D {
199 fn scale(&mut self, factor: Positive) {
200 self.size_x *= factor;
201 self.size_y *= factor;
202 self.size_z *= factor;
203 }
204}
205
206impl IsMovable3D for Box3D {
207 fn move_by(&mut self, x: f64, y: f64, z: f64) {
208 self.center.move_by(x, y, z)
209 }
210}
211
212impl From<BoundingBox3D> for Box3D {
213 fn from(x: BoundingBox3D) -> Self {
214 Box3D {
215 center: x.center_bb(),
216 size_x: x.size_x(),
217 size_y: x.size_y(),
218 size_z: x.size_z(),
219 }
220 }
221}