1#[cfg(feature = "approx")]
2use approx::{AbsDiffEq, RelativeEq, UlpsEq};
3use core::ops::{Mul, MulAssign};
4use glam::{DAffine3, DMat3, DMat4, DQuat, DVec3};
5
6use crate::macros::glam_assert;
7
8#[repr(C)]
9#[derive(Debug, Default, Clone, Copy, PartialEq)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11#[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
12pub struct DTransform3 {
13 pub translation: DVec3,
14 pub rotation: DQuat,
15 pub scale: DVec3,
16}
17
18impl DTransform3 {
19 pub const ZERO: Self = Self {
24 translation: DVec3::ZERO,
25 rotation: DQuat::IDENTITY,
26 scale: DVec3::ONE,
27 };
28
29 pub const IDENTITY: Self = Self {
33 translation: DVec3::ZERO,
34 rotation: DQuat::IDENTITY,
35 scale: DVec3::ONE,
36 };
37
38 pub const NAN: Self = Self {
40 translation: DVec3::NAN,
41 rotation: DQuat::NAN,
42 scale: DVec3::NAN,
43 };
44
45 #[inline]
47 #[must_use]
48 pub fn new(translation: DVec3, rotation: DQuat, scale: DVec3) -> Self {
49 Self {
50 translation,
51 rotation,
52 scale,
53 }
54 }
55
56 #[inline]
59 #[must_use]
60 pub fn from_scale(scale: DVec3) -> Self {
61 Self {
62 translation: DVec3::ZERO,
63 rotation: DQuat::IDENTITY,
64 scale,
65 }
66 }
67
68 #[inline]
70 #[must_use]
71 pub fn from_quat(rotation: DQuat) -> Self {
72 Self {
73 translation: DVec3::ZERO,
74 rotation,
75 scale: DVec3::ONE,
76 }
77 }
78
79 #[inline]
82 #[must_use]
83 pub fn from_axis_angle(axis: DVec3, angle: f64) -> Self {
84 Self {
85 translation: DVec3::ZERO,
86 rotation: DQuat::from_axis_angle(axis, angle),
87 scale: DVec3::ONE,
88 }
89 }
90
91 #[inline]
94 #[must_use]
95 pub fn from_rotation_x(angle: f64) -> Self {
96 Self {
97 translation: DVec3::ZERO,
98 rotation: DQuat::from_rotation_x(angle),
99 scale: DVec3::ONE,
100 }
101 }
102
103 #[inline]
106 #[must_use]
107 pub fn from_rotation_y(angle: f64) -> Self {
108 Self {
109 translation: DVec3::ZERO,
110 rotation: DQuat::from_rotation_y(angle),
111 scale: DVec3::ONE,
112 }
113 }
114
115 #[inline]
118 #[must_use]
119 pub fn from_rotation_z(angle: f64) -> Self {
120 Self {
121 translation: DVec3::ZERO,
122 rotation: DQuat::from_rotation_z(angle),
123 scale: DVec3::ONE,
124 }
125 }
126
127 #[inline]
129 #[must_use]
130 pub fn from_translation(translation: DVec3) -> Self {
131 Self {
132 translation,
133 rotation: DQuat::IDENTITY,
134 scale: DVec3::ONE,
135 }
136 }
137
138 #[inline]
140 #[must_use]
141 pub fn from_rotation_translation(rotation: DQuat, translation: DVec3) -> Self {
142 Self {
143 translation,
144 rotation,
145 scale: DVec3::ONE,
146 }
147 }
148
149 #[inline]
151 #[must_use]
152 pub fn from_scale_rotation_translation(scale: DVec3, rotation: DQuat, translation: DVec3) -> Self {
153 Self {
154 translation,
155 rotation,
156 scale,
157 }
158 }
159
160 #[inline]
164 #[must_use]
165 pub fn from_mat3(mat3: DMat3) -> Self {
166 Self::from_mat3_translation(mat3, DVec3::ZERO)
167 }
168
169 #[inline]
173 #[must_use]
174 pub fn from_mat3_translation(mat3: DMat3, translation: DVec3) -> Self {
175 use super::math;
176 let det = mat3.determinant();
177 glam_assert!(det != 0.0);
178
179 let scale = DVec3::new(
180 mat3.x_axis.length() * math::signum(det),
181 mat3.y_axis.length(),
182 mat3.z_axis.length(),
183 );
184
185 glam_assert!(scale.cmpne(DVec3::ZERO).all());
186
187 let inv_scale = scale.recip();
188
189 let rotation = DQuat::from_mat3(&DMat3::from_cols(
190 mat3.x_axis * inv_scale.x,
191 mat3.y_axis * inv_scale.y,
192 mat3.z_axis * inv_scale.z,
193 ));
194 Self {
195 translation,
196 rotation,
197 scale,
198 }
199 }
200
201 #[inline]
205 #[must_use]
206 pub fn from_mat4(mat4: DMat4) -> Self {
207 let translation = mat4.w_axis.truncate();
208 Self::from_mat3_translation(DMat3::from_mat4(mat4), translation)
209 }
210
211 #[inline]
213 #[must_use]
214 pub fn to_scale_rotation_translation(&self) -> (DVec3, DQuat, DVec3) {
215 (self.scale, self.rotation, self.translation)
216 }
217
218 #[inline]
220 #[must_use]
221 pub fn transform_point3(&self, rhs: DVec3) -> DVec3 {
222 let scale: DVec3 = self.scale;
223 let translation: DVec3 = self.translation;
224 self.rotation * (rhs * scale) + translation
225 }
226
227 #[inline]
229 #[must_use]
230 pub fn transform_vector3(&self, rhs: DVec3) -> DVec3 {
231 let scale: DVec3 = self.scale;
232 self.rotation * (rhs * scale)
233 }
234
235 #[inline]
239 #[must_use]
240 pub fn is_finite(&self) -> bool {
241 self.translation.is_finite() && self.rotation.is_finite() && self.scale.is_finite()
242 }
243
244 #[inline]
246 #[must_use]
247 pub fn is_nan(&self) -> bool {
248 self.translation.is_nan() && self.rotation.is_nan() && self.scale.is_nan()
249 }
250
251 #[inline]
254 #[must_use]
255 pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f64) -> bool {
256 self.translation.abs_diff_eq(rhs.translation, max_abs_diff)
257 && self.rotation.abs_diff_eq(rhs.rotation, max_abs_diff)
258 && self.scale.abs_diff_eq(rhs.scale, max_abs_diff)
259 }
260
261 #[inline]
265 #[must_use]
266 pub fn inverse(&self) -> Self {
267 let rot = DMat3::from_quat(self.rotation);
268 let mat_inv = DMat3::from_cols(
269 rot.x_axis * self.scale.x,
270 rot.y_axis * self.scale.y,
271 rot.z_axis * self.scale.z,
272 )
273 .inverse();
274 let translation = -(mat_inv * self.translation);
275 DTransform3::from_mat3_translation(mat_inv, translation)
276 }
277}
278
279impl From<DTransform3> for DMat4 {
280 #[inline]
281 fn from(t: DTransform3) -> DMat4 {
282 let mat3 = DMat3::from_quat(t.rotation);
283 DMat4::from_cols(
284 (mat3.x_axis * t.scale.x).extend(0.0),
285 (mat3.y_axis * t.scale.y).extend(0.0),
286 (mat3.z_axis * t.scale.z).extend(0.0),
287 t.translation.extend(1.0),
288 )
289 }
290}
291
292impl From<DTransform3> for DAffine3 {
293 #[inline]
294 fn from(t: DTransform3) -> DAffine3 {
295 DAffine3::from_scale_rotation_translation(t.scale, t.rotation, t.translation)
296 }
297}
298
299impl Mul for DTransform3 {
300 type Output = DTransform3;
301
302 #[inline]
303 fn mul(self, rhs: Self) -> Self::Output {
304 let rot1 = DMat3::from_quat(self.rotation);
305 let mat1 = DMat3::from_cols(
306 rot1.x_axis * self.scale.x,
307 rot1.y_axis * self.scale.y,
308 rot1.z_axis * self.scale.z,
309 );
310 let rot2 = DMat3::from_quat(rhs.rotation);
311 let mat2 = DMat3::from_cols(
312 rot2.x_axis * rhs.scale.x,
313 rot2.y_axis * rhs.scale.y,
314 rot2.z_axis * rhs.scale.z,
315 );
316 let translation = self.rotation * (self.scale * rhs.translation) + self.translation;
317 DTransform3::from_mat3_translation(mat1 * mat2, translation)
318 }
319}
320
321impl MulAssign for DTransform3 {
322 #[inline]
323 fn mul_assign(&mut self, rhs: DTransform3) {
324 *self = self.mul(rhs);
325 }
326}
327
328impl Mul<DMat4> for DTransform3 {
329 type Output = DMat4;
330
331 #[inline]
332 fn mul(self, rhs: DMat4) -> Self::Output {
333 DMat4::from(self) * rhs
334 }
335}
336
337impl Mul<DTransform3> for DMat4 {
338 type Output = DMat4;
339
340 #[inline]
341 fn mul(self, rhs: DTransform3) -> Self::Output {
342 self * DMat4::from(rhs)
343 }
344}
345
346#[cfg(feature = "approx")]
347impl AbsDiffEq for DTransform3 {
348 type Epsilon = <f64 as AbsDiffEq>::Epsilon;
349
350 #[inline]
351 fn default_epsilon() -> Self::Epsilon {
352 f64::default_epsilon()
353 }
354
355 #[inline]
356 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
357 self.translation.abs_diff_eq(other.translation, epsilon)
358 && self.rotation.abs_diff_eq(other.rotation, epsilon)
359 && self.scale.abs_diff_eq(other.scale, epsilon)
360 }
361}
362
363#[cfg(feature = "approx")]
364impl RelativeEq for DTransform3 {
365 #[inline]
366 fn default_max_relative() -> Self::Epsilon {
367 f64::default_max_relative()
368 }
369
370 #[inline]
371 fn relative_eq(&self, other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon) -> bool {
372 self.translation.relative_eq(&other.translation, epsilon, max_relative)
373 && self.rotation.relative_eq(&other.rotation, epsilon, max_relative)
374 && self.scale.relative_eq(&other.scale, epsilon, max_relative)
375 }
376}
377
378#[cfg(feature = "approx")]
379impl UlpsEq for DTransform3 {
380 #[inline]
381 fn default_max_ulps() -> u32 {
382 f64::default_max_ulps()
383 }
384
385 #[inline]
386 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
387 self.translation.ulps_eq(&other.translation, epsilon, max_ulps)
388 && self.rotation.ulps_eq(&other.rotation, epsilon, max_ulps)
389 && self.scale.ulps_eq(&other.scale, epsilon, max_ulps)
390 }
391}
392
393#[cfg(test)]
394mod test {
395 use super::*;
396
397 #[test]
398 fn test_from_mat4() {
399 let scale = DVec3::new(0.5, 1.0, 2.0);
400 let rot = DQuat::from_rotation_y(-0.6);
401 let pos = DVec3::new(1.0, -2.0, 3.0);
402 let mat = DMat4::from_scale_rotation_translation(scale, rot, pos);
403 let tran = DTransform3::from_mat4(mat);
404 assert!(DVec3::abs_diff_eq(tran.scale, scale, 1e-6));
405 assert!(DQuat::abs_diff_eq(tran.rotation, rot, 1e-6));
406 assert!(DVec3::abs_diff_eq(tran.translation, pos, 1e-6));
407 }
408
409 #[test]
410 fn test_transform_point3() {
411 let scale = DVec3::new(1.0, 0.7, 0.5);
412 let rot = DQuat::from_rotation_x(0.41);
413 let pos = DVec3::new(1.1, 2.1, -3.1);
414 let mat = DMat4::from_scale_rotation_translation(scale, rot, pos);
415 let tran = DTransform3::from_mat4(mat);
416
417 let point = DVec3::new(5.0, -5.0, 5.0);
418 let p1 = mat.project_point3(point);
419 let p2 = tran.transform_point3(point);
420 assert!(DVec3::abs_diff_eq(p1, p2, 1e-6));
421 }
422
423 #[test]
424 fn test_transform_vec3() {
425 let scale = DVec3::new(2.0, 2.0, 0.35);
426 let rot = DQuat::from_rotation_z(-0.2);
427 let pos = DVec3::new(-1.5, 2.5, 4.5);
428 let mat = DMat4::from_scale_rotation_translation(scale, rot, pos);
429 let tran = DTransform3::from_mat4(mat);
430
431 let vec = DVec3::new(1.0, 0.0, 0.7);
432 let v1 = mat.transform_vector3(vec);
433 let v2 = tran.transform_vector3(vec);
434 assert!(DVec3::abs_diff_eq(v1, v2, 1e-6));
435 }
436
437 #[test]
438 fn test_inverse() {
439 let scale = DVec3::new(2.0, 1.7, 0.35);
440 let rot = DQuat::from_rotation_z(1.5) * DQuat::from_rotation_x(1.0);
441 let pos = DVec3::new(1.99, 0.77, -1.55);
442 let mat = DMat4::from_scale_rotation_translation(scale, rot, pos);
443 let mat_inv = mat.inverse();
444 let tran1 = DTransform3::from_mat4(mat).inverse();
445 let tran2 = DTransform3::from_mat4(mat_inv);
446 assert!(DTransform3::abs_diff_eq(tran1, tran2, 1e-6));
447 }
448
449 #[test]
450 fn test_mat4_from() {
451 let scale = DVec3::new(3.1, 0.7, 1.11);
452 let rot = DQuat::from_rotation_y(-2.0);
453 let pos = DVec3::new(3.0, 3.3, 3.33);
454 let mat = DMat4::from_scale_rotation_translation(scale, rot, pos);
455 let is = DTransform3::from_mat4(mat);
456 let mat2 = DMat4::from(is);
457 assert!(DMat4::abs_diff_eq(&mat, mat2, 1e-6));
458 }
459
460 #[test]
461 fn test_transform_mul() {
462 let scale1 = DVec3::new(1.1, 1.4, 1.7);
463 let rot1 = DQuat::from_rotation_x(0.77);
464 let pos1 = DVec3::new(5.5, -6.6, 3.3);
465 let mat1 = DMat4::from_scale_rotation_translation(scale1, rot1, pos1);
466 let tran1 = DTransform3::from_scale_rotation_translation(scale1, rot1, pos1);
467
468 let scale2 = DVec3::new(0.3, 1.0, 0.7);
469 let rot2 = DQuat::from_rotation_y(-0.44);
470 let pos2 = DVec3::new(-4.4, -2.2, -3.3);
471 let mat2 = DMat4::from_scale_rotation_translation(scale2, rot2, pos2);
472 let tran2 = DTransform3::from_scale_rotation_translation(scale2, rot2, pos2);
473
474 let mat = mat1 * mat2;
475 let tran = tran1 * tran2;
476 let tran_mat = DTransform3::from_mat4(mat);
477 assert!(DTransform3::abs_diff_eq(tran, tran_mat, 1e-6));
478 }
479}