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