Skip to main content

manifold_rust/
types_bounds.rs

1// types_bounds.rs — axis-aligned bounding volumes: Box (3D) and Rect (2D).
2//
3// Ported from include/manifold/common.h. Extracted from types.rs, which
4// re-exports both types so external paths (`crate::types::Box`,
5// `crate::types::Rect`) are unchanged. The collider (collider.rs) and the
6// broadphase queries in boolean3.rs are the main consumers of Box; Rect
7// backs the 2D cross-section pipeline (cross_section.rs, tree2d.rs).
8
9use crate::linalg::{Vec2, Vec3, Mat3x4};
10
11// ---------------------------------------------------------------------------
12// Box (3D axis-aligned bounding box)
13// ---------------------------------------------------------------------------
14
15#[derive(Clone, Copy, Debug, PartialEq)]
16pub struct Box {
17    pub min: Vec3,
18    pub max: Vec3,
19}
20
21impl Default for Box {
22    fn default() -> Self {
23        Box {
24            min: Vec3::splat(f64::INFINITY),
25            max: Vec3::splat(f64::NEG_INFINITY),
26        }
27    }
28}
29
30impl Box {
31    /// Default is an infinite box containing all space.
32    pub fn new() -> Self {
33        Self::default()
34    }
35
36    /// Box containing the two given points.
37    pub fn from_points(p1: Vec3, p2: Vec3) -> Self {
38        Box {
39            min: Vec3::new(p1.x.min(p2.x), p1.y.min(p2.y), p1.z.min(p2.z)),
40            max: Vec3::new(p1.x.max(p2.x), p1.y.max(p2.y), p1.z.max(p2.z)),
41        }
42    }
43
44    /// A box containing a single point.
45    pub fn from_point(p: Vec3) -> Self {
46        Box { min: p, max: p }
47    }
48
49    /// True when the box has no volume (min > max on any axis).
50    pub fn is_empty(&self) -> bool {
51        self.min.x > self.max.x || self.min.y > self.max.y || self.min.z > self.max.z
52    }
53
54    pub fn size(&self) -> Vec3 {
55        self.max - self.min
56    }
57
58    pub fn center(&self) -> Vec3 {
59        (self.max + self.min) * 0.5
60    }
61
62    /// Absolute-largest coordinate value.
63    pub fn scale(&self) -> f64 {
64        let abs_min = Vec3::new(self.min.x.abs(), self.min.y.abs(), self.min.z.abs());
65        let abs_max = Vec3::new(self.max.x.abs(), self.max.y.abs(), self.max.z.abs());
66        let m = Vec3::new(
67            abs_min.x.max(abs_max.x),
68            abs_min.y.max(abs_max.y),
69            abs_min.z.max(abs_max.z),
70        );
71        m.x.max(m.y).max(m.z)
72    }
73
74    pub fn contains_point(&self, p: Vec3) -> bool {
75        p.x >= self.min.x && p.x <= self.max.x
76            && p.y >= self.min.y && p.y <= self.max.y
77            && p.z >= self.min.z && p.z <= self.max.z
78    }
79
80    pub fn contains_box(&self, other: &Box) -> bool {
81        other.min.x >= self.min.x && other.max.x <= self.max.x
82            && other.min.y >= self.min.y && other.max.y <= self.max.y
83            && other.min.z >= self.min.z && other.max.z <= self.max.z
84    }
85
86    /// Expand in-place to include the given point.
87    pub fn union_point(&mut self, p: Vec3) {
88        self.min.x = self.min.x.min(p.x);
89        self.min.y = self.min.y.min(p.y);
90        self.min.z = self.min.z.min(p.z);
91        self.max.x = self.max.x.max(p.x);
92        self.max.y = self.max.y.max(p.y);
93        self.max.z = self.max.z.max(p.z);
94    }
95
96    /// Return the union of this box with another.
97    pub fn union_box(&self, other: &Box) -> Box {
98        Box {
99            min: Vec3::new(
100                self.min.x.min(other.min.x),
101                self.min.y.min(other.min.y),
102                self.min.z.min(other.min.z),
103            ),
104            max: Vec3::new(
105                self.max.x.max(other.max.x),
106                self.max.y.max(other.max.y),
107                self.max.z.max(other.max.z),
108            ),
109        }
110    }
111
112    /// Transform by axis-aligned affine transform (Mat3x4 * vec4(pt, 1)).
113    pub fn transform(&self, t: &Mat3x4) -> Box {
114        use crate::linalg::Vec4 as V4;
115        let min_t = *t * V4::new(self.min.x, self.min.y, self.min.z, 1.0);
116        let max_t = *t * V4::new(self.max.x, self.max.y, self.max.z, 1.0);
117        Box {
118            min: Vec3::new(min_t.x.min(max_t.x), min_t.y.min(max_t.y), min_t.z.min(max_t.z)),
119            max: Vec3::new(min_t.x.max(max_t.x), min_t.y.max(max_t.y), min_t.z.max(max_t.z)),
120        }
121    }
122
123    pub fn does_overlap_box(&self, other: &Box) -> bool {
124        self.min.x <= other.max.x && self.min.y <= other.max.y && self.min.z <= other.max.z
125            && self.max.x >= other.min.x && self.max.y >= other.min.y && self.max.z >= other.min.z
126    }
127
128    /// Does the given point project within the XY extent (including equality)?
129    pub fn does_overlap_point_xy(&self, p: Vec3) -> bool {
130        p.x >= self.min.x && p.x <= self.max.x && p.y >= self.min.y && p.y <= self.max.y
131    }
132
133    pub fn is_finite(&self) -> bool {
134        self.min.x.is_finite() && self.min.y.is_finite() && self.min.z.is_finite()
135            && self.max.x.is_finite() && self.max.y.is_finite() && self.max.z.is_finite()
136    }
137}
138
139impl std::ops::Add<Vec3> for Box {
140    type Output = Box;
141    fn add(self, shift: Vec3) -> Box {
142        Box { min: self.min + shift, max: self.max + shift }
143    }
144}
145impl std::ops::AddAssign<Vec3> for Box {
146    fn add_assign(&mut self, shift: Vec3) {
147        self.min = self.min + shift;
148        self.max = self.max + shift;
149    }
150}
151impl std::ops::Mul<Vec3> for Box {
152    type Output = Box;
153    fn mul(self, scale: Vec3) -> Box {
154        Box { min: self.min * scale, max: self.max * scale }
155    }
156}
157impl std::ops::MulAssign<Vec3> for Box {
158    fn mul_assign(&mut self, scale: Vec3) {
159        self.min = self.min * scale;
160        self.max = self.max * scale;
161    }
162}
163
164// ---------------------------------------------------------------------------
165// Rect (2D axis-aligned bounding box)
166// ---------------------------------------------------------------------------
167
168#[derive(Clone, Copy, Debug, PartialEq)]
169pub struct Rect {
170    pub min: Vec2,
171    pub max: Vec2,
172}
173
174impl Default for Rect {
175    fn default() -> Self {
176        Rect {
177            min: Vec2::splat(f64::INFINITY),
178            max: Vec2::splat(f64::NEG_INFINITY),
179        }
180    }
181}
182
183impl Rect {
184    pub fn new() -> Self {
185        Self::default()
186    }
187
188    pub fn from_points(a: Vec2, b: Vec2) -> Self {
189        Rect {
190            min: Vec2::new(a.x.min(b.x), a.y.min(b.y)),
191            max: Vec2::new(a.x.max(b.x), a.y.max(b.y)),
192        }
193    }
194
195    pub fn size(&self) -> Vec2 {
196        self.max - self.min
197    }
198
199    pub fn area(&self) -> f64 {
200        let sz = self.size();
201        sz.x * sz.y
202    }
203
204    pub fn scale(&self) -> f64 {
205        let abs_min = Vec2::new(self.min.x.abs(), self.min.y.abs());
206        let abs_max = Vec2::new(self.max.x.abs(), self.max.y.abs());
207        let m = Vec2::new(abs_min.x.max(abs_max.x), abs_min.y.max(abs_max.y));
208        m.x.max(m.y)
209    }
210
211    pub fn center(&self) -> Vec2 {
212        (self.max + self.min) * 0.5
213    }
214
215    pub fn contains_point(&self, p: Vec2) -> bool {
216        p.x >= self.min.x && p.x <= self.max.x && p.y >= self.min.y && p.y <= self.max.y
217    }
218
219    pub fn contains_rect(&self, other: &Rect) -> bool {
220        other.min.x >= self.min.x && other.max.x <= self.max.x
221            && other.min.y >= self.min.y && other.max.y <= self.max.y
222    }
223
224    pub fn does_overlap(&self, other: &Rect) -> bool {
225        self.min.x <= other.max.x && self.min.y <= other.max.y
226            && self.max.x >= other.min.x && self.max.y >= other.min.y
227    }
228
229    pub fn is_empty(&self) -> bool {
230        self.max.y <= self.min.y || self.max.x <= self.min.x
231    }
232
233    pub fn is_finite(&self) -> bool {
234        self.min.x.is_finite() && self.min.y.is_finite()
235            && self.max.x.is_finite() && self.max.y.is_finite()
236    }
237
238    pub fn union_point(&mut self, p: Vec2) {
239        self.min.x = self.min.x.min(p.x);
240        self.min.y = self.min.y.min(p.y);
241        self.max.x = self.max.x.max(p.x);
242        self.max.y = self.max.y.max(p.y);
243    }
244
245    pub fn union_rect(&self, other: &Rect) -> Rect {
246        Rect {
247            min: Vec2::new(self.min.x.min(other.min.x), self.min.y.min(other.min.y)),
248            max: Vec2::new(self.max.x.max(other.max.x), self.max.y.max(other.max.y)),
249        }
250    }
251}
252
253impl std::ops::Add<Vec2> for Rect {
254    type Output = Rect;
255    fn add(self, shift: Vec2) -> Rect {
256        Rect { min: self.min + shift, max: self.max + shift }
257    }
258}
259impl std::ops::AddAssign<Vec2> for Rect {
260    fn add_assign(&mut self, shift: Vec2) {
261        self.min = self.min + shift;
262        self.max = self.max + shift;
263    }
264}
265impl std::ops::Mul<Vec2> for Rect {
266    type Output = Rect;
267    fn mul(self, scale: Vec2) -> Rect {
268        Rect { min: self.min * scale, max: self.max * scale }
269    }
270}
271impl std::ops::MulAssign<Vec2> for Rect {
272    fn mul_assign(&mut self, scale: Vec2) {
273        self.min = self.min * scale;
274        self.max = self.max * scale;
275    }
276}