imath/
bbox.rs

1use super::traits::*;
2use super::vec::*;
3use std::fmt;
4
5#[repr(C)]
6#[derive(Clone, Debug, Eq, PartialEq)]
7/// A generic N-dimensional bounding box type. We use the name BBox instead of
8/// Imath's `Box` since Box is already a type in Rust. Otherwise it functions
9/// much the same.
10pub struct BBox<T>
11where
12    T: Vector,
13{
14    min: T,
15    max: T,
16}
17
18pub type Box2i32 = BBox<V2i32>;
19pub type Box2f32 = BBox<V2f32>;
20pub type Box2f64 = BBox<V2f64>;
21pub type Box3i32 = BBox<V3i32>;
22pub type Box3f32 = BBox<V3f32>;
23pub type Box3f64 = BBox<V3f64>;
24
25impl<T> fmt::Display for BBox<T>
26where
27    T: Vector + fmt::Display,
28{
29    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
30        write!(f, "[{}, {}]", self.min, self.max)
31    }
32}
33
34impl<T> BBox<T>
35where
36    T: Vector,
37{
38    /// Create a new, empty bounding box
39    pub fn new() -> BBox<T> {
40        BBox::<T>::make_empty()
41    }
42
43    /// Create a new, empty bounding box
44    pub fn make_empty() -> BBox<T> {
45        BBox::<T> {
46            min: T::max_value(),
47            max: T::min_value(),
48        }
49    }
50
51    /// Create a new bounding box with the largest possible extent representable
52    /// the base type
53    pub fn make_infinite() -> BBox<T> {
54        BBox::<T> {
55            min: T::min_value(),
56            max: T::max_value(),
57        }
58    }
59
60    /// Return a new bounding box covering the total extent of `self` and
61    /// `point`
62    pub fn extend_by_pnt(&self, point: T) -> BBox<T> {
63        BBox::<T> {
64            min: self.min.min(point),
65            max: self.max.max(point),
66        }
67    }
68
69    /// Return a new bounding box covering the total extent of `self` and
70    /// `other`
71    pub fn extend_by_box(&self, other: &BBox<T>) -> BBox<T> {
72        BBox::<T> {
73            min: self.min.min(other.min),
74            max: self.max.max(other.max),
75        }
76    }
77
78    /// Return the dimensions of the bounding box
79    pub fn size(&self) -> T
80    where
81        T: Vector,
82    {
83        self.max - self.min
84    }
85
86    /// Return the center of the bounding box
87    pub fn center(&self) -> T
88    where
89        T: Vector,
90    {
91        // This is a bit ugly currently. Might be preferable to compute in user
92        // code rather than use this function.
93        self.min + (self.max - self.min) / (T::one() + T::one())
94    }
95
96    /// Returns true if the bounding box is empty
97    pub fn is_empty(&self) -> bool
98    where
99        T: Vector,
100    {
101        self.max < self.min
102    }
103
104    /// Returns true if the bounding box is not empty
105    pub fn has_volume(&self) -> bool
106    where
107        T: Vector,
108    {
109        !self.is_empty()
110    }
111
112    /// Returns true if the bounding box covers the maximum representable range
113    pub fn is_infinite(&self) -> bool
114    where
115        T: Vector,
116    {
117        self.min == T::min_value() && self.max == T::max_value()
118    }
119
120    /// Returns true if the bounding box contains the point
121    pub fn contains(&self, point: T) -> bool
122    where
123        T: Vector,
124    {
125        point >= self.min && point <= self.max
126    }
127}
128
129impl Box2i32 {
130    pub fn intersects(&self, other: &Box2i32) -> bool {
131        if other.max.x < self.min.x
132            || other.max.y < self.min.y
133            || other.min.x > self.max.x
134            || other.min.y > self.max.y
135        {
136            false
137        } else {
138            true
139        }
140    }
141}
142
143impl Box2f32 {
144    pub fn intersects(&self, other: &Box2f32) -> bool {
145        if other.max.x < self.min.x
146            || other.max.y < self.min.y
147            || other.min.x > self.max.x
148            || other.min.y > self.max.y
149        {
150            false
151        } else {
152            true
153        }
154    }
155}
156
157impl Box2f64 {
158    pub fn intersects(&self, other: &Box2f64) -> bool {
159        if other.max.x < self.min.x
160            || other.max.y < self.min.y
161            || other.min.x > self.max.x
162            || other.min.y > self.max.y
163        {
164            false
165        } else {
166            true
167        }
168    }
169}
170
171impl Box3i32 {
172    pub fn intersects(&self, other: &Box3i32) -> bool {
173        if other.max.x < self.min.x
174            || other.max.y < self.min.y
175            || other.max.z < self.max.z
176            || other.min.x > self.max.x
177            || other.min.y > self.max.y
178            || other.min.z > self.max.z
179        {
180            false
181        } else {
182            true
183        }
184    }
185}
186
187impl Box3f32 {
188    pub fn intersects(&self, other: &Box3f32) -> bool {
189        if other.max.x < self.min.x
190            || other.max.y < self.min.y
191            || other.max.z < self.max.z
192            || other.min.x > self.max.x
193            || other.min.y > self.max.y
194            || other.min.z > self.max.z
195        {
196            false
197        } else {
198            true
199        }
200    }
201}
202
203impl Box3f64 {
204    pub fn intersects(&self, other: &Box3f64) -> bool {
205        if other.max.x < self.min.x
206            || other.max.y < self.min.y
207            || other.max.z < self.max.z
208            || other.min.x > self.max.x
209            || other.min.y > self.max.y
210            || other.min.z > self.max.z
211        {
212            false
213        } else {
214            true
215        }
216    }
217}
218
219#[test]
220fn test_bbox() {
221    let b21 = Box2f32::new();
222    assert!(b21.is_empty());
223
224    let v21 = V2f32 { x: -1.0, y: -1.0 };
225    let v22 = V2f32 { x: 1.0, y: 1.0 };
226    let b22 = b21.extend_by_pnt(v21);
227    println!("b22: {}", b22);
228    assert!(b22.has_volume());
229    assert!(!b22.is_infinite());
230    assert!(b22.min == v21 && b22.max == v21);
231    let b23 = b22.extend_by_pnt(v22);
232    assert!(b23.min == v21 && b23.max == v22);
233
234    let b24 = Box2f32 {
235        min: V2f32 { x: 2.0, y: 2.0 },
236        max: V2f32 { x: 3.0, y: 3.0 },
237    };
238    let b25 = Box2f32 {
239        min: V2f32 { x: 0.0, y: 0.0 },
240        max: V2f32 { x: 3.0, y: 3.0 },
241    };
242    assert!(!b23.intersects(&b24));
243    assert!(b23.intersects(&b25));
244    assert!(b25.contains(v22));
245
246    let b28 = Box2f32 {
247        min: V2f32 { x: -1.0, y: -1.0 },
248        max: V2f32 { x: 3.0, y: 3.0 },
249    };
250
251    let b29 = Box2f32 {
252        min: V2f32 { x: 0.0, y: 0.0 },
253        max: V2f32 { x: 2.0, y: 2.0 },
254    };
255
256    assert!(b28.intersects(&b29));
257
258    let b26 = b23.extend_by_box(&b25);
259    assert!(b26.size() == V2f32 { x: 4.0, y: 4.0 });
260    assert!(b26.center() == V2f32 { x: 1.0, y: 1.0 });
261
262    let b27 = Box2f32::make_infinite();
263    assert!(b27.is_infinite());
264}