1 use {Rect, Box2D, Box3D, Vector2D, Vector3D, size2, point2, point3};
2 use approxord::{min, max};
3 use core::ops::Deref;
4 use core::ops::{Add, Sub};
5 use core::cmp::{PartialEq};
6 
7 
8 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
9 #[cfg_attr(feature = "serde", serde(transparent))]
10 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
11 pub struct NonEmpty<T>(pub(crate) T);
12 
13 impl<T> Deref for NonEmpty<T> {
14     type Target = T;
deref(&self) -> &T15     fn deref(&self) -> &T {
16         &self.0
17     }
18 }
19 
20 impl<T> NonEmpty<T> {
21     #[inline]
get(&self) -> &T22     pub fn get(&self) -> &T {
23         &self.0
24     }
25 }
26 
27 impl<T, U> NonEmpty<Rect<T, U>>
28 where
29     T: Copy + PartialOrd + Add<T, Output = T> + Sub<T, Output = T>,
30 {
31     #[inline]
union(&self, other: &NonEmpty<Rect<T, U>>) -> NonEmpty<Rect<T, U>>32     pub fn union(&self, other: &NonEmpty<Rect<T, U>>) -> NonEmpty<Rect<T, U>> {
33         let origin = point2(
34             min(self.min_x(), other.min_x()),
35             min(self.min_y(), other.min_y()),
36         );
37 
38         let lower_right_x = max(self.max_x(), other.max_x());
39         let lower_right_y = max(self.max_y(), other.max_y());
40 
41         NonEmpty(Rect {
42             origin,
43             size: size2(
44                 lower_right_x - origin.x,
45                 lower_right_y - origin.y,
46             ),
47         })
48     }
49 
50     #[inline]
contains_rect(&self, rect: &Self) -> bool51     pub fn contains_rect(&self, rect: &Self) -> bool {
52         self.min_x() <= rect.min_x()
53             && rect.max_x() <= self.max_x()
54             && self.min_y() <= rect.min_y()
55             && rect.max_y() <= self.max_y()
56     }
57 
58     #[inline]
translate(&self, by: Vector2D<T, U>) -> Self59     pub fn translate(&self, by: Vector2D<T, U>) -> Self {
60         NonEmpty(self.0.translate(by))
61     }
62 }
63 
64 impl<T, U> NonEmpty<Box2D<T, U>>
65 where
66     T: Copy + PartialOrd,
67 {
68     #[inline]
union(&self, other: &NonEmpty<Box2D<T, U>>) -> NonEmpty<Box2D<T, U>>69     pub fn union(&self, other: &NonEmpty<Box2D<T, U>>) -> NonEmpty<Box2D<T, U>> {
70         NonEmpty(Box2D {
71             min: point2(
72                 min(self.min.x, other.min.x),
73                 min(self.min.y, other.min.y),
74             ),
75             max: point2(
76                 max(self.max.x, other.max.x),
77                 max(self.max.y, other.max.y),
78             ),
79         })
80     }
81 
82     /// Returns true if this box contains the interior of the other box.
83     #[inline]
contains_box(&self, other: &Self) -> bool84     pub fn contains_box(&self, other: &Self) -> bool {
85         self.min.x <= other.min.x
86             && other.max.x <= self.max.x
87             && self.min.y <= other.min.y
88             && other.max.y <= self.max.y
89     }
90 }
91 
92 impl<T, U> NonEmpty<Box2D<T, U>>
93 where
94     T: Copy + Add<T, Output = T>,
95 {
96     #[inline]
translate(&self, by: Vector2D<T, U>) -> Self97     pub fn translate(&self, by: Vector2D<T, U>) -> Self {
98         NonEmpty(self.0.translate(by))
99     }
100 }
101 
102 impl<T, U> NonEmpty<Box3D<T, U>>
103 where
104     T: Copy + PartialOrd,
105 {
106     #[inline]
union(&self, other: &NonEmpty<Box3D<T, U>>) -> NonEmpty<Box3D<T, U>>107     pub fn union(&self, other: &NonEmpty<Box3D<T, U>>) -> NonEmpty<Box3D<T, U>> {
108         NonEmpty(Box3D {
109             min: point3(
110                 min(self.min.x, other.min.x),
111                 min(self.min.y, other.min.y),
112                 min(self.min.z, other.min.z),
113             ),
114             max: point3(
115                 max(self.max.x, other.max.x),
116                 max(self.max.y, other.max.y),
117                 max(self.max.z, other.max.z),
118             ),
119         })
120     }
121 
122     /// Returns true if this box contains the interior of the other box.
123     #[inline]
contains_box(&self, other: &Self) -> bool124     pub fn contains_box(&self, other: &Self) -> bool {
125         self.min.x <= other.min.x
126             && other.max.x <= self.max.x
127             && self.min.y <= other.min.y
128             && other.max.y <= self.max.y
129             && self.min.z <= other.min.z
130             && other.max.z <= self.max.z
131     }
132 }
133 
134 impl<T, U> NonEmpty<Box3D<T, U>>
135 where
136     T: Copy + Add<T, Output = T>,
137 {
138     #[inline]
translate(&self, by: Vector3D<T, U>) -> Self139     pub fn translate(&self, by: Vector3D<T, U>) -> Self {
140         NonEmpty(self.0.translate(by))
141     }
142 }
143 
144 #[test]
empty_nonempty()145 fn empty_nonempty() {
146     use default;
147 
148     // zero-width
149     let box1: default::Box2D<i32> = Box2D {
150         min: point2(-10, 2),
151         max: point2(-10, 12),
152     };
153     // zero-height
154     let box2: default::Box2D<i32> = Box2D {
155         min: point2(0, 11),
156         max: point2(2, 11),
157     };
158     // negative width
159     let box3: default::Box2D<i32> = Box2D {
160         min: point2(1, 11),
161         max: point2(0, 12),
162     };
163     // negative height
164     let box4: default::Box2D<i32> = Box2D {
165         min: point2(0, 11),
166         max: point2(5, 10),
167     };
168 
169     assert!(box1.to_non_empty().is_none());
170     assert!(box2.to_non_empty().is_none());
171     assert!(box3.to_non_empty().is_none());
172     assert!(box4.to_non_empty().is_none());
173 }
174 
175 #[test]
nonempty_union()176 fn nonempty_union() {
177     use default;
178 
179     let box1: default::Box2D<i32> = Box2D {
180         min: point2(-10, 2),
181         max: point2(15, 12),
182     };
183     let box2 = Box2D {
184         min: point2(-2, -5),
185         max: point2(10, 5),
186     };
187 
188     assert_eq!(box1.union(&box2), *box1.to_non_empty().unwrap().union(&box2.to_non_empty().unwrap()));
189 
190     let box3: default::Box3D<i32> = Box3D {
191         min: point3(1, -10, 2),
192         max: point3(6, 15, 12),
193     };
194     let box4 = Box3D {
195         min: point3(0, -2, -5),
196         max: point3(7, 10, 5),
197     };
198 
199     assert_eq!(box3.union(&box4), *box3.to_non_empty().unwrap().union(&box4.to_non_empty().unwrap()));
200 
201     let rect1: default::Rect<i32> = Rect {
202         origin: point2(1, 2),
203         size: size2(3, 4),
204     };
205     let rect2 = Rect {
206         origin: point2(-1, 5),
207         size: size2(1, 10),
208     };
209 
210     assert_eq!(rect1.union(&rect2), *rect1.to_non_empty().unwrap().union(&rect2.to_non_empty().unwrap()));
211 }
212 
213 #[test]
nonempty_contains()214 fn nonempty_contains() {
215     use default;
216     use {vec2, vec3};
217 
218     let r: NonEmpty<default::Rect<i32>> = Rect {
219         origin: point2(-20, 15),
220         size: size2(100, 200),
221     }.to_non_empty().unwrap();
222 
223     assert!(r.contains_rect(&r));
224     assert!(!r.contains_rect(&r.translate(vec2(1, 0))));
225     assert!(!r.contains_rect(&r.translate(vec2(-1, 0))));
226     assert!(!r.contains_rect(&r.translate(vec2(0, 1))));
227     assert!(!r.contains_rect(&r.translate(vec2(0, -1))));
228 
229     let b: NonEmpty<default::Box2D<i32>> = Box2D {
230         min: point2(-10, 5),
231         max: point2(30, 100),
232     }.to_non_empty().unwrap();
233 
234     assert!(b.contains_box(&b));
235     assert!(!b.contains_box(&b.translate(vec2(1, 0))));
236     assert!(!b.contains_box(&b.translate(vec2(-1, 0))));
237     assert!(!b.contains_box(&b.translate(vec2(0, 1))));
238     assert!(!b.contains_box(&b.translate(vec2(0, -1))));
239 
240     let b: NonEmpty<default::Box3D<i32>> = Box3D {
241         min: point3(-1, -10, 5),
242         max: point3(10, 30, 100),
243     }.to_non_empty().unwrap();
244 
245     assert!(b.contains_box(&b));
246     assert!(!b.contains_box(&b.translate(vec3(0, 1, 0))));
247     assert!(!b.contains_box(&b.translate(vec3(0, -1, 0))));
248     assert!(!b.contains_box(&b.translate(vec3(0, 0, 1))));
249     assert!(!b.contains_box(&b.translate(vec3(0, 0, -1))));
250     assert!(!b.contains_box(&b.translate(vec3(1, 1, 0))));
251     assert!(!b.contains_box(&b.translate(vec3(1, -1, 0))));
252     assert!(!b.contains_box(&b.translate(vec3(1, 0, 1))));
253     assert!(!b.contains_box(&b.translate(vec3(1, 0, -1))));
254     assert!(!b.contains_box(&b.translate(vec3(-1, 1, 0))));
255     assert!(!b.contains_box(&b.translate(vec3(-1, -1, 0))));
256     assert!(!b.contains_box(&b.translate(vec3(-1, 0, 1))));
257     assert!(!b.contains_box(&b.translate(vec3(-1, 0, -1))));
258 }
259