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