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