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}