1#[derive(Clone, Copy, Debug, Default, PartialEq)]
6pub struct Point {
7 pub x: f32,
9 pub y: f32,
11}
12
13impl Point {
14 pub const fn new(x: f32, y: f32) -> Point {
16 Point { x, y }
17 }
18}
19
20#[derive(Clone, Copy, Debug, Default, PartialEq)]
22pub struct Size {
23 pub width: f32,
25 pub height: f32,
27}
28
29impl Size {
30 pub const fn new(width: f32, height: f32) -> Size {
32 Size { width, height }
33 }
34}
35
36#[derive(Clone, Copy, Debug, Default, PartialEq)]
38pub struct Rect {
39 pub x: f32,
41 pub y: f32,
43 pub width: f32,
45 pub height: f32,
47}
48
49impl Rect {
50 pub const fn new(x: f32, y: f32, width: f32, height: f32) -> Rect {
52 Rect {
53 x,
54 y,
55 width,
56 height,
57 }
58 }
59
60 pub fn right(&self) -> f32 {
62 self.x + self.width
63 }
64
65 pub fn bottom(&self) -> f32 {
67 self.y + self.height
68 }
69
70 pub fn is_empty(&self) -> bool {
72 self.width <= 0.0 || self.height <= 0.0
73 }
74
75 pub fn contains(&self, point: Point) -> bool {
79 point.x >= self.x && point.x < self.right() && point.y >= self.y && point.y < self.bottom()
80 }
81
82 pub fn union(&self, other: Rect) -> Rect {
85 if other.is_empty() {
86 return *self;
87 }
88 if self.is_empty() {
89 return other;
90 }
91 let x = self.x.min(other.x);
92 let y = self.y.min(other.y);
93 Rect::new(
94 x,
95 y,
96 self.right().max(other.right()) - x,
97 self.bottom().max(other.bottom()) - y,
98 )
99 }
100
101 pub fn intersect(&self, other: Rect) -> Rect {
103 let x = self.x.max(other.x);
104 let y = self.y.max(other.y);
105 let right = self.right().min(other.right());
106 let bottom = self.bottom().min(other.bottom());
107 if right > x && bottom > y {
108 Rect::new(x, y, right - x, bottom - y)
109 } else {
110 Rect::default()
111 }
112 }
113}
114
115impl Rect {
116 pub(crate) fn outset(&self, by: f32) -> Rect {
119 if self.is_empty() {
120 return *self;
121 }
122 Rect::new(
123 self.x - by,
124 self.y - by,
125 self.width + 2.0 * by,
126 self.height + 2.0 * by,
127 )
128 }
129}
130
131#[derive(Clone, Copy, Debug, PartialEq)]
134pub struct Affine {
135 pub sx: f32,
137 pub ky: f32,
139 pub kx: f32,
141 pub sy: f32,
143 pub tx: f32,
145 pub ty: f32,
147}
148
149impl Affine {
150 pub(crate) fn map(&self, point: Point) -> Point {
152 Point::new(
153 self.sx * point.x + self.kx * point.y + self.tx,
154 self.ky * point.x + self.sy * point.y + self.ty,
155 )
156 }
157
158 pub(crate) fn map_rect(&self, rect: Rect) -> Rect {
161 let corners = [
162 Point::new(rect.x, rect.y),
163 Point::new(rect.right(), rect.y),
164 Point::new(rect.x, rect.bottom()),
165 Point::new(rect.right(), rect.bottom()),
166 ]
167 .map(|corner| self.map(corner));
168 let (mut left, mut top) = (f32::INFINITY, f32::INFINITY);
169 let (mut right, mut bottom) = (f32::NEG_INFINITY, f32::NEG_INFINITY);
170 for corner in corners {
171 left = left.min(corner.x);
172 top = top.min(corner.y);
173 right = right.max(corner.x);
174 bottom = bottom.max(corner.y);
175 }
176 let mapped = Rect::new(left, top, right - left, bottom - top);
177 if [mapped.x, mapped.y, mapped.width, mapped.height]
178 .iter()
179 .all(|n| n.is_finite())
180 {
181 mapped
182 } else {
183 Rect::default()
184 }
185 }
186
187 pub(crate) fn invert(&self) -> Option<Affine> {
190 let det = self.sx * self.sy - self.kx * self.ky;
191 if det == 0.0 || !det.is_finite() {
192 return None;
193 }
194 let (sx, ky, kx, sy) = (self.sy / det, -self.ky / det, -self.kx / det, self.sx / det);
195 Some(Affine {
196 sx,
197 ky,
198 kx,
199 sy,
200 tx: -(sx * self.tx + kx * self.ty),
201 ty: -(ky * self.tx + sy * self.ty),
202 })
203 }
204}
205
206pub(crate) fn through(chain: &[Affine], rect: Rect) -> Rect {
211 chain.iter().rev().fold(rect, |rect, transform| {
212 if rect.is_empty() {
214 rect
215 } else {
216 transform.map_rect(rect.outset(1.0))
217 }
218 })
219}