1use std::ops::{Add, AddAssign, Neg, Sub, SubAssign};
2
3use crate::Float;
4
5#[derive(Clone, Copy, Debug, Default, PartialEq)]
6pub struct Point<T> {
7 pub x: T,
8 pub y: T,
9}
10
11#[derive(Clone, Copy, Debug, Default, PartialEq)]
12pub struct Size<T> {
13 pub width: T,
14 pub height: T,
15}
16
17#[derive(Clone, Copy, Debug, Default, PartialEq)]
18pub struct Rect<T> {
19 pub point: Point<T>,
20 pub size: Size<T>,
21}
22
23pub type FPoint = Point<Float>;
24pub type FSize = Size<Float>;
25pub type FRect = Rect<Float>;
26
27pub type IPoint = Point<i32>;
28pub type ISize = Size<i32>;
29pub type IRect = Rect<i32>;
30
31impl<T> Point<T> {
32 pub fn new(x: T, y: T) -> Self {
33 Self {
34 x,
35 y,
36 }
37 }
38}
39
40impl<T> Size<T> {
41 pub fn new(width: T, height: T) -> Self {
42 Self {
43 width,
44 height,
45 }
46 }
47}
48
49impl<T> Rect<T>
50where
51 T: Add<Output = T> + AddAssign + Sub<Output = T> + SubAssign + Neg<Output = T> + Copy + Default + PartialOrd + PartialEq,
52{
53 pub fn new(x: T, y: T, width: T, height: T) -> Self {
54 Self {
55 point: Point {
56 x,
57 y,
58 },
59 size: Size {
60 width,
61 height,
62 },
63 }
64 }
65
66 pub fn from_bounds(left: T, top: T, right: T, bottom: T) -> Self {
67 Self {
68 point: Point {
69 x: left,
70 y: top,
71 },
72 size: Size {
73 width: right - left,
74 height: bottom - top,
75 },
76 }
77 }
78
79 pub fn standardize(&self) {
80 let mut rect = *self;
81 if rect.size.width < T::default() {
82 rect.point.x += rect.size.width;
83 rect.size.width = -rect.size.width;
84 }
85 if rect.size.height < T::default() {
86 rect.point.y += rect.size.height;
87 rect.size.height = -rect.size.height;
88 }
89 }
90
91 pub fn is_empty(&self) -> bool {
92 self.size.width <= T::default() || self.size.height <= T::default()
93 }
94
95 pub fn is_null(&self) -> bool {
96 self.point.x == T::default() && self.point.y == T::default() && self.size.width == T::default() && self.size.height == T::default()
97 }
98
99 pub fn offset(&self, dx: T, dy: T) -> Rect<T> {
100 let mut rect = *self;
101 rect.point.x += dx;
102 rect.point.y += dy;
103 rect
104 }
105
106 pub fn inflate(&self, dx: T, dy: T) -> Rect<T> {
107 let mut rect = *self;
108 rect.point.x -= dx;
109 rect.point.y -= dy;
110 rect.size.width += dx + dx;
111 rect.size.height += dy + dy;
112 rect
113 }
114
115 pub fn deflate(&self, dx: T, dy: T) -> Rect<T> {
116 let mut rect = *self;
117 rect.point.x += dx;
118 rect.point.y += dy;
119 rect.size.width -= dx + dx;
120 rect.size.height -= dy + dy;
121 rect
122 }
123
124 pub fn contains_point(&self, point: Point<T>) -> bool {
125 point.x >= self.point.x && point.x < self.point.x + self.size.width && point.y >= self.point.y && point.y < self.point.y + self.size.height
126 }
127
128 pub fn contains_rect(&self, rect: Rect<T>) -> bool {
129 self.point.x <= rect.point.x &&
130 self.point.y <= rect.point.y &&
131 self.point.x + self.size.width >= rect.point.x + rect.size.width &&
132 self.point.y + self.size.height >= rect.point.y + rect.size.height
133 }
134
135 pub fn intersects(&self, rect: Rect<T>) -> bool {
136 self.point.x < rect.point.x + rect.size.width &&
137 rect.point.x < self.point.x + self.size.width &&
138 self.point.y < rect.point.y + rect.size.height &&
139 rect.point.y < self.point.y + self.size.height
140 }
141
142 pub fn union(&self, rect: Rect<T>) -> Option<Rect<T>> {
143 let left = if self.point.x < rect.point.x {
144 self.point.x
145 } else {
146 rect.point.x
147 };
148 let top = if self.point.y < rect.point.y {
149 self.point.y
150 } else {
151 rect.point.y
152 };
153 let right = if self.point.x + self.size.width > rect.point.x + rect.size.width {
154 self.point.x + self.size.width
155 } else {
156 rect.point.x + rect.size.width
157 };
158 let bottom = if self.point.y + self.size.height > rect.point.y + rect.size.height {
159 self.point.y + self.size.height
160 } else {
161 rect.point.y + rect.size.height
162 };
163 if left > right || top > bottom {
164 None
165 } else {
166 Some(Rect::from_bounds(left, top, right, bottom))
167 }
168 }
169
170 pub fn intersection(&self, rect: Rect<T>) -> Option<Rect<T>> {
171 let left = if self.point.x > rect.point.x {
172 self.point.x
173 } else {
174 rect.point.x
175 };
176 let top = if self.point.y > rect.point.y {
177 self.point.y
178 } else {
179 rect.point.y
180 };
181 let right = if self.point.x + self.size.width < rect.point.x + rect.size.width {
182 self.point.x + self.size.width
183 } else {
184 rect.point.x + rect.size.width
185 };
186 let bottom = if self.point.y + self.size.height < rect.point.y + rect.size.height {
187 self.point.y + self.size.height
188 } else {
189 rect.point.y + rect.size.height
190 };
191 if left > right || top > bottom {
192 None
193 } else {
194 Some(Rect::from_bounds(left, top, right, bottom))
195 }
196 }
197}
198
199impl From<IPoint> for (i32, i32) {
200 fn from(point: IPoint) -> Self {
201 (point.x, point.y)
202 }
203}
204
205impl From<FPoint> for (Float, Float) {
206 fn from(point: FPoint) -> Self {
207 (point.x, point.y)
208 }
209}
210
211impl From<IPoint> for FPoint {
212 fn from(point: IPoint) -> Self {
213 Self {
214 x: point.x as Float,
215 y: point.y as Float,
216 }
217 }
218}
219
220impl From<FPoint> for IPoint {
221 fn from(point: FPoint) -> Self {
222 Self {
223 x: point.x as i32,
224 y: point.y as i32,
225 }
226 }
227}
228
229impl From<ISize> for (i32, i32) {
230 fn from(size: ISize) -> Self {
231 (size.width, size.height)
232 }
233}
234
235impl From<FSize> for (Float, Float) {
236 fn from(size: FSize) -> Self {
237 (size.width, size.height)
238 }
239}
240
241impl From<ISize> for FSize {
242 fn from(size: ISize) -> Self {
243 Self {
244 width: size.width as Float,
245 height: size.height as Float,
246 }
247 }
248}
249
250impl From<FSize> for ISize {
251 fn from(size: FSize) -> Self {
252 Self {
253 width: size.width as i32,
254 height: size.height as i32,
255 }
256 }
257}
258
259impl From<IRect> for (i32, i32, i32, i32) {
260 fn from(rect: IRect) -> Self {
261 (rect.point.x, rect.point.y, rect.size.width, rect.size.height)
262 }
263}
264
265impl From<FRect> for (Float, Float, Float, Float) {
266 fn from(rect: FRect) -> Self {
267 (rect.point.x, rect.point.y, rect.size.width, rect.size.height)
268 }
269}
270
271impl From<IRect> for FRect {
272 fn from(rect: IRect) -> Self {
273 Self {
274 point: FPoint {
275 x: rect.point.x as Float,
276 y: rect.point.y as Float,
277 },
278 size: FSize {
279 width: rect.size.width as Float,
280 height: rect.size.height as Float,
281 },
282 }
283 }
284}
285
286impl From<FRect> for IRect {
287 fn from(rect: FRect) -> Self {
288 Self {
289 point: IPoint {
290 x: rect.point.x as i32,
291 y: rect.point.y as i32,
292 },
293 size: ISize {
294 width: rect.size.width as i32,
295 height: rect.size.height as i32,
296 },
297 }
298 }
299}