1use crate::{DMat3, DMat4, DQuat, DVec3};
4use core::ops::{Deref, DerefMut, Mul, MulAssign};
5
6#[cfg(feature = "zerocopy-08")]
7use zerocopy_derive_08::*;
8
9#[derive(Copy, Clone)]
11#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
12#[cfg_attr(
13 feature = "zerocopy-08",
14 derive(FromBytes, Immutable, IntoBytes, KnownLayout)
15)]
16#[repr(C)]
17pub struct DAffine3 {
18 pub matrix3: DMat3,
19 pub translation: DVec3,
20}
21
22impl DAffine3 {
23 pub const ZERO: Self = Self {
28 matrix3: DMat3::ZERO,
29 translation: DVec3::ZERO,
30 };
31
32 pub const IDENTITY: Self = Self {
36 matrix3: DMat3::IDENTITY,
37 translation: DVec3::ZERO,
38 };
39
40 pub const NAN: Self = Self {
42 matrix3: DMat3::NAN,
43 translation: DVec3::NAN,
44 };
45
46 #[inline(always)]
48 #[must_use]
49 pub const fn from_cols(x_axis: DVec3, y_axis: DVec3, z_axis: DVec3, w_axis: DVec3) -> Self {
50 Self {
51 matrix3: DMat3::from_cols(x_axis, y_axis, z_axis),
52 translation: w_axis,
53 }
54 }
55
56 #[inline]
58 #[must_use]
59 pub fn from_cols_array(m: &[f64; 12]) -> Self {
60 Self {
61 matrix3: DMat3::from_cols_array(&[
62 m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8],
63 ]),
64 translation: DVec3::from_array([m[9], m[10], m[11]]),
65 }
66 }
67
68 #[inline]
70 #[must_use]
71 pub fn to_cols_array(&self) -> [f64; 12] {
72 let x = &self.matrix3.x_axis;
73 let y = &self.matrix3.y_axis;
74 let z = &self.matrix3.z_axis;
75 let w = &self.translation;
76 [x.x, x.y, x.z, y.x, y.y, y.z, z.x, z.y, z.z, w.x, w.y, w.z]
77 }
78
79 #[inline]
84 #[must_use]
85 pub fn from_cols_array_2d(m: &[[f64; 3]; 4]) -> Self {
86 Self {
87 matrix3: DMat3::from_cols(m[0].into(), m[1].into(), m[2].into()),
88 translation: m[3].into(),
89 }
90 }
91
92 #[inline]
96 #[must_use]
97 pub fn to_cols_array_2d(&self) -> [[f64; 3]; 4] {
98 [
99 self.matrix3.x_axis.into(),
100 self.matrix3.y_axis.into(),
101 self.matrix3.z_axis.into(),
102 self.translation.into(),
103 ]
104 }
105
106 #[inline]
112 #[must_use]
113 pub fn from_cols_slice(slice: &[f64]) -> Self {
114 Self {
115 matrix3: DMat3::from_cols_slice(&slice[0..9]),
116 translation: DVec3::from_slice(&slice[9..12]),
117 }
118 }
119
120 #[inline]
126 pub fn write_cols_to_slice(&self, slice: &mut [f64]) {
127 self.matrix3.write_cols_to_slice(&mut slice[0..9]);
128 self.translation.write_to_slice(&mut slice[9..12]);
129 }
130
131 #[inline]
134 #[must_use]
135 pub fn from_scale(scale: DVec3) -> Self {
136 Self {
137 matrix3: DMat3::from_diagonal(scale),
138 translation: DVec3::ZERO,
139 }
140 }
141 #[inline]
147 #[must_use]
148 #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
149 pub fn from_quat(rotation: DQuat) -> Self {
150 Self {
151 matrix3: DMat3::from_quat(rotation),
152 translation: DVec3::ZERO,
153 }
154 }
155
156 #[inline]
163 #[must_use]
164 #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
165 pub fn from_axis_angle(axis: DVec3, angle: f64) -> Self {
166 Self {
167 matrix3: DMat3::from_axis_angle(axis, angle),
168 translation: DVec3::ZERO,
169 }
170 }
171
172 #[inline]
175 #[must_use]
176 pub fn from_rotation_x(angle: f64) -> Self {
177 Self {
178 matrix3: DMat3::from_rotation_x(angle),
179 translation: DVec3::ZERO,
180 }
181 }
182
183 #[inline]
186 #[must_use]
187 pub fn from_rotation_y(angle: f64) -> Self {
188 Self {
189 matrix3: DMat3::from_rotation_y(angle),
190 translation: DVec3::ZERO,
191 }
192 }
193
194 #[inline]
197 #[must_use]
198 pub fn from_rotation_z(angle: f64) -> Self {
199 Self {
200 matrix3: DMat3::from_rotation_z(angle),
201 translation: DVec3::ZERO,
202 }
203 }
204
205 #[inline]
207 #[must_use]
208 pub fn from_translation(translation: DVec3) -> Self {
209 #[allow(clippy::useless_conversion)]
210 Self {
211 matrix3: DMat3::IDENTITY,
212 translation: translation.into(),
213 }
214 }
215
216 #[inline]
219 #[must_use]
220 pub fn from_mat3(mat3: DMat3) -> Self {
221 #[allow(clippy::useless_conversion)]
222 Self {
223 matrix3: mat3.into(),
224 translation: DVec3::ZERO,
225 }
226 }
227
228 #[inline]
233 #[must_use]
234 pub fn from_mat3_translation(mat3: DMat3, translation: DVec3) -> Self {
235 #[allow(clippy::useless_conversion)]
236 Self {
237 matrix3: mat3.into(),
238 translation: translation.into(),
239 }
240 }
241
242 #[inline]
252 #[must_use]
253 #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
254 pub fn from_scale_rotation_translation(
255 scale: DVec3,
256 rotation: DQuat,
257 translation: DVec3,
258 ) -> Self {
259 let rotation = DMat3::from_quat(rotation);
260 #[allow(clippy::useless_conversion)]
261 Self {
262 matrix3: DMat3::from_cols(
263 rotation.x_axis * scale.x,
264 rotation.y_axis * scale.y,
265 rotation.z_axis * scale.z,
266 ),
267 translation: translation.into(),
268 }
269 }
270
271 #[inline]
279 #[must_use]
280 #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
281 pub fn from_rotation_translation(rotation: DQuat, translation: DVec3) -> Self {
282 #[allow(clippy::useless_conversion)]
283 Self {
284 matrix3: DMat3::from_quat(rotation),
285 translation: translation.into(),
286 }
287 }
288
289 #[inline]
292 #[must_use]
293 pub fn from_mat4(m: DMat4) -> Self {
294 Self {
295 matrix3: DMat3::from_cols(
296 DVec3::from_vec4(m.x_axis),
297 DVec3::from_vec4(m.y_axis),
298 DVec3::from_vec4(m.z_axis),
299 ),
300 translation: DVec3::from_vec4(m.w_axis),
301 }
302 }
303
304 #[inline]
314 #[must_use]
315 #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
316 pub fn to_scale_rotation_translation(&self) -> (DVec3, DQuat, DVec3) {
317 let det = self.matrix3.determinant();
318 glam_assert!(det != 0.0);
319
320 let scale = DVec3::new(
321 self.matrix3.x_axis.length() * det.signum(),
322 self.matrix3.y_axis.length(),
323 self.matrix3.z_axis.length(),
324 );
325
326 glam_assert!(scale.cmpne(DVec3::ZERO).all());
327
328 let inv_scale = scale.recip();
329
330 #[allow(clippy::useless_conversion)]
331 let rotation = DQuat::from_mat3(&DMat3::from_cols(
332 (self.matrix3.x_axis * inv_scale.x).into(),
333 (self.matrix3.y_axis * inv_scale.y).into(),
334 (self.matrix3.z_axis * inv_scale.z).into(),
335 ));
336
337 #[allow(clippy::useless_conversion)]
338 (scale, rotation, self.translation.into())
339 }
340
341 #[inline]
343 pub fn transform_point3(&self, rhs: DVec3) -> DVec3 {
344 #[allow(clippy::useless_conversion)]
345 ((self.matrix3.x_axis * rhs.x)
346 + (self.matrix3.y_axis * rhs.y)
347 + (self.matrix3.z_axis * rhs.z)
348 + self.translation)
349 .into()
350 }
351
352 #[inline]
357 #[must_use]
358 pub fn transform_vector3(&self, rhs: DVec3) -> DVec3 {
359 #[allow(clippy::useless_conversion)]
360 ((self.matrix3.x_axis * rhs.x)
361 + (self.matrix3.y_axis * rhs.y)
362 + (self.matrix3.z_axis * rhs.z))
363 .into()
364 }
365
366 #[inline]
371 #[must_use]
372 pub fn is_finite(&self) -> bool {
373 self.matrix3.is_finite() && self.translation.is_finite()
374 }
375
376 #[inline]
378 #[must_use]
379 pub fn is_nan(&self) -> bool {
380 self.matrix3.is_nan() || self.translation.is_nan()
381 }
382
383 #[inline]
393 #[must_use]
394 pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f64) -> bool {
395 self.matrix3.abs_diff_eq(rhs.matrix3, max_abs_diff)
396 && self.translation.abs_diff_eq(rhs.translation, max_abs_diff)
397 }
398
399 #[inline]
407 #[must_use]
408 #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
409 pub fn inverse(&self) -> Self {
410 let matrix3 = self.matrix3.inverse();
411 let translation = -(matrix3 * self.translation);
413
414 Self {
415 matrix3,
416 translation,
417 }
418 }
419
420 #[inline]
422 #[must_use]
423 pub fn as_affine3(&self) -> crate::Affine3 {
424 crate::Affine3::from_mat3_translation(self.matrix3.as_mat3(), self.translation.as_vec3())
425 }
426
427 #[inline]
429 #[must_use]
430 pub fn as_affine3a(&self) -> crate::Affine3A {
431 crate::Affine3A::from_mat3_translation(self.matrix3.as_mat3(), self.translation.as_vec3())
432 }
433}
434
435impl Default for DAffine3 {
436 #[inline(always)]
437 fn default() -> Self {
438 Self::IDENTITY
439 }
440}
441
442impl Deref for DAffine3 {
443 type Target = crate::deref::Cols4<DVec3>;
444 #[inline(always)]
445 fn deref(&self) -> &Self::Target {
446 unsafe { &*(self as *const Self as *const Self::Target) }
447 }
448}
449
450impl DerefMut for DAffine3 {
451 #[inline(always)]
452 fn deref_mut(&mut self) -> &mut Self::Target {
453 unsafe { &mut *(self as *mut Self as *mut Self::Target) }
454 }
455}
456
457impl PartialEq for DAffine3 {
458 #[inline]
459 fn eq(&self, rhs: &Self) -> bool {
460 self.matrix3.eq(&rhs.matrix3) && self.translation.eq(&rhs.translation)
461 }
462}
463
464impl core::fmt::Debug for DAffine3 {
465 fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
466 fmt.debug_struct(stringify!(DAffine3))
467 .field("matrix3", &self.matrix3)
468 .field("translation", &self.translation)
469 .finish()
470 }
471}
472
473impl core::fmt::Display for DAffine3 {
474 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
475 if let Some(p) = f.precision() {
476 write!(
477 f,
478 "[{:.*}, {:.*}, {:.*}, {:.*}]",
479 p,
480 self.matrix3.x_axis,
481 p,
482 self.matrix3.y_axis,
483 p,
484 self.matrix3.z_axis,
485 p,
486 self.translation
487 )
488 } else {
489 write!(
490 f,
491 "[{}, {}, {}, {}]",
492 self.matrix3.x_axis, self.matrix3.y_axis, self.matrix3.z_axis, self.translation
493 )
494 }
495 }
496}
497
498impl<'a> core::iter::Product<&'a Self> for DAffine3 {
499 fn product<I>(iter: I) -> Self
500 where
501 I: Iterator<Item = &'a Self>,
502 {
503 iter.fold(Self::IDENTITY, |a, &b| a * b)
504 }
505}
506
507impl Mul for DAffine3 {
508 type Output = Self;
509
510 #[inline]
511 fn mul(self, rhs: Self) -> Self {
512 Self {
513 matrix3: self.matrix3 * rhs.matrix3,
514 translation: self.matrix3 * rhs.translation + self.translation,
515 }
516 }
517}
518
519impl Mul<&Self> for DAffine3 {
520 type Output = Self;
521 #[inline]
522 fn mul(self, rhs: &Self) -> Self {
523 self.mul(*rhs)
524 }
525}
526
527impl Mul<&DAffine3> for &DAffine3 {
528 type Output = DAffine3;
529 #[inline]
530 fn mul(self, rhs: &DAffine3) -> DAffine3 {
531 (*self).mul(*rhs)
532 }
533}
534
535impl Mul<DAffine3> for &DAffine3 {
536 type Output = DAffine3;
537 #[inline]
538 fn mul(self, rhs: DAffine3) -> DAffine3 {
539 (*self).mul(rhs)
540 }
541}
542
543impl MulAssign for DAffine3 {
544 #[inline]
545 fn mul_assign(&mut self, rhs: Self) {
546 *self = self.mul(rhs);
547 }
548}
549
550impl MulAssign<&Self> for DAffine3 {
551 #[inline]
552 fn mul_assign(&mut self, rhs: &Self) {
553 self.mul_assign(*rhs);
554 }
555}
556
557impl Mul<DMat4> for DAffine3 {
558 type Output = DMat4;
559
560 #[inline]
561 fn mul(self, rhs: DMat4) -> Self::Output {
562 DMat4::from(self) * rhs
563 }
564}
565
566impl Mul<&DMat4> for DAffine3 {
567 type Output = DMat4;
568 #[inline]
569 fn mul(self, rhs: &DMat4) -> DMat4 {
570 self.mul(*rhs)
571 }
572}
573
574impl Mul<&DMat4> for &DAffine3 {
575 type Output = DMat4;
576 #[inline]
577 fn mul(self, rhs: &DMat4) -> DMat4 {
578 (*self).mul(*rhs)
579 }
580}
581
582impl Mul<DMat4> for &DAffine3 {
583 type Output = DMat4;
584 #[inline]
585 fn mul(self, rhs: DMat4) -> DMat4 {
586 (*self).mul(rhs)
587 }
588}
589
590impl Mul<DAffine3> for DMat4 {
591 type Output = Self;
592
593 #[inline]
594 fn mul(self, rhs: DAffine3) -> Self {
595 self * Self::from(rhs)
596 }
597}
598
599impl Mul<&DAffine3> for DMat4 {
600 type Output = Self;
601 #[inline]
602 fn mul(self, rhs: &DAffine3) -> Self {
603 self.mul(*rhs)
604 }
605}
606
607impl Mul<&DAffine3> for &DMat4 {
608 type Output = DMat4;
609 #[inline]
610 fn mul(self, rhs: &DAffine3) -> DMat4 {
611 (*self).mul(*rhs)
612 }
613}
614
615impl Mul<DAffine3> for &DMat4 {
616 type Output = DMat4;
617 #[inline]
618 fn mul(self, rhs: DAffine3) -> DMat4 {
619 (*self).mul(rhs)
620 }
621}
622
623impl MulAssign<DAffine3> for DMat4 {
624 #[inline]
625 fn mul_assign(&mut self, rhs: DAffine3) {
626 *self = self.mul(rhs);
627 }
628}
629
630impl MulAssign<&DAffine3> for DMat4 {
631 #[inline]
632 fn mul_assign(&mut self, rhs: &DAffine3) {
633 self.mul_assign(*rhs);
634 }
635}
636
637impl From<DAffine3> for DMat4 {
638 #[inline]
639 fn from(m: DAffine3) -> Self {
640 Self::from_cols(
641 m.matrix3.x_axis.extend(0.0),
642 m.matrix3.y_axis.extend(0.0),
643 m.matrix3.z_axis.extend(0.0),
644 m.translation.extend(1.0),
645 )
646 }
647}