1#![allow(clippy::inline_always)]
2
3use std::borrow::Borrow;
4use std::ops::{Add, Div, Mul, Sub};
5
6use ordered_float::NotNan;
7
8use crate::geometry::DTransformation;
9
10#[derive(Clone, Debug)]
11pub struct Transformation {
14 matrix: [[NotNan<f32>; 3]; 3],
15}
16
17impl Transformation {
18 #[must_use]
20 pub const fn empty() -> Self {
21 Self {
22 matrix: EMPTY_MATRIX,
23 }
24 }
25
26 #[must_use]
27 pub fn from_translation((tx, ty): (f32, f32)) -> Self {
28 Self {
29 matrix: transl_m((tx, ty)),
30 }
31 }
32
33 #[must_use]
34 pub fn from_rotation(angle: f32) -> Self {
35 Self {
36 matrix: rot_m(angle),
37 }
38 }
39
40 #[must_use]
42 pub fn rotate(mut self, angle: f32) -> Self {
43 self.matrix = dot_prod(&rot_m(angle), &self.matrix);
44 self
45 }
46
47 #[must_use]
49 pub fn translate(mut self, (tx, ty): (f32, f32)) -> Self {
50 self.matrix = dot_prod(&transl_m((tx, ty)), &self.matrix);
51 self
52 }
53
54 #[must_use]
56 pub fn rotate_translate(mut self, angle: f32, (tx, ty): (f32, f32)) -> Self {
57 self.matrix = dot_prod(&rot_transl_m(angle, (tx, ty)), &self.matrix);
58 self
59 }
60
61 #[must_use]
63 pub fn translate_rotate(mut self, (tx, ty): (f32, f32), angle: f32) -> Self {
64 self.matrix = dot_prod(&transl_rot_m((tx, ty), angle), &self.matrix);
65 self
66 }
67
68 #[must_use]
70 pub fn transform(mut self, other: &Self) -> Self {
71 self.matrix = dot_prod(&other.matrix, &self.matrix);
72 self
73 }
74
75 #[must_use]
76 pub fn transform_from_decomposed(self, other: &DTransformation) -> Self {
77 self.rotate_translate(other.rotation(), other.translation())
78 }
79
80 #[must_use]
82 pub fn inverse(mut self) -> Self {
83 self.matrix = inverse(&self.matrix);
84 self
85 }
86
87 #[must_use]
88 pub fn is_empty(&self) -> bool {
89 self.matrix == EMPTY_MATRIX
90 }
91
92 #[must_use]
93 pub fn matrix(&self) -> &[[NotNan<f32>; 3]; 3] {
94 &self.matrix
95 }
96
97 #[must_use]
98 pub fn decompose(&self) -> DTransformation {
99 let m = self.matrix();
100 let angle = m[1][0].atan2(m[0][0].into_inner());
101 let (tx, ty) = (m[0][2].into_inner(), m[1][2].into_inner());
102 DTransformation::new(angle, (tx, ty))
103 }
104}
105
106impl<T> From<T> for Transformation
107where
108 T: Borrow<DTransformation>,
109{
110 fn from(dt: T) -> Self {
111 let rot = dt.borrow().rotation();
112 let transl = dt.borrow().translation();
113 Self {
114 matrix: rot_transl_m(rot, transl),
115 }
116 }
117}
118
119impl Default for Transformation {
120 fn default() -> Self {
121 Self::empty()
122 }
123}
124
125const _0: NotNan<f32> = unsafe { NotNan::new_unchecked(0.0) };
126const _1: NotNan<f32> = unsafe { NotNan::new_unchecked(1.0) };
127
128const EMPTY_MATRIX: [[NotNan<f32>; 3]; 3] = [[_1, _0, _0], [_0, _1, _0], [_0, _0, _1]];
129
130fn rot_m(angle: f32) -> [[NotNan<f32>; 3]; 3] {
131 let (sin, cos) = angle.sin_cos();
132 let cos = NotNan::new(cos).expect("cos is NaN");
133 let sin = NotNan::new(sin).expect("sin is NaN");
134
135 [[cos, -sin, _0], [sin, cos, _0], [_0, _0, _1]]
136}
137
138fn transl_m((tx, ty): (f32, f32)) -> [[NotNan<f32>; 3]; 3] {
139 let h = NotNan::new(tx).expect("tx is NaN");
140 let k = NotNan::new(ty).expect("ty is NaN");
141
142 [[_1, _0, h], [_0, _1, k], [_0, _0, _1]]
143}
144
145fn rot_transl_m(angle: f32, (tx, ty): (f32, f32)) -> [[NotNan<f32>; 3]; 3] {
147 let (sin, cos) = angle.sin_cos();
148 let cos = NotNan::new(cos).expect("cos is NaN");
149 let sin = NotNan::new(sin).expect("sin is NaN");
150 let h = NotNan::new(tx).expect("tx is NaN");
151 let k = NotNan::new(ty).expect("ty is NaN");
152
153 [[cos, -sin, h], [sin, cos, k], [_0, _0, _1]]
154}
155
156fn transl_rot_m((tx, ty): (f32, f32), angle: f32) -> [[NotNan<f32>; 3]; 3] {
158 let (sin, cos) = angle.sin_cos();
159 let cos = NotNan::new(cos).expect("cos is NaN");
160 let sin = NotNan::new(sin).expect("sin is NaN");
161 let h = NotNan::new(tx).expect("tx is NaN");
162 let k = NotNan::new(ty).expect("ty is NaN");
163
164 [
165 [cos, -sin, h * cos - k * sin],
166 [sin, cos, h * sin + k * cos],
167 [_0, _0, _1],
168 ]
169}
170
171#[inline(always)]
172fn dot_prod<T>(l: &[[T; 3]; 3], r: &[[T; 3]; 3]) -> [[T; 3]; 3]
173where
174 T: Add<Output = T> + Mul<Output = T> + Copy + Default,
175{
176 [
177 [
178 l[0][0] * r[0][0] + l[0][1] * r[1][0] + l[0][2] * r[2][0],
179 l[0][0] * r[0][1] + l[0][1] * r[1][1] + l[0][2] * r[2][1],
180 l[0][0] * r[0][2] + l[0][1] * r[1][2] + l[0][2] * r[2][2],
181 ],
182 [
183 l[1][0] * r[0][0] + l[1][1] * r[1][0] + l[1][2] * r[2][0],
184 l[1][0] * r[0][1] + l[1][1] * r[1][1] + l[1][2] * r[2][1],
185 l[1][0] * r[0][2] + l[1][1] * r[1][2] + l[1][2] * r[2][2],
186 ],
187 [
188 l[2][0] * r[0][0] + l[2][1] * r[1][0] + l[2][2] * r[2][0],
189 l[2][0] * r[0][1] + l[2][1] * r[1][1] + l[2][2] * r[2][1],
190 l[2][0] * r[0][2] + l[2][1] * r[1][2] + l[2][2] * r[2][2],
191 ],
192 ]
193}
194
195#[inline(always)]
196fn inverse<T>(m: &[[T; 3]; 3]) -> [[T; 3]; 3]
197where
198 T: Add<Output = T> + Mul<Output = T> + Sub<Output = T> + Div<Output = T> + Copy,
199{
200 let det =
201 m[0][0] * m[1][1] * m[2][2] + m[0][1] * m[1][2] * m[2][0] + m[0][2] * m[1][0] * m[2][1]
202 - m[0][2] * m[1][1] * m[2][0]
203 - m[0][1] * m[1][0] * m[2][2]
204 - m[0][0] * m[1][2] * m[2][1];
205
206 [
207 [
208 (m[1][1] * m[2][2] - m[1][2] * m[2][1]) / det,
209 (m[0][2] * m[2][1] - m[0][1] * m[2][2]) / det,
210 (m[0][1] * m[1][2] - m[0][2] * m[1][1]) / det,
211 ],
212 [
213 (m[1][2] * m[2][0] - m[1][0] * m[2][2]) / det,
214 (m[0][0] * m[2][2] - m[0][2] * m[2][0]) / det,
215 (m[0][2] * m[1][0] - m[0][0] * m[1][2]) / det,
216 ],
217 [
218 (m[1][0] * m[2][1] - m[1][1] * m[2][0]) / det,
219 (m[0][1] * m[2][0] - m[0][0] * m[2][1]) / det,
220 (m[0][0] * m[1][1] - m[0][1] * m[1][0]) / det,
221 ],
222 ]
223}