1use std::fmt;
4use std::ops::{Add, Mul, Neg, Sub};
5
6use super::single::{ieee_remainder, InvariantF32};
7use super::Vector2;
8
9const ROTATION_EPSILON: f32 = 0.001 * std::f32::consts::PI / 180.0;
12
13#[derive(Clone, Copy, Debug, PartialEq, Default)]
15pub struct Matrix3x2 {
16 pub m11: f32,
18 pub m12: f32,
20 pub m21: f32,
22 pub m22: f32,
24 pub m31: f32,
26 pub m32: f32,
28}
29
30impl Matrix3x2 {
31 pub const IDENTITY: Matrix3x2 = Matrix3x2::new(1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
33
34 #[inline]
36 pub const fn new(m11: f32, m12: f32, m21: f32, m22: f32, m31: f32, m32: f32) -> Self {
37 Self {
38 m11,
39 m12,
40 m21,
41 m22,
42 m31,
43 m32,
44 }
45 }
46
47 #[inline]
49 pub fn is_identity(&self) -> bool {
50 *self == Matrix3x2::IDENTITY
51 }
52
53 #[inline]
55 pub fn translation(&self) -> Vector2 {
56 Vector2::new(self.m31, self.m32)
57 }
58
59 #[inline]
61 pub fn set_translation(&mut self, value: Vector2) {
62 self.m31 = value.x;
63 self.m32 = value.y;
64 }
65
66 pub fn create_rotation(radians: f32) -> Matrix3x2 {
68 let (s, c) = rotation_sin_cos(radians);
69
70 Matrix3x2::new(c, s, -s, c, 0.0, 0.0)
74 }
75
76 pub fn create_rotation_at(radians: f32, center_point: Vector2) -> Matrix3x2 {
78 let (s, c) = rotation_sin_cos(radians);
79
80 let x = center_point.x * (1.0 - c) + center_point.y * s;
81 let y = center_point.y * (1.0 - c) - center_point.x * s;
82
83 Matrix3x2::new(c, s, -s, c, x, y)
87 }
88
89 #[inline]
91 pub fn create_scale(scales: Vector2) -> Matrix3x2 {
92 Matrix3x2::create_scale_xy(scales.x, scales.y)
93 }
94
95 #[inline]
97 pub fn create_scale_xy(x_scale: f32, y_scale: f32) -> Matrix3x2 {
98 Matrix3x2::new(x_scale, 0.0, 0.0, y_scale, 0.0, 0.0)
99 }
100
101 #[inline]
103 pub fn create_scale_uniform(scale: f32) -> Matrix3x2 {
104 Matrix3x2::create_scale_xy(scale, scale)
105 }
106
107 #[inline]
110 pub fn create_scale_at(scales: Vector2, center_point: Vector2) -> Matrix3x2 {
111 let tx = center_point.x * (1.0 - scales.x);
112 let ty = center_point.y * (1.0 - scales.y);
113 Matrix3x2::new(scales.x, 0.0, 0.0, scales.y, tx, ty)
114 }
115
116 pub fn create_skew(radians_x: f32, radians_y: f32) -> Matrix3x2 {
118 let x_tan = radians_x.tan();
119 let y_tan = radians_y.tan();
120
121 Matrix3x2::new(1.0, y_tan, x_tan, 1.0, 0.0, 0.0)
122 }
123
124 pub fn create_skew_at(radians_x: f32, radians_y: f32, center_point: Vector2) -> Matrix3x2 {
126 let x_tan = radians_x.tan();
127 let y_tan = radians_y.tan();
128
129 let tx = -center_point.y * x_tan;
130 let ty = -center_point.x * y_tan;
131
132 Matrix3x2::new(1.0, y_tan, x_tan, 1.0, tx, ty)
133 }
134
135 #[inline]
137 pub fn create_translation(position: Vector2) -> Matrix3x2 {
138 Matrix3x2::create_translation_xy(position.x, position.y)
139 }
140
141 #[inline]
143 pub fn create_translation_xy(x_position: f32, y_position: f32) -> Matrix3x2 {
144 Matrix3x2::new(1.0, 0.0, 0.0, 1.0, x_position, y_position)
145 }
146
147 #[inline]
149 pub fn get_determinant(&self) -> f32 {
150 (self.m11 * self.m22) - (self.m21 * self.m12)
166 }
167
168 pub fn invert(matrix: Matrix3x2) -> Option<Matrix3x2> {
172 let det = (matrix.m11 * matrix.m22) - (matrix.m21 * matrix.m12);
173
174 if det.abs() < f32::from_bits(1) {
177 return None;
178 }
179
180 let inv_det = 1.0 / det;
181
182 Some(Matrix3x2::new(
183 matrix.m22 * inv_det,
184 -matrix.m12 * inv_det,
185 -matrix.m21 * inv_det,
186 matrix.m11 * inv_det,
187 (matrix.m21 * matrix.m32 - matrix.m31 * matrix.m22) * inv_det,
188 (matrix.m31 * matrix.m12 - matrix.m11 * matrix.m32) * inv_det,
189 ))
190 }
191
192 pub fn invert_or_nan(matrix: Matrix3x2) -> Matrix3x2 {
195 Matrix3x2::invert(matrix).unwrap_or(Matrix3x2::new(
196 f32::NAN,
197 f32::NAN,
198 f32::NAN,
199 f32::NAN,
200 f32::NAN,
201 f32::NAN,
202 ))
203 }
204
205 pub fn lerp(matrix1: Matrix3x2, matrix2: Matrix3x2, amount: f32) -> Matrix3x2 {
208 Matrix3x2::new(
209 matrix1.m11 + (matrix2.m11 - matrix1.m11) * amount,
210 matrix1.m12 + (matrix2.m12 - matrix1.m12) * amount,
211 matrix1.m21 + (matrix2.m21 - matrix1.m21) * amount,
212 matrix1.m22 + (matrix2.m22 - matrix1.m22) * amount,
213 matrix1.m31 + (matrix2.m31 - matrix1.m31) * amount,
214 matrix1.m32 + (matrix2.m32 - matrix1.m32) * amount,
215 )
216 }
217}
218
219#[allow(clippy::manual_range_contains)]
221fn rotation_sin_cos(radians: f32) -> (f32, f32) {
222 use std::f32::consts::PI;
223
224 let radians = ieee_remainder(radians, PI * 2.0);
225
226 if radians > -ROTATION_EPSILON && radians < ROTATION_EPSILON {
227 (0.0, 1.0)
229 } else if radians > PI / 2.0 - ROTATION_EPSILON && radians < PI / 2.0 + ROTATION_EPSILON {
230 (1.0, 0.0)
232 } else if radians < -PI + ROTATION_EPSILON || radians > PI - ROTATION_EPSILON {
233 (0.0, -1.0)
235 } else if radians > -PI / 2.0 - ROTATION_EPSILON && radians < -PI / 2.0 + ROTATION_EPSILON {
236 (-1.0, 0.0)
238 } else {
239 (radians.sin(), radians.cos())
241 }
242}
243
244impl Add for Matrix3x2 {
245 type Output = Matrix3x2;
246 #[inline]
247 fn add(self, value2: Matrix3x2) -> Matrix3x2 {
248 Matrix3x2::new(
249 self.m11 + value2.m11,
250 self.m12 + value2.m12,
251 self.m21 + value2.m21,
252 self.m22 + value2.m22,
253 self.m31 + value2.m31,
254 self.m32 + value2.m32,
255 )
256 }
257}
258
259impl Sub for Matrix3x2 {
260 type Output = Matrix3x2;
261 #[inline]
262 fn sub(self, value2: Matrix3x2) -> Matrix3x2 {
263 Matrix3x2::new(
264 self.m11 - value2.m11,
265 self.m12 - value2.m12,
266 self.m21 - value2.m21,
267 self.m22 - value2.m22,
268 self.m31 - value2.m31,
269 self.m32 - value2.m32,
270 )
271 }
272}
273
274impl Neg for Matrix3x2 {
275 type Output = Matrix3x2;
276 #[inline]
277 fn neg(self) -> Matrix3x2 {
278 Matrix3x2::new(-self.m11, -self.m12, -self.m21, -self.m22, -self.m31, -self.m32)
279 }
280}
281
282impl Mul for Matrix3x2 {
283 type Output = Matrix3x2;
284 #[inline]
285 fn mul(self, value2: Matrix3x2) -> Matrix3x2 {
286 let value1 = self;
287 Matrix3x2::new(
288 value1.m11 * value2.m11 + value1.m12 * value2.m21,
289 value1.m11 * value2.m12 + value1.m12 * value2.m22,
290 value1.m21 * value2.m11 + value1.m22 * value2.m21,
291 value1.m21 * value2.m12 + value1.m22 * value2.m22,
292 value1.m31 * value2.m11 + value1.m32 * value2.m21 + value2.m31,
293 value1.m31 * value2.m12 + value1.m32 * value2.m22 + value2.m32,
294 )
295 }
296}
297
298impl Mul<f32> for Matrix3x2 {
300 type Output = Matrix3x2;
301 #[inline]
302 fn mul(self, value2: f32) -> Matrix3x2 {
303 Matrix3x2::new(
304 self.m11 * value2,
305 self.m12 * value2,
306 self.m21 * value2,
307 self.m22 * value2,
308 self.m31 * value2,
309 self.m32 * value2,
310 )
311 }
312}
313
314impl fmt::Display for Matrix3x2 {
315 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
316 write!(
317 f,
318 "{{ {{M11:{} M12:{}}} {{M21:{} M22:{}}} {{M31:{} M32:{}}} }}",
319 InvariantF32(self.m11),
320 InvariantF32(self.m12),
321 InvariantF32(self.m21),
322 InvariantF32(self.m22),
323 InvariantF32(self.m31),
324 InvariantF32(self.m32)
325 )
326 }
327}