1use core::fmt::{Display, Formatter};
2use core::ops::{Add, Sub};
3
4#[derive(Copy, Clone, PartialEq, Debug)]
5pub struct Size {
6 pub w: i32,
7 pub h: i32,
8}
9
10impl Size {
11 fn empty() -> Size {
12 Size { w: -99, h: -99 }
13 }
14}
15
16impl Size {
17 pub fn new(w: i32, h: i32) -> Size {
18 Size { w, h }
19 }
20 pub fn sub(&self, b: &Insets) -> Size {
21 Size {
22 w: self.w - b.left - b.right,
23 h: self.h - b.top - b.bottom,
24 }
25 }
26 pub fn add(&self, b: &Insets) -> Size {
27 Size {
28 w: self.w + b.left + b.right,
29 h: self.h + b.top + b.bottom,
30 }
31 }
32}
33impl Display for Size {
34 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
35 write!(f, "{}x{}", self.w, self.h)
36 }
37}
38impl Add<Size> for Size {
39 type Output = Size;
40
41 fn add(self, rhs: Size) -> Self::Output {
42 Self {
43 w: self.w + rhs.w,
44 h: self.h + rhs.h,
45 }
46 }
47}
48impl Add<Insets> for Size {
49 type Output = Size;
50
51 fn add(self, rhs: Insets) -> Self::Output {
52 Self {
53 w: self.w + rhs.left + rhs.right,
54 h: self.h + rhs.top + rhs.bottom,
55 }
56 }
57}
58impl Add<&Insets> for Size {
59 type Output = Size;
60
61 fn add(self, rhs: &Insets) -> Self::Output {
62 Self {
63 w: self.w + rhs.left + rhs.right,
64 h: self.h + rhs.top + rhs.bottom,
65 }
66 }
67}
68impl Sub<Insets> for Size {
69 type Output = Self;
70
71 fn sub(self, rhs: Insets) -> Self::Output {
72 Size {
73 w: self.w - rhs.left - rhs.right,
74 h: self.h - rhs.top - rhs.bottom,
75 }
76 }
77}
78
79#[derive(Copy, Clone, PartialEq, Debug, Default)]
80pub struct Insets {
81 pub left: i32,
82 pub right: i32,
83 pub top: i32,
84 pub bottom: i32,
85}
86
87impl Insets {
88 pub fn new(top: i32, right: i32, bottom: i32, left: i32) -> Insets {
89 Insets {
90 top,
91 right,
92 bottom,
93 left,
94 }
95 }
96 pub fn new_same(size: i32) -> Insets {
97 Insets {
98 top: size,
99 bottom: size,
100 left: size,
101 right: size,
102 }
103 }
104}
105
106#[derive(Copy, Clone, PartialEq, Debug)]
107pub struct Point {
108 pub x: i32,
109 pub y: i32,
110}
111
112impl Point {
113 pub(crate) fn negate(&self) -> Point {
114 Point {
115 x: -self.x,
116 y: -self.y,
117 }
118 }
119}
120
121impl Point {
122 pub(crate) fn subtract(&self, p0: &Point) -> Point {
123 Point {
124 x: self.x - p0.x,
125 y: self.y - p0.y,
126 }
127 }
128}
129
130impl Point {
131 pub fn new(x: i32, y: i32) -> Point {
132 Point { x, y }
133 }
134 pub fn zero() -> Point {
135 Point::new(0, 0)
136 }
137}
138impl Add<Point> for Point {
139 type Output = Point;
140
141 fn add(self, rhs: Point) -> Self::Output {
142 Point {
143 x: self.x + rhs.x,
144 y: self.y + rhs.y,
145 }
146 }
147}
148impl Sub<Point> for Point {
149 type Output = Point;
150
151 fn sub(self, rhs: Point) -> Self::Output {
152 Point {
153 x: self.x - rhs.x,
154 y: self.y - rhs.y,
155 }
156 }
157}
158impl Display for Point {
159 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
160 write!(f, "{},{}", self.x, self.y)
161 }
162}
163
164#[derive(Copy, Clone, Debug, PartialEq)]
165pub struct Bounds {
166 pub position: Point,
167 pub size: Size,
168}
169
170impl Bounds {
171 pub(crate) fn x(&self) -> i32 {
172 self.position.x
173 }
174 pub(crate) fn y(&self) -> i32 {
175 self.position.y
176 }
177 pub fn w(&self) -> i32 {
178 self.size.w
179 }
180 pub fn h(&self) -> i32 {
181 self.size.h
182 }
183}
184
185impl Bounds {
186 pub(crate) fn contract(&self, i: i32) -> Bounds {
187 Bounds {
188 position: Point {
189 x: self.position.x + i,
190 y: self.position.y + i,
191 },
192 size: Size {
193 w: self.size.w - i - i,
194 h: self.size.h - i - i,
195 },
196 }
197 }
198}
199
200impl Bounds {
201 pub fn new(x: i32, y: i32, w: i32, h: i32) -> Bounds {
202 Bounds {
203 position: Point::new(x, y),
204 size: Size::new(w, h),
205 }
206 }
207 pub fn new_from(position: Point, size: Size) -> Bounds {
208 Bounds { position, size }
209 }
210}
211impl Default for Bounds {
212 fn default() -> Self {
213 Bounds::new(0, 0, 100, 100)
214 }
215}
216impl Add<Point> for Bounds {
217 type Output = Bounds;
218
219 fn add(self, rhs: Point) -> Self::Output {
220 Bounds {
221 position: self.position + rhs,
222 size: self.size,
223 }
224 }
225}
226impl Sub<Point> for Bounds {
227 type Output = Bounds;
228
229 fn sub(self, rhs: Point) -> Self::Output {
230 Bounds {
231 position: self.position - rhs,
232 size: self.size,
233 }
234 }
235}
236impl Add<Insets> for Bounds {
237 type Output = Bounds;
238
239 fn add(self, rhs: Insets) -> Self::Output {
240 Bounds {
241 position: Point {
242 x: self.position.x - rhs.left,
243 y: self.position.y - rhs.top,
244 },
245 size: Size {
246 w: self.size.w + rhs.left + rhs.right,
247 h: self.size.h + rhs.top + rhs.bottom,
248 },
249 }
250 }
251}
252impl Sub<Insets> for Bounds {
253 type Output = Bounds;
254
255 fn sub(self, rhs: Insets) -> Self::Output {
256 Bounds {
257 position: Point {
258 x: self.position.x + rhs.left,
259 y: self.position.y + rhs.top,
260 },
261 size: Size {
262 w: self.size.w - rhs.left - rhs.right,
263 h: self.size.h - rhs.top - rhs.bottom,
264 },
265 }
266 }
267}
268impl Display for Bounds {
269 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
270 write!(
271 f,
272 "{},{} {}x{}",
273 self.position.x, self.position.y, self.size.w, self.size.h
274 )
275 }
276}
277impl Bounds {
278 pub fn union(&self, b: Bounds) -> Bounds {
279 if self.is_empty() {
280 return b;
281 }
282 if b.is_empty() {
283 return *self;
284 }
285 Bounds::from_xyxy2(
286 self.position.x.min(b.position.x),
287 self.position.y.min(b.position.y),
288 self.x2().max(b.x2()),
289 self.y2().max(b.y2()),
290 )
291 }
292 pub(crate) fn center(&self) -> Point {
293 Point::new(
294 self.position.x + self.size.w / 2,
295 self.position.y + self.size.h / 2,
296 )
297 }
298 fn from_xyxy2(x: i32, y: i32, x2: i32, y2: i32) -> Bounds {
299 Bounds {
300 position: Point::new(x, y),
301 size: Size::new(x2 - x, y2 - y),
302 }
303 }
304 pub fn x2(&self) -> i32 {
305 self.position.x + self.size.w
306 }
307 pub fn y2(&self) -> i32 {
308 self.position.y + self.size.h
309 }
310 pub fn center_at(&self, x: i32, y: i32) -> Bounds {
311 Bounds {
312 position: Point::new(x - self.size.w / 2, y - self.size.h / 2),
313 size: self.size,
314 }
315 }
316}
317
318impl Bounds {
319 pub fn new_empty() -> Bounds {
320 Bounds {
321 position: Point::zero(),
322 size: Size::empty(),
323 }
324 }
325}
326
327impl Bounds {
328 pub fn is_empty(&self) -> bool {
329 self.size.w < 1 || self.size.h < 1
330 }
331 pub fn contains(&self, pt: &Point) -> bool {
332 if self.position.x <= pt.x && self.position.y <= pt.y {
333 if self.position.x + self.size.w > pt.x && self.position.y + self.size.h > pt.y {
334 return true;
335 }
336 }
337 false
338 }
339}
340
341#[cfg(test)]
342mod tests {
343 use crate::geom::{Bounds, Insets, Point, Size};
344 use alloc::format;
345
346 #[test]
347 fn points() {
348 let p1 = Point::new(20, 30);
349 let p2 = Point::new(40, 50);
350 assert_eq!(p1 + p2, Point::new(60, 80));
351 assert_eq!(p1 - p2, Point::new(-20, -20));
352 assert_eq!(format!("{}", Point::new(20, 30)), "20,30");
353 }
354 #[test]
355 fn sizes() {
356 let a = Size::new(10, 10);
357 let b = Size::new(10, 10);
358 let c = Size::new(20, 20);
359 assert_eq!(a + b, c);
360 let d = Insets::new_same(10);
361 assert_eq!(a + d, Size::new(30, 30));
362 assert_eq!(format!("{}", Size::new(10, 20)), "10x20");
363 }
364 #[test]
365 fn bounds() {
366 let a = Bounds::new(10, 20, 30, 40);
367 let pt = Point::new(1, 1);
368 assert_eq!(format!("{}", a), "10,20 30x40");
369 assert_eq!(a + pt, Bounds::new(11, 21, 30, 40));
370 assert_eq!(a - pt, Bounds::new(9, 19, 30, 40));
371 assert_eq!(
372 Bounds::new_from(Point::new(5, 6), Size::new(7, 8)),
373 Bounds::new(5, 6, 7, 8)
374 );
375 }
376
377 #[test]
378 fn test_geometry() {
379 let bounds = Bounds::new(0, 0, 100, 100);
380 assert_eq!(bounds.contains(&Point::new(10, 10)), true);
381 assert_eq!(bounds.contains(&Point::new(-1, -1)), false);
382
383 let b2 = Bounds::new(140, 180, 80, 30);
384 let b3 = Bounds::new(140, 180, 80, 30);
385 assert_eq!(b2.union(b3), b2.clone());
387 }
388 #[test]
389 fn test_point() {
390 let pt1 = Point::new(8, 9);
391 let pt2 = Point::new(10, 11);
392 let pt3 = pt1 + pt2;
393 assert_eq!(pt3, Point::new(18, 20));
394 let bounds = Bounds::new(1, 2, 3, 4);
395 assert_eq!(bounds.position, Point::new(1, 2));
396
397 let pt4 = pt1 - pt2;
398 assert_eq!(pt4, Point::new(-2, -2));
399 }
400}