glam/f64/
dquat.rs

1// Generated from quat.rs.tera template. Edit the template, not the generated file.
2
3use crate::{
4    euler::{EulerFromQuaternion, EulerRot, EulerToQuaternion},
5    f64::math,
6    DMat3, DMat4, DVec2, DVec3, DVec4, Quat,
7};
8
9#[cfg(not(target_arch = "spirv"))]
10use core::fmt;
11use core::iter::{Product, Sum};
12use core::ops::{Add, Div, Mul, MulAssign, Neg, Sub};
13
14/// Creates a quaternion from `x`, `y`, `z` and `w` values.
15///
16/// This should generally not be called manually unless you know what you are doing. Use
17/// one of the other constructors instead such as `identity` or `from_axis_angle`.
18#[inline]
19#[must_use]
20pub const fn dquat(x: f64, y: f64, z: f64, w: f64) -> DQuat {
21    DQuat::from_xyzw(x, y, z, w)
22}
23
24/// A quaternion representing an orientation.
25///
26/// This quaternion is intended to be of unit length but may denormalize due to
27/// floating point "error creep" which can occur when successive quaternion
28/// operations are applied.
29#[derive(Clone, Copy)]
30#[cfg_attr(not(target_arch = "spirv"), repr(C))]
31#[cfg_attr(target_arch = "spirv", repr(simd))]
32pub struct DQuat {
33    pub x: f64,
34    pub y: f64,
35    pub z: f64,
36    pub w: f64,
37}
38
39impl DQuat {
40    /// All zeros.
41    const ZERO: Self = Self::from_array([0.0; 4]);
42
43    /// The identity quaternion. Corresponds to no rotation.
44    pub const IDENTITY: Self = Self::from_xyzw(0.0, 0.0, 0.0, 1.0);
45
46    /// All NANs.
47    pub const NAN: Self = Self::from_array([f64::NAN; 4]);
48
49    /// Creates a new rotation quaternion.
50    ///
51    /// This should generally not be called manually unless you know what you are doing.
52    /// Use one of the other constructors instead such as `identity` or `from_axis_angle`.
53    ///
54    /// `from_xyzw` is mostly used by unit tests and `serde` deserialization.
55    ///
56    /// # Preconditions
57    ///
58    /// This function does not check if the input is normalized, it is up to the user to
59    /// provide normalized input or to normalized the resulting quaternion.
60    #[inline(always)]
61    #[must_use]
62    pub const fn from_xyzw(x: f64, y: f64, z: f64, w: f64) -> Self {
63        Self { x, y, z, w }
64    }
65
66    /// Creates a rotation quaternion from an array.
67    ///
68    /// # Preconditions
69    ///
70    /// This function does not check if the input is normalized, it is up to the user to
71    /// provide normalized input or to normalized the resulting quaternion.
72    #[inline]
73    #[must_use]
74    pub const fn from_array(a: [f64; 4]) -> Self {
75        Self::from_xyzw(a[0], a[1], a[2], a[3])
76    }
77
78    /// Creates a new rotation quaternion from a 4D vector.
79    ///
80    /// # Preconditions
81    ///
82    /// This function does not check if the input is normalized, it is up to the user to
83    /// provide normalized input or to normalized the resulting quaternion.
84    #[inline]
85    #[must_use]
86    pub const fn from_vec4(v: DVec4) -> Self {
87        Self {
88            x: v.x,
89            y: v.y,
90            z: v.z,
91            w: v.w,
92        }
93    }
94
95    /// Creates a rotation quaternion from a slice.
96    ///
97    /// # Preconditions
98    ///
99    /// This function does not check if the input is normalized, it is up to the user to
100    /// provide normalized input or to normalized the resulting quaternion.
101    ///
102    /// # Panics
103    ///
104    /// Panics if `slice` length is less than 4.
105    #[inline]
106    #[must_use]
107    pub fn from_slice(slice: &[f64]) -> Self {
108        Self::from_xyzw(slice[0], slice[1], slice[2], slice[3])
109    }
110
111    /// Writes the quaternion to an unaligned slice.
112    ///
113    /// # Panics
114    ///
115    /// Panics if `slice` length is less than 4.
116    #[inline]
117    pub fn write_to_slice(self, slice: &mut [f64]) {
118        slice[0] = self.x;
119        slice[1] = self.y;
120        slice[2] = self.z;
121        slice[3] = self.w;
122    }
123
124    /// Create a quaternion for a normalized rotation `axis` and `angle` (in radians).
125    ///
126    /// The axis must be a unit vector.
127    ///
128    /// # Panics
129    ///
130    /// Will panic if `axis` is not normalized when `glam_assert` is enabled.
131    #[inline]
132    #[must_use]
133    pub fn from_axis_angle(axis: DVec3, angle: f64) -> Self {
134        glam_assert!(axis.is_normalized());
135        let (s, c) = math::sin_cos(angle * 0.5);
136        let v = axis * s;
137        Self::from_xyzw(v.x, v.y, v.z, c)
138    }
139
140    /// Create a quaternion that rotates `v.length()` radians around `v.normalize()`.
141    ///
142    /// `from_scaled_axis(Vec3::ZERO)` results in the identity quaternion.
143    #[inline]
144    #[must_use]
145    pub fn from_scaled_axis(v: DVec3) -> Self {
146        let length = v.length();
147        if length == 0.0 {
148            Self::IDENTITY
149        } else {
150            Self::from_axis_angle(v / length, length)
151        }
152    }
153
154    /// Creates a quaternion from the `angle` (in radians) around the x axis.
155    #[inline]
156    #[must_use]
157    pub fn from_rotation_x(angle: f64) -> Self {
158        let (s, c) = math::sin_cos(angle * 0.5);
159        Self::from_xyzw(s, 0.0, 0.0, c)
160    }
161
162    /// Creates a quaternion from the `angle` (in radians) around the y axis.
163    #[inline]
164    #[must_use]
165    pub fn from_rotation_y(angle: f64) -> Self {
166        let (s, c) = math::sin_cos(angle * 0.5);
167        Self::from_xyzw(0.0, s, 0.0, c)
168    }
169
170    /// Creates a quaternion from the `angle` (in radians) around the z axis.
171    #[inline]
172    #[must_use]
173    pub fn from_rotation_z(angle: f64) -> Self {
174        let (s, c) = math::sin_cos(angle * 0.5);
175        Self::from_xyzw(0.0, 0.0, s, c)
176    }
177
178    /// Creates a quaternion from the given Euler rotation sequence and the angles (in radians).
179    #[inline]
180    #[must_use]
181    pub fn from_euler(euler: EulerRot, a: f64, b: f64, c: f64) -> Self {
182        euler.new_quat(a, b, c)
183    }
184
185    /// From the columns of a 3x3 rotation matrix.
186    #[inline]
187    #[must_use]
188    pub(crate) fn from_rotation_axes(x_axis: DVec3, y_axis: DVec3, z_axis: DVec3) -> Self {
189        // Based on https://github.com/microsoft/DirectXMath `XM$quaternionRotationMatrix`
190        let (m00, m01, m02) = x_axis.into();
191        let (m10, m11, m12) = y_axis.into();
192        let (m20, m21, m22) = z_axis.into();
193        if m22 <= 0.0 {
194            // x^2 + y^2 >= z^2 + w^2
195            let dif10 = m11 - m00;
196            let omm22 = 1.0 - m22;
197            if dif10 <= 0.0 {
198                // x^2 >= y^2
199                let four_xsq = omm22 - dif10;
200                let inv4x = 0.5 / math::sqrt(four_xsq);
201                Self::from_xyzw(
202                    four_xsq * inv4x,
203                    (m01 + m10) * inv4x,
204                    (m02 + m20) * inv4x,
205                    (m12 - m21) * inv4x,
206                )
207            } else {
208                // y^2 >= x^2
209                let four_ysq = omm22 + dif10;
210                let inv4y = 0.5 / math::sqrt(four_ysq);
211                Self::from_xyzw(
212                    (m01 + m10) * inv4y,
213                    four_ysq * inv4y,
214                    (m12 + m21) * inv4y,
215                    (m20 - m02) * inv4y,
216                )
217            }
218        } else {
219            // z^2 + w^2 >= x^2 + y^2
220            let sum10 = m11 + m00;
221            let opm22 = 1.0 + m22;
222            if sum10 <= 0.0 {
223                // z^2 >= w^2
224                let four_zsq = opm22 - sum10;
225                let inv4z = 0.5 / math::sqrt(four_zsq);
226                Self::from_xyzw(
227                    (m02 + m20) * inv4z,
228                    (m12 + m21) * inv4z,
229                    four_zsq * inv4z,
230                    (m01 - m10) * inv4z,
231                )
232            } else {
233                // w^2 >= z^2
234                let four_wsq = opm22 + sum10;
235                let inv4w = 0.5 / math::sqrt(four_wsq);
236                Self::from_xyzw(
237                    (m12 - m21) * inv4w,
238                    (m20 - m02) * inv4w,
239                    (m01 - m10) * inv4w,
240                    four_wsq * inv4w,
241                )
242            }
243        }
244    }
245
246    /// Creates a quaternion from a 3x3 rotation matrix.
247    #[inline]
248    #[must_use]
249    pub fn from_mat3(mat: &DMat3) -> Self {
250        Self::from_rotation_axes(mat.x_axis, mat.y_axis, mat.z_axis)
251    }
252
253    /// Creates a quaternion from a 3x3 rotation matrix inside a homogeneous 4x4 matrix.
254    #[inline]
255    #[must_use]
256    pub fn from_mat4(mat: &DMat4) -> Self {
257        Self::from_rotation_axes(
258            mat.x_axis.truncate(),
259            mat.y_axis.truncate(),
260            mat.z_axis.truncate(),
261        )
262    }
263
264    /// Gets the minimal rotation for transforming `from` to `to`.  The rotation is in the
265    /// plane spanned by the two vectors.  Will rotate at most 180 degrees.
266    ///
267    /// The inputs must be unit vectors.
268    ///
269    /// `from_rotation_arc(from, to) * from ≈ to`.
270    ///
271    /// For near-singular cases (from≈to and from≈-to) the current implementation
272    /// is only accurate to about 0.001 (for `f32`).
273    ///
274    /// # Panics
275    ///
276    /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled.
277    #[must_use]
278    pub fn from_rotation_arc(from: DVec3, to: DVec3) -> Self {
279        glam_assert!(from.is_normalized());
280        glam_assert!(to.is_normalized());
281
282        const ONE_MINUS_EPS: f64 = 1.0 - 2.0 * core::f64::EPSILON;
283        let dot = from.dot(to);
284        if dot > ONE_MINUS_EPS {
285            // 0° singulary: from ≈ to
286            Self::IDENTITY
287        } else if dot < -ONE_MINUS_EPS {
288            // 180° singulary: from ≈ -to
289            use core::f64::consts::PI; // half a turn = 𝛕/2 = 180°
290            Self::from_axis_angle(from.any_orthonormal_vector(), PI)
291        } else {
292            let c = from.cross(to);
293            Self::from_xyzw(c.x, c.y, c.z, 1.0 + dot).normalize()
294        }
295    }
296
297    /// Gets the minimal rotation for transforming `from` to either `to` or `-to`.  This means
298    /// that the resulting quaternion will rotate `from` so that it is colinear with `to`.
299    ///
300    /// The rotation is in the plane spanned by the two vectors.  Will rotate at most 90
301    /// degrees.
302    ///
303    /// The inputs must be unit vectors.
304    ///
305    /// `to.dot(from_rotation_arc_colinear(from, to) * from).abs() ≈ 1`.
306    ///
307    /// # Panics
308    ///
309    /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled.
310    #[inline]
311    #[must_use]
312    pub fn from_rotation_arc_colinear(from: DVec3, to: DVec3) -> Self {
313        if from.dot(to) < 0.0 {
314            Self::from_rotation_arc(from, -to)
315        } else {
316            Self::from_rotation_arc(from, to)
317        }
318    }
319
320    /// Gets the minimal rotation for transforming `from` to `to`.  The resulting rotation is
321    /// around the z axis. Will rotate at most 180 degrees.
322    ///
323    /// The inputs must be unit vectors.
324    ///
325    /// `from_rotation_arc_2d(from, to) * from ≈ to`.
326    ///
327    /// For near-singular cases (from≈to and from≈-to) the current implementation
328    /// is only accurate to about 0.001 (for `f32`).
329    ///
330    /// # Panics
331    ///
332    /// Will panic if `from` or `to` are not normalized when `glam_assert` is enabled.
333    #[must_use]
334    pub fn from_rotation_arc_2d(from: DVec2, to: DVec2) -> Self {
335        glam_assert!(from.is_normalized());
336        glam_assert!(to.is_normalized());
337
338        const ONE_MINUS_EPSILON: f64 = 1.0 - 2.0 * core::f64::EPSILON;
339        let dot = from.dot(to);
340        if dot > ONE_MINUS_EPSILON {
341            // 0° singulary: from ≈ to
342            Self::IDENTITY
343        } else if dot < -ONE_MINUS_EPSILON {
344            // 180° singulary: from ≈ -to
345            const COS_FRAC_PI_2: f64 = 0.0;
346            const SIN_FRAC_PI_2: f64 = 1.0;
347            // rotation around z by PI radians
348            Self::from_xyzw(0.0, 0.0, SIN_FRAC_PI_2, COS_FRAC_PI_2)
349        } else {
350            // vector3 cross where z=0
351            let z = from.x * to.y - to.x * from.y;
352            let w = 1.0 + dot;
353            // calculate length with x=0 and y=0 to normalize
354            let len_rcp = 1.0 / math::sqrt(z * z + w * w);
355            Self::from_xyzw(0.0, 0.0, z * len_rcp, w * len_rcp)
356        }
357    }
358
359    /// Returns the rotation axis (normalized) and angle (in radians) of `self`.
360    #[inline]
361    #[must_use]
362    pub fn to_axis_angle(self) -> (DVec3, f64) {
363        const EPSILON: f64 = 1.0e-8;
364        let v = DVec3::new(self.x, self.y, self.z);
365        let length = v.length();
366        if length >= EPSILON {
367            let angle = 2.0 * math::atan2(length, self.w);
368            let axis = v / length;
369            (axis, angle)
370        } else {
371            (DVec3::X, 0.0)
372        }
373    }
374
375    /// Returns the rotation axis scaled by the rotation in radians.
376    #[inline]
377    #[must_use]
378    pub fn to_scaled_axis(self) -> DVec3 {
379        let (axis, angle) = self.to_axis_angle();
380        axis * angle
381    }
382
383    /// Returns the rotation angles for the given euler rotation sequence.
384    #[inline]
385    #[must_use]
386    pub fn to_euler(self, euler: EulerRot) -> (f64, f64, f64) {
387        euler.convert_quat(self)
388    }
389
390    /// `[x, y, z, w]`
391    #[inline]
392    #[must_use]
393    pub fn to_array(&self) -> [f64; 4] {
394        [self.x, self.y, self.z, self.w]
395    }
396
397    /// Returns the vector part of the quaternion.
398    #[inline]
399    #[must_use]
400    pub fn xyz(self) -> DVec3 {
401        DVec3::new(self.x, self.y, self.z)
402    }
403
404    /// Returns the quaternion conjugate of `self`. For a unit quaternion the
405    /// conjugate is also the inverse.
406    #[inline]
407    #[must_use]
408    pub fn conjugate(self) -> Self {
409        Self {
410            x: -self.x,
411            y: -self.y,
412            z: -self.z,
413            w: self.w,
414        }
415    }
416
417    /// Returns the inverse of a normalized quaternion.
418    ///
419    /// Typically quaternion inverse returns the conjugate of a normalized quaternion.
420    /// Because `self` is assumed to already be unit length this method *does not* normalize
421    /// before returning the conjugate.
422    ///
423    /// # Panics
424    ///
425    /// Will panic if `self` is not normalized when `glam_assert` is enabled.
426    #[inline]
427    #[must_use]
428    pub fn inverse(self) -> Self {
429        glam_assert!(self.is_normalized());
430        self.conjugate()
431    }
432
433    /// Computes the dot product of `self` and `rhs`. The dot product is
434    /// equal to the cosine of the angle between two quaternion rotations.
435    #[inline]
436    #[must_use]
437    pub fn dot(self, rhs: Self) -> f64 {
438        DVec4::from(self).dot(DVec4::from(rhs))
439    }
440
441    /// Computes the length of `self`.
442    #[doc(alias = "magnitude")]
443    #[inline]
444    #[must_use]
445    pub fn length(self) -> f64 {
446        DVec4::from(self).length()
447    }
448
449    /// Computes the squared length of `self`.
450    ///
451    /// This is generally faster than `length()` as it avoids a square
452    /// root operation.
453    #[doc(alias = "magnitude2")]
454    #[inline]
455    #[must_use]
456    pub fn length_squared(self) -> f64 {
457        DVec4::from(self).length_squared()
458    }
459
460    /// Computes `1.0 / length()`.
461    ///
462    /// For valid results, `self` must _not_ be of length zero.
463    #[inline]
464    #[must_use]
465    pub fn length_recip(self) -> f64 {
466        DVec4::from(self).length_recip()
467    }
468
469    /// Returns `self` normalized to length 1.0.
470    ///
471    /// For valid results, `self` must _not_ be of length zero.
472    ///
473    /// Panics
474    ///
475    /// Will panic if `self` is zero length when `glam_assert` is enabled.
476    #[inline]
477    #[must_use]
478    pub fn normalize(self) -> Self {
479        Self::from_vec4(DVec4::from(self).normalize())
480    }
481
482    /// Returns `true` if, and only if, all elements are finite.
483    /// If any element is either `NaN`, positive or negative infinity, this will return `false`.
484    #[inline]
485    #[must_use]
486    pub fn is_finite(self) -> bool {
487        DVec4::from(self).is_finite()
488    }
489
490    #[inline]
491    #[must_use]
492    pub fn is_nan(self) -> bool {
493        DVec4::from(self).is_nan()
494    }
495
496    /// Returns whether `self` of length `1.0` or not.
497    ///
498    /// Uses a precision threshold of `1e-6`.
499    #[inline]
500    #[must_use]
501    pub fn is_normalized(self) -> bool {
502        DVec4::from(self).is_normalized()
503    }
504
505    #[inline]
506    #[must_use]
507    pub fn is_near_identity(self) -> bool {
508        // Based on https://github.com/nfrechette/rtm `rtm::quat_near_identity`
509        let threshold_angle = 0.002_847_144_6;
510        // Because of floating point precision, we cannot represent very small rotations.
511        // The closest f32 to 1.0 that is not 1.0 itself yields:
512        // 0.99999994.acos() * 2.0  = 0.000690533954 rad
513        //
514        // An error threshold of 1.e-6 is used by default.
515        // (1.0 - 1.e-6).acos() * 2.0 = 0.00284714461 rad
516        // (1.0 - 1.e-7).acos() * 2.0 = 0.00097656250 rad
517        //
518        // We don't really care about the angle value itself, only if it's close to 0.
519        // This will happen whenever quat.w is close to 1.0.
520        // If the quat.w is close to -1.0, the angle will be near 2*PI which is close to
521        // a negative 0 rotation. By forcing quat.w to be positive, we'll end up with
522        // the shortest path.
523        let positive_w_angle = math::acos_approx(math::abs(self.w)) * 2.0;
524        positive_w_angle < threshold_angle
525    }
526
527    /// Returns the angle (in radians) for the minimal rotation
528    /// for transforming this quaternion into another.
529    ///
530    /// Both quaternions must be normalized.
531    ///
532    /// # Panics
533    ///
534    /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled.
535    #[inline]
536    #[must_use]
537    pub fn angle_between(self, rhs: Self) -> f64 {
538        glam_assert!(self.is_normalized() && rhs.is_normalized());
539        math::acos_approx(math::abs(self.dot(rhs))) * 2.0
540    }
541
542    /// Returns true if the absolute difference of all elements between `self` and `rhs`
543    /// is less than or equal to `max_abs_diff`.
544    ///
545    /// This can be used to compare if two quaternions contain similar elements. It works
546    /// best when comparing with a known value. The `max_abs_diff` that should be used used
547    /// depends on the values being compared against.
548    ///
549    /// For more see
550    /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/).
551    #[inline]
552    #[must_use]
553    pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f64) -> bool {
554        DVec4::from(self).abs_diff_eq(DVec4::from(rhs), max_abs_diff)
555    }
556
557    /// Performs a linear interpolation between `self` and `rhs` based on
558    /// the value `s`.
559    ///
560    /// When `s` is `0.0`, the result will be equal to `self`.  When `s`
561    /// is `1.0`, the result will be equal to `rhs`.
562    ///
563    /// # Panics
564    ///
565    /// Will panic if `self` or `end` are not normalized when `glam_assert` is enabled.
566    #[doc(alias = "mix")]
567    #[inline]
568    #[must_use]
569    pub fn lerp(self, end: Self, s: f64) -> Self {
570        glam_assert!(self.is_normalized());
571        glam_assert!(end.is_normalized());
572
573        let start = self;
574        let dot = start.dot(end);
575        let bias = if dot >= 0.0 { 1.0 } else { -1.0 };
576        let interpolated = start.add(end.mul(bias).sub(start).mul(s));
577        interpolated.normalize()
578    }
579
580    /// Performs a spherical linear interpolation between `self` and `end`
581    /// based on the value `s`.
582    ///
583    /// When `s` is `0.0`, the result will be equal to `self`.  When `s`
584    /// is `1.0`, the result will be equal to `end`.
585    ///
586    /// # Panics
587    ///
588    /// Will panic if `self` or `end` are not normalized when `glam_assert` is enabled.
589    #[inline]
590    #[must_use]
591    pub fn slerp(self, mut end: Self, s: f64) -> Self {
592        // http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/
593        glam_assert!(self.is_normalized());
594        glam_assert!(end.is_normalized());
595
596        const DOT_THRESHOLD: f64 = 0.9995;
597
598        // Note that a rotation can be represented by two quaternions: `q` and
599        // `-q`. The slerp path between `q` and `end` will be different from the
600        // path between `-q` and `end`. One path will take the long way around and
601        // one will take the short way. In order to correct for this, the `dot`
602        // product between `self` and `end` should be positive. If the `dot`
603        // product is negative, slerp between `self` and `-end`.
604        let mut dot = self.dot(end);
605        if dot < 0.0 {
606            end = -end;
607            dot = -dot;
608        }
609
610        if dot > DOT_THRESHOLD {
611            // assumes lerp returns a normalized quaternion
612            self.lerp(end, s)
613        } else {
614            let theta = math::acos_approx(dot);
615
616            let scale1 = math::sin(theta * (1.0 - s));
617            let scale2 = math::sin(theta * s);
618            let theta_sin = math::sin(theta);
619
620            self.mul(scale1).add(end.mul(scale2)).mul(1.0 / theta_sin)
621        }
622    }
623
624    /// Multiplies a quaternion and a 3D vector, returning the rotated vector.
625    ///
626    /// # Panics
627    ///
628    /// Will panic if `self` is not normalized when `glam_assert` is enabled.
629    #[inline]
630    #[must_use]
631    pub fn mul_vec3(self, rhs: DVec3) -> DVec3 {
632        glam_assert!(self.is_normalized());
633
634        let w = self.w;
635        let b = DVec3::new(self.x, self.y, self.z);
636        let b2 = b.dot(b);
637        rhs.mul(w * w - b2)
638            .add(b.mul(rhs.dot(b) * 2.0))
639            .add(b.cross(rhs).mul(w * 2.0))
640    }
641
642    /// Multiplies two quaternions. If they each represent a rotation, the result will
643    /// represent the combined rotation.
644    ///
645    /// Note that due to floating point rounding the result may not be perfectly normalized.
646    ///
647    /// # Panics
648    ///
649    /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled.
650    #[inline]
651    #[must_use]
652    pub fn mul_quat(self, rhs: Self) -> Self {
653        glam_assert!(self.is_normalized());
654        glam_assert!(rhs.is_normalized());
655
656        let (x0, y0, z0, w0) = self.into();
657        let (x1, y1, z1, w1) = rhs.into();
658        Self::from_xyzw(
659            w0 * x1 + x0 * w1 + y0 * z1 - z0 * y1,
660            w0 * y1 - x0 * z1 + y0 * w1 + z0 * x1,
661            w0 * z1 + x0 * y1 - y0 * x1 + z0 * w1,
662            w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1,
663        )
664    }
665
666    /// Creates a quaternion from a 3x3 rotation matrix inside a 3D affine transform.
667    #[inline]
668    #[must_use]
669    pub fn from_affine3(a: &crate::DAffine3) -> Self {
670        #[allow(clippy::useless_conversion)]
671        Self::from_rotation_axes(
672            a.matrix3.x_axis.into(),
673            a.matrix3.y_axis.into(),
674            a.matrix3.z_axis.into(),
675        )
676    }
677
678    #[inline]
679    #[must_use]
680    pub fn as_quat(self) -> Quat {
681        Quat::from_xyzw(self.x as f32, self.y as f32, self.z as f32, self.w as f32)
682    }
683
684    #[inline]
685    #[must_use]
686    #[deprecated(since = "0.24.2", note = "Use as_quat() instead")]
687    pub fn as_f32(self) -> Quat {
688        self.as_quat()
689    }
690}
691
692#[cfg(not(target_arch = "spirv"))]
693impl fmt::Debug for DQuat {
694    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
695        fmt.debug_tuple(stringify!(DQuat))
696            .field(&self.x)
697            .field(&self.y)
698            .field(&self.z)
699            .field(&self.w)
700            .finish()
701    }
702}
703
704#[cfg(not(target_arch = "spirv"))]
705impl fmt::Display for DQuat {
706    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
707        write!(fmt, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
708    }
709}
710
711impl Add<DQuat> for DQuat {
712    type Output = Self;
713    /// Adds two quaternions.
714    ///
715    /// The sum is not guaranteed to be normalized.
716    ///
717    /// Note that addition is not the same as combining the rotations represented by the
718    /// two quaternions! That corresponds to multiplication.
719    #[inline]
720    fn add(self, rhs: Self) -> Self {
721        Self::from_vec4(DVec4::from(self) + DVec4::from(rhs))
722    }
723}
724
725impl Sub<DQuat> for DQuat {
726    type Output = Self;
727    /// Subtracts the `rhs` quaternion from `self`.
728    ///
729    /// The difference is not guaranteed to be normalized.
730    #[inline]
731    fn sub(self, rhs: Self) -> Self {
732        Self::from_vec4(DVec4::from(self) - DVec4::from(rhs))
733    }
734}
735
736impl Mul<f64> for DQuat {
737    type Output = Self;
738    /// Multiplies a quaternion by a scalar value.
739    ///
740    /// The product is not guaranteed to be normalized.
741    #[inline]
742    fn mul(self, rhs: f64) -> Self {
743        Self::from_vec4(DVec4::from(self) * rhs)
744    }
745}
746
747impl Div<f64> for DQuat {
748    type Output = Self;
749    /// Divides a quaternion by a scalar value.
750    /// The quotient is not guaranteed to be normalized.
751    #[inline]
752    fn div(self, rhs: f64) -> Self {
753        Self::from_vec4(DVec4::from(self) / rhs)
754    }
755}
756
757impl Mul<DQuat> for DQuat {
758    type Output = Self;
759    /// Multiplies two quaternions. If they each represent a rotation, the result will
760    /// represent the combined rotation.
761    ///
762    /// Note that due to floating point rounding the result may not be perfectly
763    /// normalized.
764    ///
765    /// # Panics
766    ///
767    /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled.
768    #[inline]
769    fn mul(self, rhs: Self) -> Self {
770        self.mul_quat(rhs)
771    }
772}
773
774impl MulAssign<DQuat> for DQuat {
775    /// Multiplies two quaternions. If they each represent a rotation, the result will
776    /// represent the combined rotation.
777    ///
778    /// Note that due to floating point rounding the result may not be perfectly
779    /// normalized.
780    ///
781    /// # Panics
782    ///
783    /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled.
784    #[inline]
785    fn mul_assign(&mut self, rhs: Self) {
786        *self = self.mul_quat(rhs);
787    }
788}
789
790impl Mul<DVec3> for DQuat {
791    type Output = DVec3;
792    /// Multiplies a quaternion and a 3D vector, returning the rotated vector.
793    ///
794    /// # Panics
795    ///
796    /// Will panic if `self` is not normalized when `glam_assert` is enabled.
797    #[inline]
798    fn mul(self, rhs: DVec3) -> Self::Output {
799        self.mul_vec3(rhs)
800    }
801}
802
803impl Neg for DQuat {
804    type Output = Self;
805    #[inline]
806    fn neg(self) -> Self {
807        self * -1.0
808    }
809}
810
811impl Default for DQuat {
812    #[inline]
813    fn default() -> Self {
814        Self::IDENTITY
815    }
816}
817
818impl PartialEq for DQuat {
819    #[inline]
820    fn eq(&self, rhs: &Self) -> bool {
821        DVec4::from(*self).eq(&DVec4::from(*rhs))
822    }
823}
824
825#[cfg(not(target_arch = "spirv"))]
826impl AsRef<[f64; 4]> for DQuat {
827    #[inline]
828    fn as_ref(&self) -> &[f64; 4] {
829        unsafe { &*(self as *const Self as *const [f64; 4]) }
830    }
831}
832
833impl Sum<Self> for DQuat {
834    fn sum<I>(iter: I) -> Self
835    where
836        I: Iterator<Item = Self>,
837    {
838        iter.fold(Self::ZERO, Self::add)
839    }
840}
841
842impl<'a> Sum<&'a Self> for DQuat {
843    fn sum<I>(iter: I) -> Self
844    where
845        I: Iterator<Item = &'a Self>,
846    {
847        iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
848    }
849}
850
851impl Product for DQuat {
852    fn product<I>(iter: I) -> Self
853    where
854        I: Iterator<Item = Self>,
855    {
856        iter.fold(Self::IDENTITY, Self::mul)
857    }
858}
859
860impl<'a> Product<&'a Self> for DQuat {
861    fn product<I>(iter: I) -> Self
862    where
863        I: Iterator<Item = &'a Self>,
864    {
865        iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b))
866    }
867}
868
869impl From<DQuat> for DVec4 {
870    #[inline]
871    fn from(q: DQuat) -> Self {
872        Self::new(q.x, q.y, q.z, q.w)
873    }
874}
875
876impl From<DQuat> for (f64, f64, f64, f64) {
877    #[inline]
878    fn from(q: DQuat) -> Self {
879        (q.x, q.y, q.z, q.w)
880    }
881}
882
883impl From<DQuat> for [f64; 4] {
884    #[inline]
885    fn from(q: DQuat) -> Self {
886        [q.x, q.y, q.z, q.w]
887    }
888}