1use core::ops::{Mul, MulAssign};
2use glam::{DAffine3, DMat3, DMat4, DQuat, DVec3};
3
4use crate::macros::glam_assert;
5
6#[repr(C)]
7#[derive(Debug, Default, Clone, Copy, PartialEq)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9#[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
10pub struct DTransform3 {
11 pub translation: DVec3,
12 pub rotation: DQuat,
13 pub scale: DVec3,
14}
15
16impl DTransform3 {
17 pub const ZERO: Self = Self {
22 translation: DVec3::ZERO,
23 rotation: DQuat::IDENTITY,
24 scale: DVec3::ONE,
25 };
26
27 pub const IDENTITY: Self = Self {
31 translation: DVec3::ZERO,
32 rotation: DQuat::IDENTITY,
33 scale: DVec3::ONE,
34 };
35
36 pub const NAN: Self = Self {
38 translation: DVec3::NAN,
39 rotation: DQuat::NAN,
40 scale: DVec3::NAN,
41 };
42
43 #[inline]
45 #[must_use]
46 pub fn new(translation: DVec3, rotation: DQuat, scale: DVec3) -> Self {
47 Self {
48 translation,
49 rotation,
50 scale,
51 }
52 }
53
54 #[inline]
57 #[must_use]
58 pub fn from_scale(scale: DVec3) -> Self {
59 Self {
60 translation: DVec3::ZERO,
61 rotation: DQuat::IDENTITY,
62 scale,
63 }
64 }
65
66 #[inline]
68 #[must_use]
69 pub fn from_quat(rotation: DQuat) -> Self {
70 Self {
71 translation: DVec3::ZERO,
72 rotation,
73 scale: DVec3::ONE,
74 }
75 }
76
77 #[inline]
80 #[must_use]
81 pub fn from_axis_angle(axis: DVec3, angle: f64) -> Self {
82 Self {
83 translation: DVec3::ZERO,
84 rotation: DQuat::from_axis_angle(axis, angle),
85 scale: DVec3::ONE,
86 }
87 }
88
89 #[inline]
92 #[must_use]
93 pub fn from_rotation_x(angle: f64) -> Self {
94 Self {
95 translation: DVec3::ZERO,
96 rotation: DQuat::from_rotation_x(angle),
97 scale: DVec3::ONE,
98 }
99 }
100
101 #[inline]
104 #[must_use]
105 pub fn from_rotation_y(angle: f64) -> Self {
106 Self {
107 translation: DVec3::ZERO,
108 rotation: DQuat::from_rotation_y(angle),
109 scale: DVec3::ONE,
110 }
111 }
112
113 #[inline]
116 #[must_use]
117 pub fn from_rotation_z(angle: f64) -> Self {
118 Self {
119 translation: DVec3::ZERO,
120 rotation: DQuat::from_rotation_z(angle),
121 scale: DVec3::ONE,
122 }
123 }
124
125 #[inline]
127 #[must_use]
128 pub fn from_translation(translation: DVec3) -> Self {
129 Self {
130 translation,
131 rotation: DQuat::IDENTITY,
132 scale: DVec3::ONE,
133 }
134 }
135
136 #[inline]
138 #[must_use]
139 pub fn from_rotation_translation(rotation: DQuat, translation: DVec3) -> Self {
140 Self {
141 translation,
142 rotation,
143 scale: DVec3::ONE,
144 }
145 }
146
147 #[inline]
149 #[must_use]
150 pub fn from_scale_rotation_translation(scale: DVec3, rotation: DQuat, translation: DVec3) -> Self {
151 Self {
152 translation,
153 rotation,
154 scale,
155 }
156 }
157
158 #[inline]
162 #[must_use]
163 pub fn from_mat3(mat3: DMat3) -> Self {
164 Self::from_mat3_translation(mat3, DVec3::ZERO)
165 }
166
167 #[inline]
171 #[must_use]
172 pub fn from_mat3_translation(mat3: DMat3, translation: DVec3) -> Self {
173 use super::math;
174 let det = mat3.determinant();
175 glam_assert!(det != 0.0);
176
177 let scale = DVec3::new(
178 mat3.x_axis.length() * math::signum(det),
179 mat3.y_axis.length(),
180 mat3.z_axis.length(),
181 );
182
183 glam_assert!(scale.cmpne(DVec3::ZERO).all());
184
185 let inv_scale = scale.recip();
186
187 let rotation = DQuat::from_mat3(&DMat3::from_cols(
188 mat3.x_axis * inv_scale.x,
189 mat3.y_axis * inv_scale.y,
190 mat3.z_axis * inv_scale.z,
191 ));
192 Self {
193 translation,
194 rotation,
195 scale,
196 }
197 }
198
199 #[inline]
203 #[must_use]
204 pub fn from_mat4(mat4: DMat4) -> Self {
205 let translation = mat4.w_axis.truncate();
206 Self::from_mat3_translation(DMat3::from_mat4(mat4), translation)
207 }
208
209 #[inline]
211 #[must_use]
212 pub fn to_scale_rotation_translation(&self) -> (DVec3, DQuat, DVec3) {
213 (self.scale, self.rotation, self.translation)
214 }
215
216 #[inline]
218 #[must_use]
219 pub fn transform_point3(&self, rhs: DVec3) -> DVec3 {
220 let scale: DVec3 = self.scale;
221 let translation: DVec3 = self.translation;
222 self.rotation * (rhs * scale) + translation
223 }
224
225 #[inline]
227 #[must_use]
228 pub fn transform_vector3(&self, rhs: DVec3) -> DVec3 {
229 let scale: DVec3 = self.scale;
230 self.rotation * (rhs * scale)
231 }
232
233 #[inline]
237 #[must_use]
238 pub fn is_finite(&self) -> bool {
239 self.translation.is_finite() && self.rotation.is_finite() && self.scale.is_finite()
240 }
241
242 #[inline]
244 #[must_use]
245 pub fn is_nan(&self) -> bool {
246 self.translation.is_nan() && self.rotation.is_nan() && self.scale.is_nan()
247 }
248
249 #[inline]
252 #[must_use]
253 pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f64) -> bool {
254 self.translation.abs_diff_eq(rhs.translation, max_abs_diff)
255 && self.rotation.abs_diff_eq(rhs.rotation, max_abs_diff)
256 && self.scale.abs_diff_eq(rhs.scale, max_abs_diff)
257 }
258
259 #[inline]
263 #[must_use]
264 pub fn inverse(&self) -> Self {
265 let rot = DMat3::from_quat(self.rotation);
266 let mat_inv = DMat3::from_cols(
267 rot.x_axis * self.scale.x,
268 rot.y_axis * self.scale.y,
269 rot.z_axis * self.scale.z,
270 )
271 .inverse();
272 let translation = -(mat_inv * self.translation);
273 DTransform3::from_mat3_translation(mat_inv, translation)
274 }
275}
276
277impl From<DTransform3> for DMat4 {
278 #[inline]
279 fn from(t: DTransform3) -> DMat4 {
280 let mat3 = DMat3::from_quat(t.rotation);
281 DMat4::from_cols(
282 (mat3.x_axis * t.scale.x).extend(0.0),
283 (mat3.y_axis * t.scale.y).extend(0.0),
284 (mat3.z_axis * t.scale.z).extend(0.0),
285 t.translation.extend(1.0),
286 )
287 }
288}
289
290impl From<DTransform3> for DAffine3 {
291 #[inline]
292 fn from(t: DTransform3) -> DAffine3 {
293 DAffine3::from_scale_rotation_translation(t.scale, t.rotation, t.translation)
294 }
295}
296
297impl Mul for DTransform3 {
298 type Output = DTransform3;
299
300 #[inline]
301 fn mul(self, rhs: Self) -> Self::Output {
302 let rot1 = DMat3::from_quat(self.rotation);
303 let mat1 = DMat3::from_cols(
304 rot1.x_axis * self.scale.x,
305 rot1.y_axis * self.scale.y,
306 rot1.z_axis * self.scale.z,
307 );
308 let rot2 = DMat3::from_quat(rhs.rotation);
309 let mat2 = DMat3::from_cols(
310 rot2.x_axis * rhs.scale.x,
311 rot2.y_axis * rhs.scale.y,
312 rot2.z_axis * rhs.scale.z,
313 );
314 let translation = self.rotation * (self.scale * rhs.translation) + self.translation;
315 DTransform3::from_mat3_translation(mat1 * mat2, translation)
316 }
317}
318
319impl MulAssign for DTransform3 {
320 #[inline]
321 fn mul_assign(&mut self, rhs: DTransform3) {
322 *self = self.mul(rhs);
323 }
324}
325
326impl Mul<DMat4> for DTransform3 {
327 type Output = DMat4;
328
329 #[inline]
330 fn mul(self, rhs: DMat4) -> Self::Output {
331 DMat4::from(self) * rhs
332 }
333}
334
335impl Mul<DTransform3> for DMat4 {
336 type Output = DMat4;
337
338 #[inline]
339 fn mul(self, rhs: DTransform3) -> Self::Output {
340 self * DMat4::from(rhs)
341 }
342}
343
344#[cfg(test)]
345mod test {
346 use super::*;
347
348 #[test]
349 fn test_from_mat4() {
350 let scale = DVec3::new(0.5, 1.0, 2.0);
351 let rot = DQuat::from_rotation_y(-0.6);
352 let pos = DVec3::new(1.0, -2.0, 3.0);
353 let mat = DMat4::from_scale_rotation_translation(scale, rot, pos);
354 let tran = DTransform3::from_mat4(mat);
355 assert!(DVec3::abs_diff_eq(tran.scale, scale, 1e-6));
356 assert!(DQuat::abs_diff_eq(tran.rotation, rot, 1e-6));
357 assert!(DVec3::abs_diff_eq(tran.translation, pos, 1e-6));
358 }
359
360 #[test]
361 fn test_transform_point3() {
362 let scale = DVec3::new(1.0, 0.7, 0.5);
363 let rot = DQuat::from_rotation_x(0.41);
364 let pos = DVec3::new(1.1, 2.1, -3.1);
365 let mat = DMat4::from_scale_rotation_translation(scale, rot, pos);
366 let tran = DTransform3::from_mat4(mat);
367
368 let point = DVec3::new(5.0, -5.0, 5.0);
369 let p1 = mat.project_point3(point);
370 let p2 = tran.transform_point3(point);
371 assert!(DVec3::abs_diff_eq(p1, p2, 1e-6));
372 }
373
374 #[test]
375 fn test_transform_vec3() {
376 let scale = DVec3::new(2.0, 2.0, 0.35);
377 let rot = DQuat::from_rotation_z(-0.2);
378 let pos = DVec3::new(-1.5, 2.5, 4.5);
379 let mat = DMat4::from_scale_rotation_translation(scale, rot, pos);
380 let tran = DTransform3::from_mat4(mat);
381
382 let vec = DVec3::new(1.0, 0.0, 0.7);
383 let v1 = mat.transform_vector3(vec);
384 let v2 = tran.transform_vector3(vec);
385 assert!(DVec3::abs_diff_eq(v1, v2, 1e-6));
386 }
387
388 #[test]
389 fn test_inverse() {
390 let scale = DVec3::new(2.0, 1.7, 0.35);
391 let rot = DQuat::from_rotation_z(1.5) * DQuat::from_rotation_x(1.0);
392 let pos = DVec3::new(1.99, 0.77, -1.55);
393 let mat = DMat4::from_scale_rotation_translation(scale, rot, pos);
394 let mat_inv = mat.inverse();
395 let tran1 = DTransform3::from_mat4(mat).inverse();
396 let tran2 = DTransform3::from_mat4(mat_inv);
397 assert!(DTransform3::abs_diff_eq(tran1, tran2, 1e-6));
398 }
399
400 #[test]
401 fn test_mat4_from() {
402 let scale = DVec3::new(3.1, 0.7, 1.11);
403 let rot = DQuat::from_rotation_y(-2.0);
404 let pos = DVec3::new(3.0, 3.3, 3.33);
405 let mat = DMat4::from_scale_rotation_translation(scale, rot, pos);
406 let is = DTransform3::from_mat4(mat);
407 let mat2 = DMat4::from(is);
408 assert!(DMat4::abs_diff_eq(&mat, mat2, 1e-6));
409 }
410
411 #[test]
412 fn test_transform_mul() {
413 let scale1 = DVec3::new(1.1, 1.4, 1.7);
414 let rot1 = DQuat::from_rotation_x(0.77);
415 let pos1 = DVec3::new(5.5, -6.6, 3.3);
416 let mat1 = DMat4::from_scale_rotation_translation(scale1, rot1, pos1);
417 let tran1 = DTransform3::from_scale_rotation_translation(scale1, rot1, pos1);
418
419 let scale2 = DVec3::new(0.3, 1.0, 0.7);
420 let rot2 = DQuat::from_rotation_y(-0.44);
421 let pos2 = DVec3::new(-4.4, -2.2, -3.3);
422 let mat2 = DMat4::from_scale_rotation_translation(scale2, rot2, pos2);
423 let tran2 = DTransform3::from_scale_rotation_translation(scale2, rot2, pos2);
424
425 let mat = mat1 * mat2;
426 let tran = tran1 * tran2;
427 let tran_mat = DTransform3::from_mat4(mat);
428 assert!(DTransform3::abs_diff_eq(tran, tran_mat, 1e-6));
429 }
430}