1use glam::Vec2;
4
5#[derive(Debug, Clone, Copy, PartialEq)]
10pub struct Rect {
11 pub min: Vec2,
13 pub size: Vec2,
15}
16
17impl Rect {
18 #[must_use]
20 pub const fn new(x: f32, y: f32, width: f32, height: f32) -> Self {
21 Self {
22 min: Vec2::new(x, y),
23 size: Vec2::new(width, height),
24 }
25 }
26
27 #[must_use]
29 pub fn from_min_max(min: Vec2, max: Vec2) -> Self {
30 Self {
31 min,
32 size: max - min,
33 }
34 }
35
36 #[must_use]
38 pub fn max(&self) -> Vec2 {
39 self.min + self.size
40 }
41
42 #[must_use]
44 pub fn center(&self) -> Vec2 {
45 self.min + self.size * 0.5
46 }
47
48 #[must_use]
50 pub fn width(&self) -> f32 {
51 self.size.x
52 }
53
54 #[must_use]
56 pub fn height(&self) -> f32 {
57 self.size.y
58 }
59
60 #[must_use]
62 pub fn contains(&self, p: Vec2) -> bool {
63 let max = self.max();
64 p.x >= self.min.x && p.y >= self.min.y && p.x < max.x && p.y < max.y
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 #[test]
73 fn new_constructs_min_and_size() {
74 let r = Rect::new(10.0, 20.0, 30.0, 40.0);
75 assert_eq!(r.min, Vec2::new(10.0, 20.0));
76 assert_eq!(r.size, Vec2::new(30.0, 40.0));
77 }
78
79 #[test]
80 fn max_is_min_plus_size() {
81 let r = Rect::new(0.0, 0.0, 100.0, 50.0);
82 assert_eq!(r.max(), Vec2::new(100.0, 50.0));
83 }
84
85 #[test]
86 fn from_min_max_round_trips() {
87 let min = Vec2::new(5.0, 10.0);
88 let max = Vec2::new(25.0, 40.0);
89 let r = Rect::from_min_max(min, max);
90 assert_eq!(r.min, min);
91 assert_eq!(r.max(), max);
92 }
93
94 #[test]
95 fn center_is_midpoint() {
96 let r = Rect::new(0.0, 0.0, 100.0, 100.0);
97 assert_eq!(r.center(), Vec2::new(50.0, 50.0));
98 }
99
100 #[test]
101 fn contains_inside_point() {
102 let r = Rect::new(0.0, 0.0, 100.0, 100.0);
103 assert!(r.contains(Vec2::new(50.0, 50.0)));
104 }
105
106 #[test]
107 fn contains_includes_min_edge() {
108 let r = Rect::new(0.0, 0.0, 100.0, 100.0);
109 assert!(r.contains(Vec2::new(0.0, 0.0)));
110 }
111
112 #[test]
113 fn contains_excludes_max_edge() {
114 let r = Rect::new(0.0, 0.0, 100.0, 100.0);
115 assert!(!r.contains(Vec2::new(100.0, 50.0)));
116 assert!(!r.contains(Vec2::new(50.0, 100.0)));
117 }
118
119 #[test]
120 fn width_and_height_match_size() {
121 let r = Rect::new(0.0, 0.0, 100.0, 50.0);
122 assert!((r.width() - 100.0).abs() < f32::EPSILON);
123 assert!((r.height() - 50.0).abs() < f32::EPSILON);
124 }
125}