rust_3d/
box_3d.rs

1/*
2Copyright 2017 Martin Buck
3
4Permission is hereby granted, free of charge, to any person obtaining a copy
5of this software and associated documentation files (the "Software"),
6to deal in the Software without restriction, including without limitation the
7rights to use, copy, modify, merge, publish, distribute, sublicense,
8and/or sell copies of the Software, and to permit persons to whom the Software
9is furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice shall
12be included all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
20OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21*/
22
23//! Box3D, a box in 3D space
24
25use std::cmp::{Eq, Ordering};
26
27use crate::*;
28
29//------------------------------------------------------------------------------
30
31#[derive(Debug, PartialEq, PartialOrd, Clone, Hash, Default)]
32/// Box3D, a box in 3D space
33pub 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    /// Returns the minimum position of the box
42    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    /// Returns the maximum position of the box
50    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    /// Returns the sizes of the bounding box
58    pub fn sizes(&self) -> [Positive; 3] {
59        [self.size_x, self.size_y, self.size_z]
60    }
61}
62
63//------------------------------------------------------------------------------
64
65impl 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() // safe
189    }
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}