1#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
6pub struct Point {
7 pub x: i32,
8 pub y: i32,
9}
10
11impl Point {
12 pub const ZERO: Point = Point { x: 0, y: 0 };
13
14 pub const fn new(x: i32, y: i32) -> Self {
15 Point { x, y }
16 }
17
18 pub const fn translate(self, dx: i32, dy: i32) -> Self {
19 Point::new(self.x + dx, self.y + dy)
20 }
21}
22
23#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
24pub struct Size {
25 pub w: i32,
26 pub h: i32,
27}
28
29impl Size {
30 pub const ZERO: Size = Size { w: 0, h: 0 };
31
32 pub const fn new(w: i32, h: i32) -> Self {
33 Size { w, h }
34 }
35
36 pub const fn is_empty(self) -> bool {
37 self.w <= 0 || self.h <= 0
38 }
39
40 pub const fn area(self) -> i64 {
41 if self.is_empty() {
42 0
43 } else {
44 self.w as i64 * self.h as i64
45 }
46 }
47}
48
49#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
54pub struct PixelSize {
55 pub w: u16,
56 pub h: u16,
57}
58
59impl PixelSize {
60 pub const fn new(w: u16, h: u16) -> Self {
61 PixelSize { w, h }
62 }
63
64 pub const fn is_empty(self) -> bool {
65 self.w == 0 || self.h == 0
66 }
67}
68
69#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
70pub struct Rect {
71 pub x: i32,
72 pub y: i32,
73 pub w: i32,
74 pub h: i32,
75}
76
77impl Rect {
78 pub const ZERO: Rect = Rect {
79 x: 0,
80 y: 0,
81 w: 0,
82 h: 0,
83 };
84
85 pub const fn new(x: i32, y: i32, w: i32, h: i32) -> Self {
86 Rect { x, y, w, h }
87 }
88
89 pub const fn from_size(size: Size) -> Self {
90 Rect::new(0, 0, size.w, size.h)
91 }
92
93 pub const fn origin(self) -> Point {
94 Point::new(self.x, self.y)
95 }
96
97 pub const fn size(self) -> Size {
98 Size::new(self.w, self.h)
99 }
100
101 pub const fn right(self) -> i32 {
102 self.x + self.w
103 }
104
105 pub const fn bottom(self) -> i32 {
106 self.y + self.h
107 }
108
109 pub const fn is_empty(self) -> bool {
110 self.w <= 0 || self.h <= 0
111 }
112
113 pub const fn area(self) -> i64 {
114 self.size().area()
115 }
116
117 pub const fn contains(self, p: Point) -> bool {
118 p.x >= self.x && p.y >= self.y && p.x < self.right() && p.y < self.bottom()
119 }
120
121 pub fn intersect(self, other: Rect) -> Rect {
122 let x = self.x.max(other.x);
123 let y = self.y.max(other.y);
124 let r = self.right().min(other.right());
125 let b = self.bottom().min(other.bottom());
126 if r <= x || b <= y {
127 Rect::ZERO
128 } else {
129 Rect::new(x, y, r - x, b - y)
130 }
131 }
132
133 pub fn intersects(self, other: Rect) -> bool {
134 !self.intersect(other).is_empty()
135 }
136
137 pub fn union(self, other: Rect) -> Rect {
139 if self.is_empty() {
140 return other;
141 }
142 if other.is_empty() {
143 return self;
144 }
145 let x = self.x.min(other.x);
146 let y = self.y.min(other.y);
147 let r = self.right().max(other.right());
148 let b = self.bottom().max(other.bottom());
149 Rect::new(x, y, r - x, b - y)
150 }
151
152 pub const fn translate(self, dx: i32, dy: i32) -> Rect {
153 Rect::new(self.x + dx, self.y + dy, self.w, self.h)
154 }
155
156 pub fn inset(self, n: i32) -> Rect {
158 let w = (self.w - 2 * n).max(0);
159 let h = (self.h - 2 * n).max(0);
160 if w == 0 || h == 0 {
161 Rect::new(self.x + n, self.y + n, 0, 0)
162 } else {
163 Rect::new(self.x + n, self.y + n, w, h)
164 }
165 }
166}
167
168#[cfg(test)]
169mod tests {
170 use super::*;
171
172 #[test]
173 fn intersect_and_union() {
174 let a = Rect::new(0, 0, 10, 10);
175 let b = Rect::new(5, 5, 10, 10);
176 assert_eq!(a.intersect(b), Rect::new(5, 5, 5, 5));
177 assert_eq!(a.union(b), Rect::new(0, 0, 15, 15));
178 assert!(a.intersect(Rect::new(20, 20, 5, 5)).is_empty());
179 assert_eq!(Rect::ZERO.union(a), a);
180 }
181
182 #[test]
183 fn contains_edges() {
184 let r = Rect::new(1, 1, 2, 2);
185 assert!(r.contains(Point::new(1, 1)));
186 assert!(r.contains(Point::new(2, 2)));
187 assert!(!r.contains(Point::new(3, 3)));
188 }
189}