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