glam/f64/
dquat.rs

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