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 /// Returns the rotation axis (normalized) and angle (in radians) of `self`.
382 #[inline]
383 #[must_use]
384 pub fn to_axis_angle(self) -> (DVec3, f64) {
385 const EPSILON: f64 = 1.0e-8;
386 let v = DVec3::new(self.x, self.y, self.z);
387 let length = v.length();
388 if length >= EPSILON {
389 let angle = 2.0 * math::atan2(length, self.w);
390 let axis = v / length;
391 (axis, angle)
392 } else {
393 (DVec3::X, 0.0)
394 }
395 }
396
397 /// Returns the rotation axis scaled by the rotation in radians.
398 #[inline]
399 #[must_use]
400 pub fn to_scaled_axis(self) -> DVec3 {
401 let (axis, angle) = self.to_axis_angle();
402 axis * angle
403 }
404
405 /// Returns the rotation angles for the given euler rotation sequence.
406 #[inline]
407 #[must_use]
408 pub fn to_euler(self, order: EulerRot) -> (f64, f64, f64) {
409 self.to_euler_angles(order)
410 }
411
412 /// `[x, y, z, w]`
413 #[inline]
414 #[must_use]
415 pub fn to_array(&self) -> [f64; 4] {
416 [self.x, self.y, self.z, self.w]
417 }
418
419 /// Returns the vector part of the quaternion.
420 #[inline]
421 #[must_use]
422 pub fn xyz(self) -> DVec3 {
423 DVec3::new(self.x, self.y, self.z)
424 }
425
426 /// Returns the quaternion conjugate of `self`. For a unit quaternion the
427 /// conjugate is also the inverse.
428 #[inline]
429 #[must_use]
430 pub fn conjugate(self) -> Self {
431 Self {
432 x: -self.x,
433 y: -self.y,
434 z: -self.z,
435 w: self.w,
436 }
437 }
438
439 /// Returns the inverse of a normalized quaternion.
440 ///
441 /// Typically quaternion inverse returns the conjugate of a normalized quaternion.
442 /// Because `self` is assumed to already be unit length this method *does not* normalize
443 /// before returning the conjugate.
444 ///
445 /// # Panics
446 ///
447 /// Will panic if `self` is not normalized when `glam_assert` is enabled.
448 #[inline]
449 #[must_use]
450 pub fn inverse(self) -> Self {
451 glam_assert!(self.is_normalized());
452 self.conjugate()
453 }
454
455 /// Computes the dot product of `self` and `rhs`. The dot product is
456 /// equal to the cosine of the angle between two quaternion rotations.
457 #[inline]
458 #[must_use]
459 pub fn dot(self, rhs: Self) -> f64 {
460 DVec4::from(self).dot(DVec4::from(rhs))
461 }
462
463 /// Computes the length of `self`.
464 #[doc(alias = "magnitude")]
465 #[inline]
466 #[must_use]
467 pub fn length(self) -> f64 {
468 DVec4::from(self).length()
469 }
470
471 /// Computes the squared length of `self`.
472 ///
473 /// This is generally faster than `length()` as it avoids a square
474 /// root operation.
475 #[doc(alias = "magnitude2")]
476 #[inline]
477 #[must_use]
478 pub fn length_squared(self) -> f64 {
479 DVec4::from(self).length_squared()
480 }
481
482 /// Computes `1.0 / length()`.
483 ///
484 /// For valid results, `self` must _not_ be of length zero.
485 #[inline]
486 #[must_use]
487 pub fn length_recip(self) -> f64 {
488 DVec4::from(self).length_recip()
489 }
490
491 /// Returns `self` normalized to length 1.0.
492 ///
493 /// For valid results, `self` must _not_ be of length zero.
494 ///
495 /// Panics
496 ///
497 /// Will panic if `self` is zero length when `glam_assert` is enabled.
498 #[inline]
499 #[must_use]
500 pub fn normalize(self) -> Self {
501 Self::from_vec4(DVec4::from(self).normalize())
502 }
503
504 /// Returns `true` if, and only if, all elements are finite.
505 /// If any element is either `NaN`, positive or negative infinity, this will return `false`.
506 #[inline]
507 #[must_use]
508 pub fn is_finite(self) -> bool {
509 DVec4::from(self).is_finite()
510 }
511
512 /// Returns `true` if any elements are `NAN`.
513 #[inline]
514 #[must_use]
515 pub fn is_nan(self) -> bool {
516 DVec4::from(self).is_nan()
517 }
518
519 /// Returns whether `self` of length `1.0` or not.
520 ///
521 /// Uses a precision threshold of `1e-6`.
522 #[inline]
523 #[must_use]
524 pub fn is_normalized(self) -> bool {
525 DVec4::from(self).is_normalized()
526 }
527
528 #[inline]
529 #[must_use]
530 pub fn is_near_identity(self) -> bool {
531 // Based on https://github.com/nfrechette/rtm `rtm::quat_near_identity`
532 let threshold_angle = 0.002_847_144_6;
533 // Because of floating point precision, we cannot represent very small rotations.
534 // The closest f32 to 1.0 that is not 1.0 itself yields:
535 // 0.99999994.acos() * 2.0 = 0.000690533954 rad
536 //
537 // An error threshold of 1.e-6 is used by default.
538 // (1.0 - 1.e-6).acos() * 2.0 = 0.00284714461 rad
539 // (1.0 - 1.e-7).acos() * 2.0 = 0.00097656250 rad
540 //
541 // We don't really care about the angle value itself, only if it's close to 0.
542 // This will happen whenever quat.w is close to 1.0.
543 // If the quat.w is close to -1.0, the angle will be near 2*PI which is close to
544 // a negative 0 rotation. By forcing quat.w to be positive, we'll end up with
545 // the shortest path.
546 let positive_w_angle = math::acos_approx(math::abs(self.w)) * 2.0;
547 positive_w_angle < threshold_angle
548 }
549
550 /// Returns the angle (in radians) for the minimal rotation
551 /// for transforming this quaternion into another.
552 ///
553 /// Both quaternions must be normalized.
554 ///
555 /// # Panics
556 ///
557 /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled.
558 #[inline]
559 #[must_use]
560 pub fn angle_between(self, rhs: Self) -> f64 {
561 glam_assert!(self.is_normalized() && rhs.is_normalized());
562 math::acos_approx(math::abs(self.dot(rhs))) * 2.0
563 }
564
565 /// Rotates towards `rhs` up to `max_angle` (in radians).
566 ///
567 /// When `max_angle` is `0.0`, the result will be equal to `self`. When `max_angle` is equal to
568 /// `self.angle_between(rhs)`, the result will be equal to `rhs`. If `max_angle` is negative,
569 /// rotates towards the exact opposite of `rhs`. Will not go past the target.
570 ///
571 /// Both quaternions must be normalized.
572 ///
573 /// # Panics
574 ///
575 /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled.
576 #[inline]
577 #[must_use]
578 pub fn rotate_towards(&self, rhs: Self, max_angle: f64) -> Self {
579 glam_assert!(self.is_normalized() && rhs.is_normalized());
580 let angle = self.angle_between(rhs);
581 if angle <= 1e-4 {
582 return *self;
583 }
584 let s = (max_angle / angle).clamp(-1.0, 1.0);
585 self.slerp(rhs, s)
586 }
587
588 /// Returns true if the absolute difference of all elements between `self` and `rhs`
589 /// is less than or equal to `max_abs_diff`.
590 ///
591 /// This can be used to compare if two quaternions contain similar elements. It works
592 /// best when comparing with a known value. The `max_abs_diff` that should be used used
593 /// depends on the values being compared against.
594 ///
595 /// For more see
596 /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/).
597 #[inline]
598 #[must_use]
599 pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f64) -> bool {
600 DVec4::from(self).abs_diff_eq(DVec4::from(rhs), max_abs_diff)
601 }
602
603 #[inline(always)]
604 #[must_use]
605 fn lerp_impl(self, end: Self, s: f64) -> Self {
606 (self * (1.0 - s) + end * s).normalize()
607 }
608
609 /// Performs a linear interpolation between `self` and `rhs` based on
610 /// the value `s`.
611 ///
612 /// When `s` is `0.0`, the result will be equal to `self`. When `s`
613 /// is `1.0`, the result will be equal to `rhs`.
614 ///
615 /// # Panics
616 ///
617 /// Will panic if `self` or `end` are not normalized when `glam_assert` is enabled.
618 #[doc(alias = "mix")]
619 #[inline]
620 #[must_use]
621 pub fn lerp(self, end: Self, s: f64) -> Self {
622 glam_assert!(self.is_normalized());
623 glam_assert!(end.is_normalized());
624
625 let dot = self.dot(end);
626 let bias = if dot >= 0.0 { 1.0 } else { -1.0 };
627 self.lerp_impl(end * bias, s)
628 }
629
630 /// Performs a spherical linear interpolation between `self` and `end`
631 /// based on the value `s`.
632 ///
633 /// When `s` is `0.0`, the result will be equal to `self`. When `s`
634 /// is `1.0`, the result will be equal to `end`.
635 ///
636 /// # Panics
637 ///
638 /// Will panic if `self` or `end` are not normalized when `glam_assert` is enabled.
639 #[inline]
640 #[must_use]
641 pub fn slerp(self, mut end: Self, s: f64) -> Self {
642 // http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/
643 glam_assert!(self.is_normalized());
644 glam_assert!(end.is_normalized());
645
646 // Note that a rotation can be represented by two quaternions: `q` and
647 // `-q`. The slerp path between `q` and `end` will be different from the
648 // path between `-q` and `end`. One path will take the long way around and
649 // one will take the short way. In order to correct for this, the `dot`
650 // product between `self` and `end` should be positive. If the `dot`
651 // product is negative, slerp between `self` and `-end`.
652 let mut dot = self.dot(end);
653 if dot < 0.0 {
654 end = -end;
655 dot = -dot;
656 }
657
658 const DOT_THRESHOLD: f64 = 1.0 - f64::EPSILON;
659 if dot > DOT_THRESHOLD {
660 // if above threshold perform linear interpolation to avoid divide by zero
661 self.lerp_impl(end, s)
662 } else {
663 let theta = math::acos_approx(dot);
664
665 let scale1 = math::sin(theta * (1.0 - s));
666 let scale2 = math::sin(theta * s);
667 let theta_sin = math::sin(theta);
668 ((self * scale1) + (end * scale2)) * (1.0 / theta_sin)
669 }
670 }
671
672 /// Multiplies a quaternion and a 3D vector, returning the rotated vector.
673 ///
674 /// # Panics
675 ///
676 /// Will panic if `self` is not normalized when `glam_assert` is enabled.
677 #[inline]
678 #[must_use]
679 pub fn mul_vec3(self, rhs: DVec3) -> DVec3 {
680 glam_assert!(self.is_normalized());
681
682 let w = self.w;
683 let b = DVec3::new(self.x, self.y, self.z);
684 let b2 = b.dot(b);
685 rhs.mul(w * w - b2)
686 .add(b.mul(rhs.dot(b) * 2.0))
687 .add(b.cross(rhs).mul(w * 2.0))
688 }
689
690 /// Multiplies two quaternions. If they each represent a rotation, the result will
691 /// represent the combined rotation.
692 ///
693 /// Note that due to floating point rounding the result may not be perfectly normalized.
694 ///
695 /// # Panics
696 ///
697 /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled.
698 #[inline]
699 #[must_use]
700 pub fn mul_quat(self, rhs: Self) -> Self {
701 let (x0, y0, z0, w0) = self.into();
702 let (x1, y1, z1, w1) = rhs.into();
703 Self::from_xyzw(
704 w0 * x1 + x0 * w1 + y0 * z1 - z0 * y1,
705 w0 * y1 - x0 * z1 + y0 * w1 + z0 * x1,
706 w0 * z1 + x0 * y1 - y0 * x1 + z0 * w1,
707 w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1,
708 )
709 }
710
711 /// Creates a quaternion from a 3x3 rotation matrix inside a 3D affine transform.
712 ///
713 /// Note if the input affine matrix contain scales, shears, or other non-rotation
714 /// transformations then the resulting quaternion will be ill-defined.
715 ///
716 /// # Panics
717 ///
718 /// Will panic if any input affine matrix column is not normalized when `glam_assert` is
719 /// enabled.
720 #[inline]
721 #[must_use]
722 pub fn from_affine3(a: &crate::DAffine3) -> Self {
723 #[allow(clippy::useless_conversion)]
724 Self::from_rotation_axes(
725 a.matrix3.x_axis.into(),
726 a.matrix3.y_axis.into(),
727 a.matrix3.z_axis.into(),
728 )
729 }
730
731 #[inline]
732 #[must_use]
733 pub fn as_quat(self) -> Quat {
734 Quat::from_xyzw(self.x as f32, self.y as f32, self.z as f32, self.w as f32)
735 }
736}
737
738impl fmt::Debug for DQuat {
739 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
740 fmt.debug_tuple(stringify!(DQuat))
741 .field(&self.x)
742 .field(&self.y)
743 .field(&self.z)
744 .field(&self.w)
745 .finish()
746 }
747}
748
749impl fmt::Display for DQuat {
750 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
751 if let Some(p) = f.precision() {
752 write!(
753 f,
754 "[{:.*}, {:.*}, {:.*}, {:.*}]",
755 p, self.x, p, self.y, p, self.z, p, self.w
756 )
757 } else {
758 write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
759 }
760 }
761}
762
763impl Add<DQuat> for DQuat {
764 type Output = Self;
765 /// Adds two quaternions.
766 ///
767 /// The sum is not guaranteed to be normalized.
768 ///
769 /// Note that addition is not the same as combining the rotations represented by the
770 /// two quaternions! That corresponds to multiplication.
771 #[inline]
772 fn add(self, rhs: Self) -> Self {
773 Self::from_vec4(DVec4::from(self) + DVec4::from(rhs))
774 }
775}
776
777impl Sub<DQuat> for DQuat {
778 type Output = Self;
779 /// Subtracts the `rhs` quaternion from `self`.
780 ///
781 /// The difference is not guaranteed to be normalized.
782 #[inline]
783 fn sub(self, rhs: Self) -> Self {
784 Self::from_vec4(DVec4::from(self) - DVec4::from(rhs))
785 }
786}
787
788impl Mul<f64> for DQuat {
789 type Output = Self;
790 /// Multiplies a quaternion by a scalar value.
791 ///
792 /// The product is not guaranteed to be normalized.
793 #[inline]
794 fn mul(self, rhs: f64) -> Self {
795 Self::from_vec4(DVec4::from(self) * rhs)
796 }
797}
798
799impl Div<f64> for DQuat {
800 type Output = Self;
801 /// Divides a quaternion by a scalar value.
802 /// The quotient is not guaranteed to be normalized.
803 #[inline]
804 fn div(self, rhs: f64) -> Self {
805 Self::from_vec4(DVec4::from(self) / rhs)
806 }
807}
808
809impl Mul<DQuat> for DQuat {
810 type Output = Self;
811 /// Multiplies two quaternions. If they each represent a rotation, the result will
812 /// represent the combined rotation.
813 ///
814 /// Note that due to floating point rounding the result may not be perfectly
815 /// normalized.
816 ///
817 /// # Panics
818 ///
819 /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled.
820 #[inline]
821 fn mul(self, rhs: Self) -> Self {
822 self.mul_quat(rhs)
823 }
824}
825
826impl MulAssign<DQuat> for DQuat {
827 /// Multiplies two quaternions. If they each represent a rotation, the result will
828 /// represent the combined rotation.
829 ///
830 /// Note that due to floating point rounding the result may not be perfectly
831 /// normalized.
832 ///
833 /// # Panics
834 ///
835 /// Will panic if `self` or `rhs` are not normalized when `glam_assert` is enabled.
836 #[inline]
837 fn mul_assign(&mut self, rhs: Self) {
838 *self = self.mul_quat(rhs);
839 }
840}
841
842impl Mul<DVec3> for DQuat {
843 type Output = DVec3;
844 /// Multiplies a quaternion and a 3D vector, returning the rotated vector.
845 ///
846 /// # Panics
847 ///
848 /// Will panic if `self` is not normalized when `glam_assert` is enabled.
849 #[inline]
850 fn mul(self, rhs: DVec3) -> Self::Output {
851 self.mul_vec3(rhs)
852 }
853}
854
855impl Neg for DQuat {
856 type Output = Self;
857 #[inline]
858 fn neg(self) -> Self {
859 self * -1.0
860 }
861}
862
863impl Default for DQuat {
864 #[inline]
865 fn default() -> Self {
866 Self::IDENTITY
867 }
868}
869
870impl PartialEq for DQuat {
871 #[inline]
872 fn eq(&self, rhs: &Self) -> bool {
873 DVec4::from(*self).eq(&DVec4::from(*rhs))
874 }
875}
876
877#[cfg(not(target_arch = "spirv"))]
878impl AsRef<[f64; 4]> for DQuat {
879 #[inline]
880 fn as_ref(&self) -> &[f64; 4] {
881 unsafe { &*(self as *const Self as *const [f64; 4]) }
882 }
883}
884
885impl Sum<Self> for DQuat {
886 fn sum<I>(iter: I) -> Self
887 where
888 I: Iterator<Item = Self>,
889 {
890 iter.fold(Self::ZERO, Self::add)
891 }
892}
893
894impl<'a> Sum<&'a Self> for DQuat {
895 fn sum<I>(iter: I) -> Self
896 where
897 I: Iterator<Item = &'a Self>,
898 {
899 iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
900 }
901}
902
903impl Product for DQuat {
904 fn product<I>(iter: I) -> Self
905 where
906 I: Iterator<Item = Self>,
907 {
908 iter.fold(Self::IDENTITY, Self::mul)
909 }
910}
911
912impl<'a> Product<&'a Self> for DQuat {
913 fn product<I>(iter: I) -> Self
914 where
915 I: Iterator<Item = &'a Self>,
916 {
917 iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b))
918 }
919}
920
921impl From<DQuat> for DVec4 {
922 #[inline]
923 fn from(q: DQuat) -> Self {
924 Self::new(q.x, q.y, q.z, q.w)
925 }
926}
927
928impl From<DQuat> for (f64, f64, f64, f64) {
929 #[inline]
930 fn from(q: DQuat) -> Self {
931 (q.x, q.y, q.z, q.w)
932 }
933}
934
935impl From<DQuat> for [f64; 4] {
936 #[inline]
937 fn from(q: DQuat) -> Self {
938 [q.x, q.y, q.z, q.w]
939 }
940}