1use crate::point::PointF;
6use crate::rect::{Rect, RectF};
7use std::ops::Mul;
8
9#[derive(Debug, Clone, Copy, PartialEq)]
18pub struct Matrix {
19 values: [f32; 6],
25}
26
27impl Matrix {
28 pub fn identity() -> Self {
30 Self {
31 values: [1.0, 0.0, 0.0, 1.0, 0.0, 0.0],
32 }
33 }
34
35 pub fn translate(dx: f32, dy: f32) -> Self {
37 Self {
38 values: [1.0, 0.0, 0.0, 1.0, dx, dy],
39 }
40 }
41
42 pub fn scale(sx: f32, sy: f32) -> Self {
44 Self {
45 values: [sx, 0.0, 0.0, sy, 0.0, 0.0],
46 }
47 }
48
49 pub fn rotate(degrees: f32) -> Self {
51 let radians = degrees.to_radians();
52 let cos = radians.cos();
53 let sin = radians.sin();
54 Self {
55 values: [cos, sin, -sin, cos, 0.0, 0.0],
56 }
57 }
58
59 pub fn rotate_at(degrees: f32, px: f32, py: f32) -> Self {
61 let translate1 = Self::translate(-px, -py);
62 let rotate = Self::rotate(degrees);
63 let translate2 = Self::translate(px, py);
64 translate2 * rotate * translate1
65 }
66
67 pub fn skew(sx: f32, sy: f32) -> Self {
69 Self {
70 values: [
71 1.0,
72 sy.to_radians().tan(),
73 sx.to_radians().tan(),
74 1.0,
75 0.0,
76 0.0,
77 ],
78 }
79 }
80
81 pub fn from_values(values: [f32; 6]) -> Self {
83 Self { values }
84 }
85
86 pub fn values(&self) -> [f32; 6] {
88 self.values
89 }
90
91 pub fn scale_x(&self) -> f32 {
93 self.values[0]
94 }
95
96 pub fn skew_y(&self) -> f32 {
98 self.values[1]
99 }
100
101 pub fn skew_x(&self) -> f32 {
103 self.values[2]
104 }
105
106 pub fn scale_y(&self) -> f32 {
108 self.values[3]
109 }
110
111 pub fn translate_x(&self) -> f32 {
113 self.values[4]
114 }
115
116 pub fn translate_y(&self) -> f32 {
118 self.values[5]
119 }
120
121 pub fn pre_translate(&self, dx: f32, dy: f32) -> Self {
123 Self::translate(dx, dy) * *self
124 }
125
126 pub fn pre_scale(&self, sx: f32, sy: f32) -> Self {
128 Self::scale(sx, sy) * *self
129 }
130
131 pub fn pre_rotate(&self, degrees: f32) -> Self {
133 Self::rotate(degrees) * *self
134 }
135
136 pub fn post_translate(&self, dx: f32, dy: f32) -> Self {
138 *self * Self::translate(dx, dy)
139 }
140
141 pub fn post_scale(&self, sx: f32, sy: f32) -> Self {
143 *self * Self::scale(sx, sy)
144 }
145
146 pub fn post_rotate(&self, degrees: f32) -> Self {
148 *self * Self::rotate(degrees)
149 }
150
151 pub fn map_point(&self, x: f32, y: f32) -> (f32, f32) {
153 let new_x = self.values[0] * x + self.values[2] * y + self.values[4];
154 let new_y = self.values[1] * x + self.values[3] * y + self.values[5];
155 (new_x, new_y)
156 }
157
158 pub fn map_pointf(&self, point: PointF) -> PointF {
160 let (x, y) = self.map_point(point.x, point.y);
161 PointF::new(x, y)
162 }
163
164 pub fn map_points(&self, points: &[PointF]) -> Vec<PointF> {
166 points.iter().map(|&p| self.map_pointf(p)).collect()
167 }
168
169 pub fn post_concat(&self, other: &Matrix) -> Self {
171 *self * *other
172 }
173
174 pub fn map_rect(&self, rect: RectF) -> RectF {
176 let points = [
177 PointF::new(rect.x, rect.y),
178 PointF::new(rect.x + rect.width, rect.y),
179 PointF::new(rect.x + rect.width, rect.y + rect.height),
180 PointF::new(rect.x, rect.y + rect.height),
181 ];
182
183 let transformed = self.map_points(&points);
184
185 let mut min_x = f32::MAX;
186 let mut min_y = f32::MAX;
187 let mut max_x = f32::MIN;
188 let mut max_y = f32::MIN;
189
190 for p in &transformed {
191 min_x = min_x.min(p.x);
192 min_y = min_y.min(p.y);
193 max_x = max_x.max(p.x);
194 max_y = max_y.max(p.y);
195 }
196
197 RectF::new(min_x, min_y, max_x - min_x, max_y - min_y)
198 }
199
200 pub fn invert(&self) -> Option<Self> {
202 let [a, b, c, d, e, f] = self.values;
203
204 let det = a * d - b * c;
206
207 if det.abs() < 1e-10 {
208 return None; }
210
211 let inv_det = 1.0 / det;
212
213 Some(Self {
214 values: [
215 d * inv_det,
216 -b * inv_det,
217 -c * inv_det,
218 a * inv_det,
219 (c * f - d * e) * inv_det,
220 (b * e - a * f) * inv_det,
221 ],
222 })
223 }
224
225 pub fn is_identity(&self) -> bool {
227 const EPSILON: f32 = 1e-6;
228 (self.values[0] - 1.0).abs() < EPSILON
229 && self.values[1].abs() < EPSILON
230 && self.values[2].abs() < EPSILON
231 && (self.values[3] - 1.0).abs() < EPSILON
232 && self.values[4].abs() < EPSILON
233 && self.values[5].abs() < EPSILON
234 }
235
236 pub fn is_translate(&self) -> bool {
238 const EPSILON: f32 = 1e-6;
239 (self.values[0] - 1.0).abs() < EPSILON
240 && self.values[1].abs() < EPSILON
241 && self.values[2].abs() < EPSILON
242 && (self.values[3] - 1.0).abs() < EPSILON
243 }
244
245 pub fn is_scale_translate(&self) -> bool {
247 const EPSILON: f32 = 1e-6;
248 self.values[1].abs() < EPSILON && self.values[2].abs() < EPSILON
249 }
250
251 pub fn reset(&mut self) {
253 *self = Self::identity();
254 }
255
256 pub fn set_translate(&mut self, dx: f32, dy: f32) {
258 *self = Self::translate(dx, dy);
259 }
260
261 pub fn set_scale(&mut self, sx: f32, sy: f32) {
263 *self = Self::scale(sx, sy);
264 }
265
266 pub fn set_rotate(&mut self, degrees: f32) {
268 *self = Self::rotate(degrees);
269 }
270}
271
272impl Default for Matrix {
273 fn default() -> Self {
274 Self::identity()
275 }
276}
277
278impl Mul for Matrix {
280 type Output = Self;
281
282 fn mul(self, rhs: Self) -> Self::Output {
283 let [a1, b1, c1, d1, e1, f1] = self.values;
284 let [a2, b2, c2, d2, e2, f2] = rhs.values;
285
286 Self {
287 values: [
288 a1 * a2 + c1 * b2,
289 b1 * a2 + d1 * b2,
290 a1 * c2 + c1 * d2,
291 b1 * c2 + d1 * d2,
292 a1 * e2 + c1 * f2 + e1,
293 b1 * e2 + d1 * f2 + f1,
294 ],
295 }
296 }
297}
298
299#[derive(Debug, Clone)]
303pub struct CanvasState {
304 pub matrix: Matrix,
306 pub clip_rect: Option<Rect>,
308}
309
310impl CanvasState {
311 pub fn new() -> Self {
313 Self {
314 matrix: Matrix::identity(),
315 clip_rect: None,
316 }
317 }
318
319 pub fn with_matrix(matrix: Matrix) -> Self {
321 Self {
322 matrix,
323 clip_rect: None,
324 }
325 }
326}
327
328impl Default for CanvasState {
329 fn default() -> Self {
330 Self::new()
331 }
332}
333
334#[cfg(test)]
335mod tests {
336 use super::*;
337
338 #[test]
339 fn test_identity_matrix() {
340 let m = Matrix::identity();
341 assert!(m.is_identity());
342 let p = PointF::new(10.0, 20.0);
343 let transformed = m.map_point(p);
344 assert_eq!(transformed, p);
345 }
346
347 #[test]
348 fn test_translate_matrix() {
349 let m = Matrix::translate(10.0, 20.0);
350 let p = PointF::new(5.0, 5.0);
351 let transformed = m.map_point(p);
352 assert_eq!(transformed, PointF::new(15.0, 25.0));
353 }
354
355 #[test]
356 fn test_scale_matrix() {
357 let m = Matrix::scale(2.0, 3.0);
358 let p = PointF::new(10.0, 10.0);
359 let transformed = m.map_point(p);
360 assert_eq!(transformed, PointF::new(20.0, 30.0));
361 }
362
363 #[test]
364 fn test_rotate_matrix() {
365 let m = Matrix::rotate(90.0);
366 let p = PointF::new(1.0, 0.0);
367 let transformed = m.map_point(p);
368 assert!((transformed.x - 0.0).abs() < 1e-6);
370 assert!((transformed.y - 1.0).abs() < 1e-6);
371 }
372
373 #[test]
374 fn test_matrix_multiply() {
375 let translate = Matrix::translate(10.0, 20.0);
376 let scale = Matrix::scale(2.0, 2.0);
377 let combined = translate * scale;
378
379 let p = PointF::new(5.0, 5.0);
380 let transformed = combined.map_point(p);
381 assert_eq!(transformed, PointF::new(20.0, 30.0));
383 }
384
385 #[test]
386 fn test_matrix_invert() {
387 let m = Matrix::translate(10.0, 20.0);
388 let inv = m.invert().unwrap();
389 let combined = m * inv;
390 assert!(combined.is_identity());
391 }
392
393 #[test]
394 fn test_map_rect() {
395 let m = Matrix::scale(2.0, 2.0);
396 let rect = RectF::new(10.0, 10.0, 20.0, 30.0);
397 let transformed = m.map_rect(rect);
398 assert_eq!(transformed.x, 20.0);
399 assert_eq!(transformed.y, 20.0);
400 assert_eq!(transformed.width, 40.0);
401 assert_eq!(transformed.height, 60.0);
402 }
403
404 #[test]
405 fn test_is_translate() {
406 let m = Matrix::translate(10.0, 20.0);
407 assert!(m.is_translate());
408
409 let m = Matrix::scale(2.0, 2.0);
410 assert!(!m.is_translate());
411 }
412
413 #[test]
414 fn test_is_scale_translate() {
415 let m = Matrix::scale(2.0, 3.0);
416 assert!(m.is_scale_translate());
417
418 let m = Matrix::rotate(45.0);
419 assert!(!m.is_scale_translate());
420 }
421}