1use crate::matrix::{Matrix3, Matrix4};
29use crate::scalar::*;
30use crate::vector::{FloatVector, Vector, Vector3};
31use core::ops::*;
32use num_traits::{Zero, One};
33
34#[repr(C)]
35#[derive(Copy, Clone, Debug, Default)]
36pub struct Quat<T: Scalar> {
37 pub x: T,
38 pub y: T,
39 pub z: T,
40 pub w: T,
41}
42
43impl<T: FloatScalar> Quat<T> {
44 pub fn identity() -> Self {
45 Self {
46 x: <T as Zero>::zero(),
47 y: <T as Zero>::zero(),
48 z: <T as Zero>::zero(),
49 w: <T as One>::one(),
50 }
51 }
52 pub fn new(x: T, y: T, z: T, w: T) -> Self {
53 Self {
54 x: x,
55 y: y,
56 z: z,
57 w: w,
58 }
59 }
60
61 pub fn dot(l: &Self, r: &Self) -> T {
67 l.x * r.x + l.y * r.y + l.z * r.z + l.w * r.w
68 }
69
70 pub fn length(&self) -> T {
76 T::tsqrt(Self::dot(self, self))
77 }
78
79 pub fn conjugate(q: &Self) -> Self {
86 Self::new(-q.x, -q.y, -q.z, q.w)
87 }
88
89 pub fn normalize(q: &Self) -> Self {
96 let ql = q.length();
97 if ql > <T as Zero>::zero() {
98 *q / ql
99 } else {
100 *q
101 }
102 }
103
104 pub fn neg(q: &Self) -> Self {
108 Self::new(-q.x, -q.y, -q.z, -q.w)
109 }
110 pub fn add(l: &Self, r: &Self) -> Self {
111 Self::new(l.x + r.x, l.y + r.y, l.z + r.z, l.w + r.w)
112 }
113 pub fn sub(l: &Self, r: &Self) -> Self {
114 Self::new(l.x - r.x, l.y - r.y, l.z - r.z, l.w - r.w)
115 }
116 pub fn mul(l: &Self, r: &Self) -> Self {
117 let x = l.w * r.x + l.x * r.w + l.y * r.z - l.z * r.y;
118 let y = l.w * r.y + l.y * r.w + l.z * r.x - l.x * r.z;
119 let z = l.w * r.z + l.z * r.w + l.x * r.y - l.y * r.x;
120 let w = l.w * r.w - l.x * r.x - l.y * r.y - l.z * r.z;
121 Self::new(x, y, z, w)
122 }
123
124 pub fn mulf(l: &Self, r: T) -> Self {
125 Self::new(l.x * r, l.y * r, l.z * r, l.w * r)
126 }
127 pub fn fmul(l: T, r: &Self) -> Self {
128 Self::new(l * r.x, l * r.y, l * r.z, l * r.w)
129 }
130 pub fn divf(l: &Self, r: T) -> Self {
131 Self::new(l.x / r, l.y / r, l.z / r, l.w / r)
132 }
133 pub fn fdiv(l: T, r: &Self) -> Self {
134 Self::new(l / r.x, l / r.y, l / r.z, l / r.w)
135 }
136 pub fn inverse(q: &Self) -> Self {
137 Self::normalize(&Self::conjugate(q))
138 }
139
140 pub fn mat3(&self) -> Matrix3<T> {
148 let xx = self.x * self.x;
149 let xy = self.x * self.y;
150 let xz = self.x * self.z;
151 let xw = self.x * self.w;
152 let yy = self.y * self.y;
153 let yz = self.y * self.z;
154 let yw = self.y * self.w;
155 let zz = self.z * self.z;
156 let zw = self.z * self.w;
157
158 let m00 = <T as One>::one() - T::two() * (yy + zz);
159 let m10 = T::two() * (xy + zw);
160 let m20 = T::two() * (xz - yw);
161 let m01 = T::two() * (xy - zw);
162 let m11 = <T as One>::one() - T::two() * (xx + zz);
163 let m21 = T::two() * (yz + xw);
164 let m02 = T::two() * (xz + yw);
165 let m12 = T::two() * (yz - xw);
166 let m22 = <T as One>::one() - T::two() * (xx + yy);
167
168 Matrix3::new(m00, m10, m20, m01, m11, m21, m02, m12, m22)
169 }
170
171 pub fn mat4(&self) -> Matrix4<T> {
176 let xx = self.x * self.x;
177 let xy = self.x * self.y;
178 let xz = self.x * self.z;
179 let xw = self.x * self.w;
180 let yy = self.y * self.y;
181 let yz = self.y * self.z;
182 let yw = self.y * self.w;
183 let zz = self.z * self.z;
184 let zw = self.z * self.w;
185
186 let m00 = <T as One>::one() - T::two() * (yy + zz);
187 let m10 = T::two() * (xy + zw);
188 let m20 = T::two() * (xz - yw);
189 let m01 = T::two() * (xy - zw);
190 let m11 = <T as One>::one() - T::two() * (xx + zz);
191 let m21 = T::two() * (yz + xw);
192 let m02 = T::two() * (xz + yw);
193 let m12 = T::two() * (yz - xw);
194 let m22 = <T as One>::one() - T::two() * (xx + yy);
195
196 Matrix4::new(
197 m00,
198 m10,
199 m20,
200 <T as Zero>::zero(),
201 m01,
202 m11,
203 m21,
204 <T as Zero>::zero(),
205 m02,
206 m12,
207 m22,
208 <T as Zero>::zero(),
209 <T as Zero>::zero(),
210 <T as Zero>::zero(),
211 <T as Zero>::zero(),
212 <T as One>::one(),
213 )
214 }
215
216 pub fn to_axis_angle(&self) -> (Vector3<T>, T) {
226 let nq = Self::normalize(self);
227 let cos_a = nq.w;
228 let sin_a = {
229 let sin_a = T::tsqrt(<T as One>::one() - cos_a * cos_a);
230 if T::tabs(sin_a) < T::epsilon() {
232 <T as One>::one()
233 } else {
234 sin_a
235 }
236 };
237
238 let angle = T::tacos(cos_a) * T::two();
239 let axis = Vector3::new(nq.x, nq.y, nq.z) / sin_a;
240 (axis, angle)
241 }
242
243 pub fn of_matrix3(m: &Matrix3<T>) -> Self {
244 let mat0 = m.col[0].x;
245 let mat1 = m.col[1].x;
246 let mat2 = m.col[2].x;
247
248 let mat4 = m.col[0].y;
249 let mat5 = m.col[1].y;
250 let mat6 = m.col[2].y;
251
252 let mat8 = m.col[0].z;
253 let mat9 = m.col[1].z;
254 let mat10 = m.col[2].z;
255
256 let t = <T as One>::one() + mat0 + mat5 + mat10;
257
258 if t > <T as Zero>::zero() {
259 let s = T::tsqrt(t) * T::two();
260
261 let x = (mat9 - mat6) / s;
262 let y = (mat2 - mat8) / s;
263 let z = (mat4 - mat1) / s;
264 let w = T::quarter() * s;
265 Self::new(x, y, z, w)
266 } else {
267 if mat0 > mat5 && mat0 > mat10 {
268 let s = T::tsqrt(<T as One>::one() + mat0 - mat5 - mat10) * T::two();
270 let x = T::quarter() * s;
271 let y = (mat4 + mat1) / s;
272 let z = (mat2 + mat8) / s;
273 let w = (mat9 - mat6) / s;
274 Self::new(x, y, z, w)
275 } else if mat5 > mat10 {
276 let s = T::tsqrt(<T as One>::one() + mat5 - mat0 - mat10) * T::two();
278 let x = (mat4 + mat1) / s;
279 let y = T::quarter() * s;
280 let z = (mat9 + mat6) / s;
281 let w = (mat2 - mat8) / s;
282 Self::new(x, y, z, w)
283 } else {
284 let s = T::tsqrt(<T as One>::one() + mat10 - mat0 - mat5) * T::two();
286 let x = (mat2 + mat8) / s;
287 let y = (mat9 + mat6) / s;
288 let z = T::quarter() * s;
289 let w = (mat4 - mat1) / s;
290 Self::new(x, y, z, w)
291 }
292 }
293 }
294
295 pub fn of_matrix4(m: &Matrix4<T>) -> Self {
296 let mat0 = m.col[0].x;
297 let mat1 = m.col[1].x;
298 let mat2 = m.col[2].x;
299
300 let mat4 = m.col[0].y;
301 let mat5 = m.col[1].y;
302 let mat6 = m.col[2].y;
303
304 let mat8 = m.col[0].z;
305 let mat9 = m.col[1].z;
306 let mat10 = m.col[2].z;
307
308 let t = <T as One>::one() + mat0 + mat5 + mat10;
309
310 if t > <T as Zero>::zero() {
311 let s = T::tsqrt(t) * T::two();
312
313 let x = (mat9 - mat6) / s;
314 let y = (mat2 - mat8) / s;
315 let z = (mat4 - mat1) / s;
316 let w = T::quarter() * s;
317 Self::new(x, y, z, w)
318 } else {
319 if mat0 > mat5 && mat0 > mat10 {
320 let s = T::tsqrt(<T as One>::one() + mat0 - mat5 - mat10) * T::two();
322 let x = T::quarter() * s;
323 let y = (mat4 + mat1) / s;
324 let z = (mat2 + mat8) / s;
325 let w = (mat9 - mat6) / s;
326 Self::new(x, y, z, w)
327 } else if mat5 > mat10 {
328 let s = T::tsqrt(<T as One>::one() + mat5 - mat0 - mat10) * T::two();
330 let x = (mat4 + mat1) / s;
331 let y = T::quarter() * s;
332 let z = (mat9 + mat6) / s;
333 let w = (mat2 - mat8) / s;
334 Self::new(x, y, z, w)
335 } else {
336 let s = T::tsqrt(<T as One>::one() + mat10 - mat0 - mat5) * T::two();
338 let x = (mat2 + mat8) / s;
339 let y = (mat9 + mat6) / s;
340 let z = T::quarter() * s;
341 let w = (mat4 - mat1) / s;
342 Self::new(x, y, z, w)
343 }
344 }
345 }
346
347 pub fn of_axis_angle(axis: &Vector3<T>, angle: T) -> Self {
358 let half_angle = angle * T::half();
359 let sin_a = T::tsin(half_angle);
360 let cos_a = T::tcos(half_angle);
361 let len = axis.length();
362 let n: Vector3<T> = (if len > <T as Zero>::zero() {
363 Vector3::normalize(&axis)
364 } else {
365 *axis
366 }) * sin_a;
367
368 let x = n.x;
369 let y = n.y;
370 let z = n.z;
371 let w = cos_a;
372 Self::new(x, y, z, w)
373 }
374}
375
376impl<T: FloatScalar> Add for Quat<T> {
377 type Output = Quat<T>;
378 fn add(self, rhs: Self) -> Self {
379 Self::add(&self, &rhs)
380 }
381}
382
383impl<T: FloatScalar> Sub for Quat<T> {
384 type Output = Quat<T>;
385 fn sub(self, rhs: Self) -> Self {
386 Self::sub(&self, &rhs)
387 }
388}
389
390impl<T: FloatScalar> Mul for Quat<T> {
391 type Output = Quat<T>;
392 fn mul(self, rhs: Self) -> Self {
393 Self::mul(&self, &rhs)
394 }
395}
396
397impl<T: FloatScalar> Div<T> for Quat<T> {
398 type Output = Quat<T>;
399 fn div(self, t: T) -> Self {
400 Self::divf(&self, t)
401 }
402}
403
404impl<T: FloatScalar> Mul<T> for Quat<T> {
405 type Output = Quat<T>;
406 fn mul(self, t: T) -> Self {
407 Self::mulf(&self, t)
408 }
409}
410
411macro_rules! impl_scalar {
412 ($Op:ident, $op:ident, $Opop:ident, $t:ident) => {
413 impl $Op<Quat<$t>> for $t {
414 type Output = Quat<$t>;
415 fn $op(self, q: Quat<$t>) -> Quat<$t> {
416 Quat::$Opop(self, &q)
417 }
418 }
419 };
420}
421
422impl_scalar!(Div, div, fdiv, f32);
423impl_scalar!(Mul, mul, fmul, f32);
424impl_scalar!(Div, div, fdiv, f64);
425impl_scalar!(Mul, mul, fmul, f64);
426
427#[cfg(test)]
428mod tests {
429 use crate::matrix::*;
430 use crate::scalar::*;
431 use crate::vector::*;
432 use crate::Quat;
433 use crate::*;
434
435 #[test]
436 fn test_identity() {
437 let q = Quat::<f32>::identity();
438 let m = q.mat3();
439
440 let x_axis = m.col[0];
441 let y_axis = m.col[1];
442 let z_axis = m.col[2];
443
444 assert_eq!(
445 (x_axis - Vector3::new(1.0, 0.0, 0.0)).length() < f32::epsilon(),
446 true
447 );
448 assert_eq!(
449 (y_axis - Vector3::new(0.0, 1.0, 0.0)).length() < f32::epsilon(),
450 true
451 );
452 assert_eq!(
453 (z_axis - Vector3::new(0.0, 0.0, 1.0)).length() < f32::epsilon(),
454 true
455 );
456 }
457
458 #[test]
459 fn test_identity_conjugate() {
460 let q = Quat::conjugate(&Quat::<f32>::identity());
461 let m = q.mat3();
462
463 let x_axis = m.col[0];
464 let y_axis = m.col[1];
465 let z_axis = m.col[2];
466
467 assert_eq!(
468 (x_axis - Vector3::new(1.0, 0.0, 0.0)).length() < f32::epsilon(),
469 true
470 );
471 assert_eq!(
472 (y_axis - Vector3::new(0.0, 1.0, 0.0)).length() < f32::epsilon(),
473 true
474 );
475 assert_eq!(
476 (z_axis - Vector3::new(0.0, 0.0, 1.0)).length() < f32::epsilon(),
477 true
478 );
479 }
480
481 #[test]
482 fn test_rot_180() {
483 let v = Vector3::<f32>::new(1.0, 0.0, 0.0);
484 let a = 3.14159265;
485
486 let q = Quat::of_axis_angle(&v, a);
487 let m = q.mat3();
488
489 let x_axis = m.col[0];
490 let y_axis = m.col[1];
491 let z_axis = m.col[2];
492
493 assert_eq!(
494 (x_axis - Vector3::new(1.0, 0.0, 0.0)).length() < f32::epsilon(),
495 true
496 );
497 assert_eq!(
498 (y_axis - Vector3::new(0.0, -1.0, 0.0)).length() < f32::epsilon(),
499 true
500 );
501 assert_eq!(
502 (z_axis - Vector3::new(0.0, 0.0, -1.0)).length() < f32::epsilon(),
503 true
504 );
505
506 let m2 = Matrix3::of_axis_angle(&v, a);
507
508 let x2_axis = m2.col[0];
509 let y2_axis = m2.col[1];
510 let z2_axis = m2.col[2];
511
512 assert_eq!((x_axis - x2_axis).length() < f32::epsilon(), true);
513 assert_eq!((y_axis - y2_axis).length() < f32::epsilon(), true);
514 assert_eq!((z_axis - z2_axis).length() < f32::epsilon(), true);
515 }
516
517 #[test]
518 fn test_rot_90() {
519 let v = Vector3::<f32>::new(1.0, 0.0, 0.0);
520 let a = 3.14159265 / 2.0;
521
522 let q = Quat::of_axis_angle(&v, a);
523 let m = q.mat3();
524
525 let x_axis = m.col[0];
526 let y_axis = m.col[1];
527 let z_axis = m.col[2];
528
529 assert_eq!(
530 (x_axis - Vector3::new(1.0, 0.0, 0.0)).length() < f32::epsilon(),
531 true
532 );
533 assert_eq!(
534 (y_axis - Vector3::new(0.0, 0.0, 1.0)).length() < f32::epsilon(),
535 true
536 );
537 assert_eq!(
538 (z_axis - Vector3::new(0.0, -1.0, 0.0)).length() < f32::epsilon(),
539 true
540 );
541
542 let m2 = Matrix3::of_axis_angle(&v, a);
543
544 let x2_axis = m2.col[0];
545 let y2_axis = m2.col[1];
546 let z2_axis = m2.col[2];
547
548 assert_eq!((x_axis - x2_axis).length() < f32::epsilon(), true);
549 assert_eq!((y_axis - y2_axis).length() < f32::epsilon(), true);
550 assert_eq!((z_axis - z2_axis).length() < f32::epsilon(), true);
551 }
552
553 #[test]
554 fn test_rot_45() {
555 let v = Vector3::<f32>::new(1.0, 0.0, 0.0);
556 let a = 3.14159265 / 4.0;
557
558 let q = Quat::of_axis_angle(&v, a);
559 let m = q.mat3();
560
561 let x_axis = m.col[0];
562 let y_axis = m.col[1];
563 let z_axis = m.col[2];
564
565 assert_eq!(
566 (x_axis - Vector3::new(1.0, 0.0, 0.0)).length() < f32::epsilon(),
567 true
568 );
569 assert_eq!(
570 (y_axis - Vector3::new(0.0, f32::sqrt(2.0) / 2.0, f32::sqrt(2.0) / 2.0)).length()
571 < f32::epsilon(),
572 true
573 );
574 assert_eq!(
575 (z_axis - Vector3::new(0.0, -f32::sqrt(2.0) / 2.0, f32::sqrt(2.0) / 2.0)).length()
576 < f32::epsilon(),
577 true
578 );
579
580 let m2 = Matrix3::of_axis_angle(&v, a);
581
582 let x2_axis = m2.col[0];
583 let y2_axis = m2.col[1];
584 let z2_axis = m2.col[2];
585
586 assert_eq!((x_axis - x2_axis).length() < f32::epsilon(), true);
587 assert_eq!((y_axis - y2_axis).length() < f32::epsilon(), true);
588 assert_eq!((z_axis - z2_axis).length() < f32::epsilon(), true);
589 }
590
591 #[test]
592 fn test_rot_composed_45() {
593 let v = Vector3::<f32>::new(1.0, 0.0, 0.0);
594 let a_u = 3.14159265 / 4.0;
595 let a_f = 3.14159265;
596
597 let q_u = Quat::of_axis_angle(&v, a_u);
598 let q_f = Quat::of_axis_angle(&v, a_f);
599
600 let m = q_f.mat3();
601
602 let x_axis = m.col[0];
603 let y_axis = m.col[1];
604 let z_axis = m.col[2];
605
606 let q_t = q_u * q_u * q_u * q_u;
607 let m2 = q_t.mat3();
608
609 let x2_axis = m2.col[0];
610 let y2_axis = m2.col[1];
611 let z2_axis = m2.col[2];
612
613 assert_eq!((x_axis - x2_axis).length() < f32::epsilon(), true);
614 assert_eq!((y_axis - y2_axis).length() < f32::epsilon(), true);
615 assert_eq!((z_axis - z2_axis).length() < f32::epsilon(), true);
616 }
617
618 #[test]
619 fn test_rot_composed_120() {
620 let v = Vector3::<f32>::new(1.0, 0.0, 0.0);
621 let a_u1 = 3.14159265 / 2.0;
622 let a_u2 = 3.14159265 / 6.0;
623 let a_f = 3.14159265 / 2.0 + 3.14159265 / 6.0;
624
625 let q_u1 = Quat::of_axis_angle(&v, a_u1);
626 let q_u2 = Quat::of_axis_angle(&v, a_u2);
627 let q_f = Quat::of_axis_angle(&v, a_f);
628
629 let m = q_f.mat3();
630
631 let x_axis = m.col[0];
632 let y_axis = m.col[1];
633 let z_axis = m.col[2];
634
635 let q_t = q_u2 * q_u1;
636 let m2 = q_t.mat3();
637
638 let x2_axis = m2.col[0];
639 let y2_axis = m2.col[1];
640 let z2_axis = m2.col[2];
641
642 assert_eq!((x_axis - x2_axis).length() < f32::epsilon(), true);
643 assert_eq!((y_axis - y2_axis).length() < f32::epsilon(), true);
644 assert_eq!((z_axis - z2_axis).length() < f32::epsilon(), true);
645 }
646
647 #[test]
648 fn test_rot_x_rot_y() {
649 let vx = Vector3::<f32>::new(1.0, 0.0, 0.0);
650 let vy = Vector3::<f32>::new(0.0, 1.0, 0.0);
651 let vz = Vector3::<f32>::new(0.0, 0.0, 1.0);
652
653 let v4x = Vector4::<f32>::new(1.0, 0.0, 0.0, 1.0);
654 let v4y = Vector4::<f32>::new(0.0, 1.0, 0.0, 1.0);
655 let v4z = Vector4::<f32>::new(0.0, 0.0, 1.0, 1.0);
656
657 let a = 3.14159265 / 2.0;
658
659 let q_ux = Quat::of_axis_angle(&vx, a);
660 let q_uy = Quat::of_axis_angle(&vy, a);
661 let q_uz = Quat::of_axis_angle(&vz, a);
662
663 let mx = q_ux.mat3();
664 let m4x = q_ux.mat4();
665
666 let px = (m4x * v4x).xyz();
667 let py = (m4x * v4y).xyz();
668 let pz = (m4x * v4z).xyz();
669
670 let x_axis = mx.col[0];
671 let y_axis = mx.col[1];
672 let z_axis = mx.col[2];
673
674 assert_eq!((x_axis - vx).length() < f32::epsilon(), true);
675 assert_eq!((y_axis - vz).length() < f32::epsilon(), true);
676 assert_eq!((z_axis - -vy).length() < f32::epsilon(), true);
677
678 assert_eq!((px - vx).length() < f32::epsilon(), true);
679 assert_eq!((py - vz).length() < f32::epsilon(), true);
680 assert_eq!((pz - -vy).length() < f32::epsilon(), true);
681
682 let q_yx = q_uy * q_ux;
684 let myx = q_yx.mat3();
685 let m4yx = q_yx.mat4();
686
687 let px = (m4yx * v4x).xyz();
688 let py = (m4yx * v4y).xyz();
689 let pz = (m4yx * v4z).xyz();
690
691 let x_axis = myx.col[0];
692 let y_axis = myx.col[1];
693 let z_axis = myx.col[2];
694
695 assert_eq!((x_axis - -vz).length() < f32::epsilon(), true);
696 assert_eq!((y_axis - vx).length() < f32::epsilon(), true);
697 assert_eq!((z_axis - -vy).length() < f32::epsilon(), true);
698
699 assert_eq!((px - -vz).length() < f32::epsilon(), true);
700 assert_eq!((py - vx).length() < f32::epsilon(), true);
701 assert_eq!((pz - -vy).length() < f32::epsilon(), true);
702
703 let q_zyx = q_uz * q_uy * q_ux;
705 let mzyx = q_zyx.mat3();
706
707 let m4zyx = q_zyx.mat4();
708
709 let px = (m4zyx * v4x).xyz();
710 let py = (m4zyx * v4y).xyz();
711 let pz = (m4zyx * v4z).xyz();
712
713 let x_axis = mzyx.col[0];
714 let y_axis = mzyx.col[1];
715 let z_axis = mzyx.col[2];
716
717 assert_eq!((x_axis - -vz).length() < f32::epsilon(), true);
718 assert_eq!((y_axis - vy).length() < f32::epsilon(), true);
719 assert_eq!((z_axis - vx).length() < f32::epsilon(), true);
720
721 assert_eq!((px - -vz).length() < f32::epsilon(), true);
722 assert_eq!((py - vy).length() < f32::epsilon(), true);
723 assert_eq!((pz - vx).length() < f32::epsilon(), true);
724 }
725
726 #[test]
727 fn test_axis_angle_f32() {
728 let v = Vector3::normalize(&Vector3::<f32>::new(1.0, 2.0, 3.0));
729 let q0 = Quat::of_axis_angle(&v, 3.0);
730 let (v2, a) = q0.to_axis_angle();
731 assert_eq!((v.x - v2.x).abs() < f32::epsilon(), true);
732 assert_eq!((v.y - v2.y).abs() < f32::epsilon(), true);
733 assert_eq!((v.z - v2.z).abs() < f32::epsilon(), true);
734 assert_eq!((a - 3.0).abs() < f32::epsilon(), true);
735 }
736
737 #[test]
738 fn test_axis_angle_f64() {
739 let v = Vector3::normalize(&Vector3::<f64>::new(1.0, 2.0, 3.0));
740 let q0 = Quat::of_axis_angle(&v, 3.0);
741 let (v2, a) = q0.to_axis_angle();
742 assert_eq!((v.x - v2.x).abs() < f64::epsilon(), true);
743 assert_eq!((v.y - v2.y).abs() < f64::epsilon(), true);
744 assert_eq!((v.z - v2.z).abs() < f64::epsilon(), true);
745 assert_eq!((a - 3.0).abs() < f64::epsilon(), true);
746 }
747
748 #[test]
749 fn test_quaternion_normalization() {
750 let q = Quat::<f32>::new(1.0, 2.0, 3.0, 4.0);
752 let nq = Quat::normalize(&q);
753 let len = nq.length();
754 assert!((len - 1.0).abs() < f32::epsilon());
755
756 let q_zero = Quat::<f32>::new(0.0, 0.0, 0.0, 0.0);
758 let nq_zero = Quat::normalize(&q_zero);
759 assert_eq!(nq_zero.x, 0.0);
760 assert_eq!(nq_zero.y, 0.0);
761 assert_eq!(nq_zero.z, 0.0);
762 assert_eq!(nq_zero.w, 0.0);
763
764 let q_unit = Quat::<f32>::identity();
766 let nq_unit = Quat::normalize(&q_unit);
767 assert!((nq_unit.length() - 1.0).abs() < f32::epsilon());
768 }
769
770 #[test]
771 fn test_quaternion_inverse() {
772 let q = Quat::<f32>::of_axis_angle(&Vector3::new(0.0, 1.0, 0.0), 1.57079632);
773 let q_inv = Quat::inverse(&q);
774 let product = q * q_inv;
775
776 assert!((product.x).abs() < 0.001);
778 assert!((product.y).abs() < 0.001);
779 assert!((product.z).abs() < 0.001);
780 assert!((product.w - 1.0).abs() < 0.001);
781 }
782
783 #[test]
784 fn test_quaternion_multiplication() {
785 let q1 = Quat::<f32>::of_axis_angle(&Vector3::new(1.0, 0.0, 0.0), 0.5);
787 let q2 = Quat::<f32>::of_axis_angle(&Vector3::new(0.0, 1.0, 0.0), 0.5);
788 let q3 = Quat::<f32>::of_axis_angle(&Vector3::new(0.0, 0.0, 1.0), 0.5);
789
790 let left = (q1 * q2) * q3;
792 let right = q1 * (q2 * q3);
793 assert!((left.x - right.x).abs() < f32::epsilon());
794 assert!((left.y - right.y).abs() < f32::epsilon());
795 assert!((left.z - right.z).abs() < f32::epsilon());
796 assert!((left.w - right.w).abs() < f32::epsilon());
797
798 let identity = Quat::<f32>::identity();
800 let result = q1 * identity;
801 assert!((result.x - q1.x).abs() < f32::epsilon());
802 assert!((result.y - q1.y).abs() < f32::epsilon());
803 assert!((result.z - q1.z).abs() < f32::epsilon());
804 assert!((result.w - q1.w).abs() < f32::epsilon());
805 }
806
807 #[test]
808 fn test_quaternion_addition_subtraction() {
809 let q1 = Quat::<f32>::new(1.0, 2.0, 3.0, 4.0);
810 let q2 = Quat::<f32>::new(5.0, 6.0, 7.0, 8.0);
811
812 let sum = q1 + q2;
813 assert_eq!(sum.x, 6.0);
814 assert_eq!(sum.y, 8.0);
815 assert_eq!(sum.z, 10.0);
816 assert_eq!(sum.w, 12.0);
817
818 let diff = q2 - q1;
819 assert_eq!(diff.x, 4.0);
820 assert_eq!(diff.y, 4.0);
821 assert_eq!(diff.z, 4.0);
822 assert_eq!(diff.w, 4.0);
823 }
824
825 #[test]
826 fn test_quaternion_scalar_multiplication() {
827 let q = Quat::<f32>::new(1.0, 2.0, 3.0, 4.0);
828 let scalar = 2.0;
829
830 let result1 = q * scalar;
831 assert_eq!(result1.x, 2.0);
832 assert_eq!(result1.y, 4.0);
833 assert_eq!(result1.z, 6.0);
834 assert_eq!(result1.w, 8.0);
835
836 let result2 = scalar * q;
837 assert_eq!(result2.x, 2.0);
838 assert_eq!(result2.y, 4.0);
839 assert_eq!(result2.z, 6.0);
840 assert_eq!(result2.w, 8.0);
841
842 let result3 = q / scalar;
843 assert_eq!(result3.x, 0.5);
844 assert_eq!(result3.y, 1.0);
845 assert_eq!(result3.z, 1.5);
846 assert_eq!(result3.w, 2.0);
847 }
848
849 #[test]
850 fn test_to_axis_angle_edge_cases() {
851 let q_identity = Quat::<f32>::identity();
853 let (axis, angle) = q_identity.to_axis_angle();
854 assert!((angle).abs() < 0.001);
855
856 let q_180 = Quat::<f32>::of_axis_angle(&Vector3::new(0.0, 1.0, 0.0), 3.14159265);
858 let (axis_180, angle_180) = q_180.to_axis_angle();
859 assert!((angle_180 - 3.14159265).abs() < 0.001);
860 assert!((axis_180.y - 1.0).abs() < 0.001);
861
862 let small_angle = 0.001;
864 let q_small = Quat::<f32>::of_axis_angle(&Vector3::new(1.0, 0.0, 0.0), small_angle);
865 let (axis_small, angle_small) = q_small.to_axis_angle();
866 assert!((angle_small - small_angle).abs() < 0.0001);
867 }
868
869 #[test]
870 fn test_matrix_quaternion_conversion() {
871 let angles = [0.0, 0.5, 1.0, 1.57, 3.14159];
873 let axes = [
874 Vector3::<f32>::new(1.0, 0.0, 0.0),
875 Vector3::<f32>::new(0.0, 1.0, 0.0),
876 Vector3::<f32>::new(0.0, 0.0, 1.0),
877 Vector3::<f32>::normalize(&Vector3::new(1.0, 1.0, 1.0)),
878 ];
879
880 for angle in &angles {
881 for axis in &axes {
882 let q1 = Quat::of_axis_angle(axis, *angle);
883 let mat = q1.mat3();
884 let q2 = Quat::of_matrix3(&mat);
885
886 let dot_product = Quat::dot(&q1, &q2);
888 let q2_adjusted = if dot_product < 0.0 {
889 Quat::neg(&q2)
890 } else {
891 q2
892 };
893
894 assert!((q1.x - q2_adjusted.x).abs() < 0.001);
895 assert!((q1.y - q2_adjusted.y).abs() < 0.001);
896 assert!((q1.z - q2_adjusted.z).abs() < 0.001);
897 assert!((q1.w - q2_adjusted.w).abs() < 0.001);
898 }
899 }
900 }
901
902 #[test]
903 fn test_quaternion_conjugate() {
904 let q = Quat::<f32>::new(1.0, 2.0, 3.0, 4.0);
905 let conj = Quat::conjugate(&q);
906
907 assert_eq!(conj.x, -1.0);
908 assert_eq!(conj.y, -2.0);
909 assert_eq!(conj.z, -3.0);
910 assert_eq!(conj.w, 4.0);
911
912 let conj_conj = Quat::conjugate(&conj);
914 assert_eq!(conj_conj.x, q.x);
915 assert_eq!(conj_conj.y, q.y);
916 assert_eq!(conj_conj.z, q.z);
917 assert_eq!(conj_conj.w, q.w);
918 }
919
920 #[test]
921 fn test_quaternion_dot_product() {
922 let q1 = Quat::<f32>::new(1.0, 2.0, 3.0, 4.0);
923 let q2 = Quat::<f32>::new(5.0, 6.0, 7.0, 8.0);
924
925 let dot = Quat::dot(&q1, &q2);
926 let expected = 1.0*5.0 + 2.0*6.0 + 3.0*7.0 + 4.0*8.0;
927 assert_eq!(dot, expected);
928
929 let self_dot = Quat::dot(&q1, &q1);
931 let length_squared = q1.length() * q1.length();
932 assert!((self_dot - length_squared).abs() < 0.0001);
933 }
934}