1use crate::{error::Result, prelude::*};
30use num_traits::{AsPrimitive, Bounded, NumCast};
31#[cfg(feature = "serde")]
32use serde::{Deserialize, Serialize};
33use std::ops::{Add, Sub};
34
35#[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Hash)]
42#[repr(transparent)]
43#[must_use]
44#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
45pub struct Rect<T = i32>(pub(crate) [T; 4]);
46
47#[macro_export]
65macro_rules! rect {
66 ($p1:expr, $p2:expr$(,)?) => {
67 $crate::prelude::Rect::with_points($p1, $p2)
68 };
69 ($p:expr, $width:expr, $height:expr$(,)?) => {
70 $crate::prelude::Rect::with_position($p, $width, $height)
71 };
72 ($x:expr, $y:expr, $width:expr, $height:expr$(,)?) => {
73 $crate::prelude::Rect::new($x, $y, $width, $height)
74 };
75}
76
77#[macro_export]
95macro_rules! square {
96 ($p:expr, $size:expr$(,)?) => {{
97 $crate::prelude::Rect::square_with_position($p, $size)
98 }};
99 ($x:expr, $y:expr, $size:expr$(,)?) => {
100 $crate::prelude::Rect::square($x, $y, $size)
101 };
102}
103
104impl<T> Rect<T> {
105 pub const fn new(x: T, y: T, width: T, height: T) -> Self {
107 Self([x, y, width, height])
108 }
109
110 pub fn square(x: T, y: T, size: T) -> Self
112 where
113 T: Copy,
114 {
115 Self::new(x, y, size, size)
116 }
117}
118
119impl<T: Copy> Rect<T> {
120 #[inline]
130 pub fn coords(&self) -> [T; 4] {
131 self.0
132 }
133
134 #[inline]
147 pub fn coords_mut(&mut self) -> &mut [T; 4] {
148 &mut self.0
149 }
150
151 #[inline]
153 pub fn x(&self) -> T {
154 self.0[0]
155 }
156
157 #[inline]
159 pub fn set_x(&mut self, x: T) {
160 self.0[0] = x;
161 }
162
163 #[inline]
165 pub fn y(&self) -> T {
166 self.0[1]
167 }
168
169 #[inline]
171 pub fn set_y(&mut self, y: T) {
172 self.0[1] = y;
173 }
174
175 #[inline]
177 pub fn width(&self) -> T {
178 self.0[2]
179 }
180
181 #[inline]
183 pub fn set_width(&mut self, width: T) {
184 self.0[2] = width;
185 }
186
187 #[inline]
189 pub fn height(&self) -> T {
190 self.0[3]
191 }
192
193 #[inline]
195 pub fn set_height(&mut self, height: T) {
196 self.0[3] = height;
197 }
198}
199
200impl<T: Num> Rect<T> {
201 pub fn with_position<P: Into<Point<T>>>(p: P, width: T, height: T) -> Self {
203 let p = p.into();
204 Self::new(p.x(), p.y(), width, height)
205 }
206
207 pub fn square_with_position<P: Into<Point<T>>>(p: P, size: T) -> Self {
209 Self::with_position(p, size, size)
210 }
211
212 pub fn with_points<P: Into<Point<T>>>(p1: P, p2: P) -> Self {
226 let p1 = p1.into();
227 let p2 = p2.into();
228 assert!(p2 > p1, "bottom-right point must be greater than top-right",);
229 let width = p2.x() - p1.x();
230 let height = p2.y() - p1.y();
231 Self::new(p1.x(), p1.y(), width, height)
232 }
233
234 pub fn from_center<P: Into<Point<T>>>(p: P, width: T, height: T) -> Self {
244 let p = p.into();
245 let two = T::one() + T::one();
246 Self::new(p.x() - width / two, p.y() - height / two, width, height)
247 }
248
249 pub fn square_from_center<P: Into<Point<T>>>(p: P, size: T) -> Self {
259 let p = p.into();
260 let two = T::one() + T::one();
261 let offset = size / two;
262 Self::new(p.x() - offset, p.y() - offset, size, size)
263 }
264
265 #[inline]
267 pub fn size(&self) -> Point<T> {
268 point!(self.width(), self.height())
269 }
270
271 #[inline]
273 pub fn reposition(&self, x: T, y: T) -> Self {
274 Self::new(x, y, self.width(), self.height())
275 }
276
277 #[inline]
279 pub fn resize(&self, width: T, height: T) -> Self {
280 Self::new(self.x(), self.y(), width, height)
281 }
282
283 #[inline]
285 pub fn offset<P>(&self, offsets: P) -> Self
286 where
287 P: Into<Point<T>>,
288 {
289 let offsets = offsets.into();
290 let mut rect = *self;
291 for i in 0..=1 {
292 rect[i] += offsets[i];
293 }
294 rect
295 }
296
297 #[inline]
299 pub fn offset_size<P>(&self, offsets: P) -> Self
300 where
301 P: Into<Point<T>>,
302 {
303 let offsets = offsets.into();
304 let mut rect = *self;
305 for i in 2..=3 {
306 rect[i] += offsets[i - 2];
307 }
308 rect
309 }
310
311 #[inline]
313 pub fn grow<P>(&self, offsets: P) -> Self
314 where
315 P: Into<Point<T>>,
316 {
317 let offsets = offsets.into();
318 let mut rect = *self;
319 for i in 0..=1 {
320 rect[i] -= offsets[i];
321 }
322 for i in 2..=3 {
323 rect[i] += (T::one() + T::one()) * offsets[i - 2];
324 }
325 rect
326 }
327
328 #[inline]
330 pub fn shrink<P>(&self, offsets: P) -> Self
331 where
332 P: Into<Point<T>>,
333 {
334 let offsets = offsets.into();
335 let mut rect = *self;
336 for i in 0..=1 {
337 rect[i] += offsets[i];
338 }
339 for i in 2..=3 {
340 rect[i] -= (T::one() + T::one()) * offsets[i - 2];
341 }
342 rect
343 }
344
345 #[inline]
355 pub fn to_vec(self) -> Vec<T> {
356 self.0.to_vec()
357 }
358
359 #[inline]
361 pub fn left(&self) -> T {
362 self.x()
363 }
364
365 #[inline]
367 pub fn set_left(&mut self, left: T) {
368 self.set_x(left);
369 }
370
371 #[inline]
373 pub fn right(&self) -> T {
374 self.x() + self.width()
375 }
376
377 #[inline]
379 pub fn set_right(&mut self, right: T) {
380 self.set_x(right - self.width());
381 }
382
383 #[inline]
385 pub fn top(&self) -> T {
386 self.y()
387 }
388
389 #[inline]
391 pub fn set_top(&mut self, top: T) {
392 self.set_y(top);
393 }
394
395 #[inline]
397 pub fn bottom(&self) -> T {
398 self.y() + self.height()
399 }
400
401 #[inline]
403 pub fn set_bottom(&mut self, bottom: T) {
404 self.set_y(bottom - self.height());
405 }
406
407 #[inline]
409 pub fn center(&self) -> Point<T> {
410 let two = T::one() + T::one();
411 point!(
412 self.x() + self.width() / two,
413 self.y() + self.height() / two
414 )
415 }
416
417 #[inline]
419 pub fn top_left(&self) -> Point<T> {
420 point!(self.left(), self.top())
421 }
422
423 #[inline]
425 pub fn top_right(&self) -> Point<T> {
426 point!(self.right(), self.top())
427 }
428
429 #[inline]
431 pub fn bottom_left(&self) -> Point<T> {
432 point!(self.left(), self.bottom())
433 }
434
435 #[inline]
437 pub fn bottom_right(&self) -> Point<T> {
438 point!(self.right(), self.bottom())
439 }
440
441 #[inline]
444 pub fn points(&self) -> [Point<T>; 4] {
445 [
446 self.top_left(),
447 self.top_right(),
448 self.bottom_right(),
449 self.bottom_left(),
450 ]
451 }
452
453 #[inline]
455 pub fn center_on<P: Into<Point<T>>>(&mut self, p: P) {
456 let p = p.into();
457 let two = T::one() + T::one();
458 self.set_x(p.x() - self.width() / two);
459 self.set_y(p.y() - self.height() / two);
460 }
461
462 #[inline]
465 pub fn rotated(&self, angle: f64, center: Option<Point<T>>) -> Self
466 where
467 T: Ord + Bounded + AsPrimitive<f64> + NumCast,
468 {
469 if angle == 0.0 {
470 return *self;
471 }
472
473 let sin_cos = angle.sin_cos();
474 let [cx, cy]: [f64; 2] = center.unwrap_or_else(|| self.center()).as_().coords();
476 let (sin, cos) = sin_cos;
477 let transformed_points = self.points().map(|p| {
478 let [x, y]: [f64; 2] = p.as_().coords();
479 point![
480 NumCast::from(((x - cx).mul_add(cos, cx) - (y - cy) * sin).round())
481 .unwrap_or_else(T::zero),
482 NumCast::from(((y - cy).mul_add(cos, (x - cx).mul_add(sin, cy))).round())
483 .unwrap_or_else(T::zero),
484 ]
485 });
486 let (min_x, min_y) = transformed_points
487 .iter()
488 .fold((T::max_value(), T::max_value()), |(min_x, min_y), point| {
489 (min_x.min(point.x()), min_y.min(point.y()))
490 });
491 let (max_x, max_y) = transformed_points
492 .iter()
493 .fold((T::min_value(), T::min_value()), |(max_x, max_y), point| {
494 (max_x.max(point.x()), max_y.max(point.y()))
495 });
496 Self::with_points([min_x, min_y], [max_x, max_y])
497 }
498}
499
500impl<T: Num> Contains<Point<T>> for Rect<T> {
501 fn contains(&self, p: Point<T>) -> bool {
503 p.x() >= self.left() && p.x() < self.right() && p.y() >= self.top() && p.y() < self.bottom()
504 }
505}
506
507impl<T: Num> Contains<Rect<T>> for Rect<T> {
508 fn contains(&self, rect: Rect<T>) -> bool {
510 rect.left() >= self.left()
511 && rect.right() < self.right()
512 && rect.top() >= self.top()
513 && rect.bottom() < self.bottom()
514 }
515}
516
517impl<T: Float> Intersects<Line<T>> for Rect<T> {
518 type Result = (Point<T>, T);
519
520 fn intersects(&self, line: Line<T>) -> Option<Self::Result> {
523 let left = line.intersects(line_![self.top_left(), self.bottom_left()]);
524 let right = line.intersects(line_![self.top_right(), self.bottom_right()]);
525 let top = line.intersects(line_![self.top_left(), self.top_right()]);
526 let bottom = line.intersects(line_![self.bottom_left(), self.bottom_right()]);
527 [left, right, top, bottom]
528 .iter()
529 .filter_map(|&p| p)
530 .fold(None, |closest, intersection| {
531 let closest_t = closest.map_or_else(T::infinity, |c| c.1);
532 let t = intersection.1;
533 if t < closest_t {
534 Some(intersection)
535 } else {
536 closest
537 }
538 })
539 }
540}
541
542impl<T: Num> Intersects<Rect<T>> for Rect<T> {
543 type Result = ();
545
546 fn intersects(&self, rect: Rect<T>) -> Option<Self::Result> {
548 let tl = self.top_left();
549 let br = self.bottom_right();
550 let otl = rect.top_left();
551 let obr = rect.bottom_right();
552 if tl.x() < obr.x() && br.x() > otl.x() && tl.y() < otl.y() && br.y() > obr.y() {
554 Some(())
555 } else {
556 None
557 }
558 }
559}
560
561impl Draw for Rect<i32> {
562 fn draw(&self, s: &mut PixState) -> Result<()> {
564 s.rect(*self)
565 }
566}
567
568impl<T: Copy> From<[T; 3]> for Rect<T> {
569 #[inline]
571 fn from([x, y, s]: [T; 3]) -> Self {
572 Self([x, y, s, s])
573 }
574}
575
576impl<T: Copy> From<&[T; 3]> for Rect<T> {
577 #[inline]
579 fn from(&[x, y, s]: &[T; 3]) -> Self {
580 Self([x, y, s, s])
581 }
582}
583
584impl Add<Point<i32>> for Rect {
585 type Output = Self;
586 fn add(self, p: Point<i32>) -> Self::Output {
587 self.offset(p)
588 }
589}
590
591impl Sub<Point<i32>> for Rect {
592 type Output = Self;
593 fn sub(self, p: Point<i32>) -> Self::Output {
594 self.offset(-p)
595 }
596}