1use crate::*;
2
3#[repr(C)]
4#[derive(Debug, Clone, Copy, PartialEq, Default, PartialOrd)]
5pub struct Rect {
6 pub xy: Vec2,
7 pub wh: Vec2,
8}
9pub const fn rect(x: f32, y: f32, w: f32, h: f32) -> Rect {
11 Rect { xy: vec2(x,y), wh: vec2(w,h)}
12}
13pub const fn rectv(xy: Vec2, wh: Vec2) -> Rect {
15 Rect { xy, wh }
16}
17pub fn rectc(xy: Vec2, wh: Vec2) -> Rect {
19 Rect { xy: xy - wh/2.0, wh }
20}
21
22impl Rect {
23 pub fn i(&self) -> Vec2 { vec2(self.wh.x, 0.0) }
24 pub fn j(&self) -> Vec2 { vec2(0.0, self.wh.y) }
25 pub fn tl(&self) -> Vec2 { self.xy }
26 pub fn tr(&self) -> Vec2 { self.xy + self.i() }
27 pub fn bl(&self) -> Vec2 { self.xy + self.j() }
28 pub fn br(&self) -> Vec2 { self.xy + self.wh }
29 pub fn w(&self) -> f32 { self.wh.x }
30 pub fn h(&self) -> f32 { self.wh.y }
31 pub fn center(&self) -> Vec2 { self.xy + self.wh/2.0 }
32 pub fn contains(&self, p: Vec2) -> bool {
33 let p = p - self.xy;
34 p.x >= 0.0 && p.x <= self.wh.x &&
35 p.y >= 0.0 && p.y <= self.wh.y
36 }
37 pub fn rect_to_world(&self, p: Vec2) -> Vec2 {
39 self.xy + p * self.wh
40 }
41 pub fn world_to_rect(&self, p: Vec2) -> Vec2 {
42 (p - self.xy) / self.wh
43 }
44 pub fn uniform_grid(&self, i: usize, j: usize, w: usize, h: usize) -> Rect {
45 let v = self.wh / vec2(w as f32, h as f32);
46 rectv(self.xy + vec2(i as f32, j as f32) * v, v)
47 }
48 pub fn grid(&self, i: usize, j: usize, widths: &[f32], heights: &[f32]) -> Rect {
50 let mut acc = vec2(0.0, 0.0);
51 let sw = widths.iter().fold(0.0f32, |acc: f32, e| acc + e);
52 let sh = widths.iter().fold(0.0f32, |acc: f32, e| acc + e);
53 for x in 0..i {
54 acc.x += widths[x];
55 }
56 for y in 0..j {
57 acc.y += heights[y];
58 }
59 acc.x /= sw;
60 acc.y /= sh;
61 acc *= self.wh;
62
63 acc += self.xy;
64
65 let wh = vec2(widths[i]/sw, heights[j]/sh) * self.wh;
66 rectv(acc, wh)
67 }
68 pub fn fit_aspect(&self, a: f32) -> Rect {
69 let a_self = self.wh.x/self.wh.y;
70 if a_self > a {
71 rect((self.wh.x - self.wh.x*(1.0/a))/2.0, 0.0, self.wh.x*1.0/a, self.wh.y)
73 } else {
74 rect(0.0, (self.wh.y - self.wh.y*(1.0/a))/2.0, self.wh.x, self.wh.y/a)
76 }
77 }
78 pub fn signed_distance(&self, p: Vec2) -> f32 {
79 let p = p - self.center();
80 let p = vec2(p.x.abs(), p.y.abs());
81 let d = p - (self.wh/2.0); d.max(vec2(0.0, 0.0)).norm() + d.x.max(d.y).min(0.0)
83 }
84 pub fn grow(&self, x: f32, y: f32) -> Self {
86 rectc(self.center(), self.wh + vec2(x,y))
87 }
88}
89
90#[test]
91fn test_rect_rtw() {
92 let r = rect(-2.0, -2.0, 4.0, 4.0);
93 let v = vec2(0.25, 0.25);
94 let p = r.rect_to_world(v);
95 assert_eq!(p, vec2(-1.0, -1.0));
96}
97
98#[test]
99fn test_rect_wtr() {
100 let r = rect(4.0, 4.0, 1.0, 2.0);
101 let v = vec2(4.5, 5.0);
102 let p = r.world_to_rect(v);
103 assert_eq!(p, vec2(0.5, 0.5));
104}
105
106#[test]
107fn test_rect_contains() {
108 let r = rect(1.0, 1.0, 2.0, 2.0);
109
110 let inside_point = vec2(1.5, 1.5);
112 assert!(r.contains(inside_point));
113
114 let outside_point = vec2(3.5, 3.5);
116 assert!(!r.contains(outside_point));
117}
118
119#[test]
120fn test_rect_uniform_grid() {
121 let r = rect(0.0, 0.0, 4.0, 4.0);
122 let i = 1;
123 let j = 0;
124 let w = 2;
125 let h = 2;
126 let grid_rect = r.uniform_grid(i, j, w, h);
127 assert_eq!(grid_rect, rect(2.0, 0.0, 2.0, 2.0));
128}
129
130#[test]
131fn test_rect_grid() {
132 let r = rect(0.0, 0.0, 4.0, 4.0);
133 let i = 1;
134 let j = 1;
135 let widths = vec![1.0, 2.0, 1.0];
136 let heights = vec![0.5, 2.5, 1.0];
137 let grid_rect = r.grid(i, j, &widths, &heights);
138 assert_eq!(grid_rect, rect(1.0, 0.5, 2.0, 5.0 / 8.0 * 4.0));
139}
140
141#[test]
142fn test_rect_fit_aspect() {
143 let r = rect(0.0, 0.0, 4.0, 4.0);
144 let aspect = 2.0;
145 let fitted_rect = r.fit_aspect(aspect);
146 assert_eq!(fitted_rect, rect(0.0, 1.0, 4.0, 2.0));
147}
148#[test]
149fn test_sdf() {
150 let p = vec2(69.0, 420.0);
151 let r = rect(0.0, 0.0,69.0, 69.0);
152 assert_eq!(r.signed_distance(p), 351.0);
153 let p = vec2(2.0, 3.0);
154 let r = rect(-2.0, -2.0,1.0, 1.0);
155 assert_eq!(r.signed_distance(p), 5.0);
156}