1use point2f::Point2f;
6use vector2f::Vector2f;
7
8use std::f32::EPSILON;
9use std::ops::Mul;
10
11#[cfg(all(windows, feature = "d2d"))]
12use winapi::um::dcommon::D2D_MATRIX_3X2_F;
13#[cfg(all(windows, feature = "d2d"))]
14use winapi::um::dwrite::DWRITE_MATRIX;
15
16pub const IDENTITY: Matrix3x2f = Matrix3x2f::IDENTITY;
18
19#[derive(Copy, Clone, Debug, PartialEq)]
44#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
45#[repr(C)]
46pub struct Matrix3x2f {
47 pub a: f32,
49 pub b: f32,
51 pub c: f32,
53 pub d: f32,
55 pub x: f32,
57 pub y: f32,
59}
60
61impl Matrix3x2f {
62 pub const IDENTITY: Matrix3x2f = Matrix3x2f {
64 a: 1.0,
65 b: 0.0,
66 c: 0.0,
67 d: 1.0,
68 x: 0.0,
69 y: 0.0,
70 };
71
72 #[inline]
74 pub fn new(parts: [[f32; 2]; 3]) -> Matrix3x2f {
75 Matrix3x2f {
76 a: parts[0][0],
77 b: parts[0][1],
78 c: parts[1][0],
79 d: parts[1][1],
80 x: parts[2][0],
81 y: parts[2][1],
82 }
83 }
84
85 #[inline]
90 pub fn from_slice(values: &[f32]) -> Matrix3x2f {
91 assert_eq!(values.len(), 6);
92 Matrix3x2f {
93 a: values[0],
94 b: values[1],
95 c: values[2],
96 d: values[3],
97 x: values[4],
98 y: values[5],
99 }
100 }
101
102 #[inline]
105 pub fn from_tuple(values: (f32, f32, f32, f32, f32, f32)) -> Matrix3x2f {
106 let (a, b, c, d, x, y) = values;
107 Matrix3x2f { a, b, c, d, x, y }
108 }
109
110 #[inline]
120 pub fn translation(trans: impl Into<Vector2f>) -> Matrix3x2f {
121 let trans = trans.into();
122
123 Matrix3x2f {
124 a: 1.0,
125 b: 0.0,
126 c: 0.0,
127 d: 1.0,
128 x: trans.x,
129 y: trans.y,
130 }
131 }
132
133 #[inline]
145 pub fn scaling(scale: impl Into<Vector2f>, center: impl Into<Point2f>) -> Matrix3x2f {
146 let scale = scale.into();
147 let center = center.into();
148
149 Matrix3x2f {
150 a: scale.x,
151 b: 0.0,
152 c: 0.0,
153 d: scale.y,
154 x: center.x - scale.x * center.x,
155 y: center.y - scale.y * center.y,
156 }
157 }
158
159 #[inline]
171 pub fn rotation(angle: f32, center: impl Into<Point2f>) -> Matrix3x2f {
172 let center = center.into();
173 let cos = angle.cos();
174 let sin = angle.sin();
175
176 Matrix3x2f {
177 a: cos,
178 b: sin,
179 c: -sin,
180 d: cos,
181 x: center.x - cos * center.x - sin * center.y,
182 y: center.y - cos * center.y - sin * center.x,
183 }
184 }
185
186 #[inline]
195 pub fn skew(angle_x: f32, angle_y: f32, center: impl Into<Point2f>) -> Matrix3x2f {
196 let center = center.into();
197 let tanx = angle_x.tan();
198 let tany = angle_y.tan();
199
200 Matrix3x2f {
201 a: 1.0,
202 b: tany,
203 c: tanx,
204 d: 1.0,
205 x: -center.y * tany,
206 y: -center.x * tanx,
207 }
208 }
209
210 #[inline]
211 pub fn linear_transpose(&self) -> Matrix3x2f {
213 Matrix3x2f {
214 a: self.a,
215 b: self.c,
216 c: self.b,
217 d: self.d,
218 x: self.x,
219 y: self.y,
220 }
221 }
222
223 #[inline]
226 pub fn determinant(&self) -> f32 {
227 self.a * self.d - self.b * self.c
228 }
229
230 #[inline]
234 pub fn is_invertible(&self) -> bool {
235 Matrix3x2f::det_shows_invertible(self.determinant())
236 }
237
238 #[inline]
240 pub fn inverse(&self) -> Matrix3x2f {
241 let det = self.determinant();
242 assert!(Matrix3x2f::det_shows_invertible(det));
243
244 self.unchecked_inverse(det)
245 }
246
247 #[inline]
250 pub fn try_inverse(&self) -> Option<Matrix3x2f> {
251 let det = self.determinant();
252 if Matrix3x2f::det_shows_invertible(det) {
253 Some(self.unchecked_inverse(det))
254 } else {
255 None
256 }
257 }
258
259 #[inline]
263 pub fn unchecked_inverse(&self, det: f32) -> Matrix3x2f {
264 Matrix3x2f {
265 a: self.d / det,
266 b: self.b / -det,
267 c: self.c / -det,
268 d: self.a / det,
269 x: (self.d * self.x - self.c * self.y) / -det,
270 y: (self.b * self.x - self.a * self.y) / det,
271 }
272 }
273
274 #[inline]
277 pub fn compose(
278 scaling: impl Into<Vector2f>,
279 rotation: f32,
280 translation: impl Into<Vector2f>,
281 ) -> Matrix3x2f {
282 let s = scaling.into();
283 let cos = rotation.cos();
284 let sin = rotation.sin();
285 let trans = translation.into();
286
287 Matrix3x2f {
288 a: s.x * cos,
289 b: s.y * sin,
290 c: s.x * -sin,
291 d: s.y * cos,
292 x: trans.x,
293 y: trans.y,
294 }
295 }
296
297 #[inline]
300 pub fn decompose(&self) -> Decomposition {
301 Decomposition {
302 translation: [self.x, self.y].into(),
303 scaling: Vector2f {
304 x: (self.a * self.a + self.c * self.c).sqrt(),
305 y: (self.b * self.b + self.d * self.d).sqrt(),
306 },
307 rotation: self.b.atan2(self.d),
308 }
309 }
310
311 #[inline]
314 pub fn transform_point(&self, point: impl Into<Point2f>) -> Point2f {
315 point.into() * *self
316 }
317
318 #[inline]
321 pub fn transform_vector(&self, vec: impl Into<Vector2f>) -> Vector2f {
322 vec.into() * *self
323 }
324
325 #[inline]
328 pub fn to_row_major(&self) -> [[f32; 3]; 3] {
329 [
330 [self.a, self.b, 0.0],
331 [self.c, self.d, 0.0],
332 [self.x, self.y, 1.0],
333 ]
334 }
335
336 #[inline]
339 pub fn to_column_major(&self) -> [[f32; 3]; 3] {
340 [
341 [self.a, self.c, self.x],
342 [self.b, self.d, self.y],
343 [0.0, 0.0, 1.0],
344 ]
345 }
346
347 #[inline]
349 pub fn is_approx_eq(&self, other: &Matrix3x2f, epsilon: f32) -> bool {
350 return (self.a - other.a).abs() < epsilon
351 && (self.b - other.b).abs() < epsilon
352 && (self.c - other.c).abs() < epsilon
353 && (self.d - other.d).abs() < epsilon
354 && (self.x - other.x).abs() < epsilon
355 && (self.y - other.y).abs() < epsilon;
356 }
357
358 #[inline]
360 pub fn is_identity(&self) -> bool {
361 self.is_approx_eq(&Matrix3x2f::IDENTITY, 1e-5)
362 }
363
364 #[inline]
365 fn det_shows_invertible(det: f32) -> bool {
366 det.abs() > EPSILON
367 }
368}
369
370impl Mul for Matrix3x2f {
371 type Output = Matrix3x2f;
372
373 #[inline]
374 fn mul(self, rhs: Matrix3x2f) -> Matrix3x2f {
375 let lhs = self;
376
377 Matrix3x2f {
378 a: lhs.a * rhs.a + lhs.b * rhs.c,
379 b: lhs.a * rhs.b + lhs.b * rhs.d,
380 c: lhs.c * rhs.a + lhs.d * rhs.c,
381 d: lhs.c * rhs.b + lhs.d * rhs.d,
382 x: lhs.x * rhs.a + lhs.y * rhs.c + rhs.x,
383 y: lhs.x * rhs.b + lhs.y * rhs.d + rhs.y,
384 }
385 }
386}
387
388impl Mul<Matrix3x2f> for Point2f {
389 type Output = Point2f;
390
391 #[inline]
392 fn mul(self, m: Matrix3x2f) -> Point2f {
393 Point2f {
394 x: self.x * m.a + self.y * m.c + m.x,
395 y: self.x * m.b + self.y * m.d + m.y,
396 }
397 }
398}
399
400impl Mul<Matrix3x2f> for Vector2f {
401 type Output = Vector2f;
402
403 #[inline]
404 fn mul(self, m: Matrix3x2f) -> Vector2f {
405 Vector2f {
406 x: self.x * m.a + self.y * m.c,
407 y: self.x * m.b + self.y * m.d,
408 }
409 }
410}
411
412impl From<[[f32; 2]; 3]> for Matrix3x2f {
413 #[inline]
414 fn from(parts: [[f32; 2]; 3]) -> Matrix3x2f {
415 Matrix3x2f::new(parts)
416 }
417}
418
419impl From<Matrix3x2f> for [[f32; 2]; 3] {
420 #[inline]
421 fn from(m: Matrix3x2f) -> [[f32; 2]; 3] {
422 [[m.a, m.b], [m.c, m.d], [m.x, m.y]]
423 }
424}
425
426impl From<Matrix3x2f> for [[f32; 3]; 3] {
427 #[inline]
428 fn from(m: Matrix3x2f) -> [[f32; 3]; 3] {
429 m.to_row_major()
430 }
431}
432
433#[cfg(all(windows, feature = "d2d"))]
434impl From<Matrix3x2f> for D2D_MATRIX_3X2_F {
435 #[inline]
436 fn from(m: Matrix3x2f) -> D2D_MATRIX_3X2_F {
437 let matrix: [[f32; 2]; 3] = m.into();
438 D2D_MATRIX_3X2_F { matrix }
439 }
440}
441
442#[cfg(all(windows, feature = "d2d"))]
443impl From<D2D_MATRIX_3X2_F> for Matrix3x2f {
444 #[inline]
445 fn from(m: D2D_MATRIX_3X2_F) -> Matrix3x2f {
446 Matrix3x2f::new(m.matrix)
447 }
448}
449
450#[cfg(all(windows, feature = "d2d"))]
451impl From<Matrix3x2f> for DWRITE_MATRIX {
452 #[inline]
453 fn from(m: Matrix3x2f) -> DWRITE_MATRIX {
454 DWRITE_MATRIX {
455 m11: m.a,
456 m12: m.b,
457 m21: m.c,
458 m22: m.d,
459 dx: m.x,
460 dy: m.y,
461 }
462 }
463}
464
465#[cfg(all(windows, feature = "d2d"))]
466impl From<DWRITE_MATRIX> for Matrix3x2f {
467 #[inline]
468 fn from(m: DWRITE_MATRIX) -> Matrix3x2f {
469 Matrix3x2f {
470 a: m.m11,
471 b: m.m12,
472 c: m.m21,
473 d: m.m22,
474 x: m.dx,
475 y: m.dy,
476 }
477 }
478}
479
480impl Default for Matrix3x2f {
481 #[inline]
482 fn default() -> Self {
483 Matrix3x2f::IDENTITY
484 }
485}
486
487pub struct Decomposition {
490 pub scaling: Vector2f,
493 pub rotation: f32,
496 pub translation: Vector2f,
499}
500
501impl From<Decomposition> for Matrix3x2f {
502 #[inline]
503 fn from(decomp: Decomposition) -> Matrix3x2f {
504 Matrix3x2f::compose(decomp.scaling, decomp.rotation, decomp.translation)
505 }
506}
507
508#[cfg(feature = "mint")]
509impl From<Matrix3x2f> for mint::RowMatrix3x2<f32> {
510 #[inline]
511 fn from(mat: Matrix3x2f) -> mint::RowMatrix3x2<f32> {
512 mint::RowMatrix3x2 {
513 x: [mat.a, mat.b].into(),
514 y: [mat.c, mat.d].into(),
515 z: [mat.x, mat.y].into(),
516 }
517 }
518}
519
520#[cfg(all(test, windows, feature = "d2d"))]
521#[test]
522fn mat32_d2d_bin_compat() {
523 use std::mem::size_of_val;
524
525 fn ptr_eq<T>(a: &T, b: &T) -> bool {
526 (a as *const T) == (b as *const T)
527 }
528
529 let mat = Matrix3x2f::IDENTITY;
530 let d2d = unsafe { &*((&mat) as *const _ as *const D2D_MATRIX_3X2_F) };
531
532 assert!(ptr_eq(&mat.a, &d2d.matrix[0][0]));
533 assert!(ptr_eq(&mat.b, &d2d.matrix[0][1]));
534 assert!(ptr_eq(&mat.c, &d2d.matrix[1][0]));
535 assert!(ptr_eq(&mat.d, &d2d.matrix[1][1]));
536 assert!(ptr_eq(&mat.x, &d2d.matrix[2][0]));
537 assert!(ptr_eq(&mat.y, &d2d.matrix[2][1]));
538 assert_eq!(size_of_val(&mat), size_of_val(d2d));
539}