1use yog_data::Schema;
4
5use crate::math::Vec2;
6
7#[derive(Schema, Debug, Clone, Copy, PartialEq, Default)]
10pub struct Rect {
11 pub x: f32,
12 pub y: f32,
13 pub w: f32,
14 pub h: f32,
15}
16
17impl Rect {
18 pub const fn new(x: f32, y: f32, w: f32, h: f32) -> Rect {
19 Rect { x, y, w, h }
20 }
21
22 pub const fn from_edges(x0: f32, y0: f32, x1: f32, y1: f32) -> Rect {
24 Rect {
25 x: x0,
26 y: y0,
27 w: x1 - x0,
28 h: y1 - y0,
29 }
30 }
31
32 pub fn from_corners(a: Vec2, b: Vec2) -> Rect {
34 Rect {
35 x: a.x.min(b.x),
36 y: a.y.min(b.y),
37 w: (a.x - b.x).abs(),
38 h: (a.y - b.y).abs(),
39 }
40 }
41
42 pub fn right(&self) -> f32 {
43 self.x + self.w
44 }
45
46 pub fn bottom(&self) -> f32 {
47 self.y + self.h
48 }
49
50 pub fn center(&self) -> Vec2 {
51 Vec2::new(self.x + self.w / 2.0, self.y + self.h / 2.0)
52 }
53
54 pub fn contains(&self, p: Vec2) -> bool {
55 p.x >= self.x && p.y >= self.y && p.x < self.right() && p.y < self.bottom()
56 }
57
58 pub fn inset(&self, pad: [f32; 4]) -> Rect {
61 Rect {
62 x: self.x + pad[3],
63 y: self.y + pad[0],
64 w: (self.w - pad[1] - pad[3]).max(0.0),
65 h: (self.h - pad[0] - pad[2]).max(0.0),
66 }
67 }
68
69 pub fn outset(&self, r: f32) -> Rect {
71 Rect {
72 x: self.x - r,
73 y: self.y - r,
74 w: self.w + 2.0 * r,
75 h: self.h + 2.0 * r,
76 }
77 }
78
79 pub fn translate(&self, d: Vec2) -> Rect {
80 Rect {
81 x: self.x + d.x,
82 y: self.y + d.y,
83 ..*self
84 }
85 }
86
87 pub fn scale(&self, s: f32) -> Rect {
89 Rect::from_corners(
90 Vec2::new(self.x * s, self.y * s),
91 Vec2::new(self.right() * s, self.bottom() * s),
92 )
93 }
94
95 pub fn intersect(&self, o: &Rect) -> Option<Rect> {
97 let (x0, y0) = (self.x.max(o.x), self.y.max(o.y));
98 let (x1, y1) = (self.right().min(o.right()), self.bottom().min(o.bottom()));
99 (x1 > x0 && y1 > y0).then_some(Rect {
100 x: x0,
101 y: y0,
102 w: x1 - x0,
103 h: y1 - y0,
104 })
105 }
106
107 pub fn union(&self, o: &Rect) -> Rect {
108 let (x, y) = (self.x.min(o.x), self.y.min(o.y));
109 Rect {
110 x,
111 y,
112 w: self.right().max(o.right()) - x,
113 h: self.bottom().max(o.bottom()) - y,
114 }
115 }
116
117 pub fn around(points: impl IntoIterator<Item = Vec2>) -> Option<Rect> {
119 let mut it = points.into_iter();
120 let first = it.next()?;
121 let (lo, hi) = it.fold((first, first), |(lo, hi), p| {
122 (
123 Vec2::new(lo.x.min(p.x), lo.y.min(p.y)),
124 Vec2::new(hi.x.max(p.x), hi.y.max(p.y)),
125 )
126 });
127 Some(Rect::from_corners(lo, hi))
128 }
129}