1use std::{fmt, ops::{Add, Div, Mul, Neg, Rem, Sub}};
6
7use crate::{Construct, F32Fmt, One, SignOps, Two, Zero, axes::{self, Axes}, imaginary::ImaginaryConstruct, linear_algebra::{
8 vector4::Vector4,
9 vector3::Vector3,
10 matrix3::Matrix3
11 }};
12
13use super::{Rotation, euler::Euler, rotor::Rotor};
14
15#[derive(Clone, Copy)]
30pub struct Quaternion<T>(pub T, pub T, pub T, pub T);
31
32impl<T> PartialEq for Quaternion<T>
33where T: Neg<Output = T> + PartialEq + Copy {
34 fn eq(&self, other: &Self) -> bool {
35 let neg = -*other;
36 (self.0 == other.0 && self.1 == other.1 && self.2 == other.2 && self.3 == other.3) ||
37 (self.0 == neg.0 && self.1 == neg.1 && self.2 == neg.2 && self.3 == neg.3)
38 }
39}
40
41impl<T> Quaternion<T> {
42 pub fn new(a: T, b: T, c: T, r: T) -> Self {
49 Quaternion(a, b, c, r)
50 }
51
52 pub fn new_vector_real(vector: Vector3<T>, real: T) -> Self {
57 Quaternion(vector.0, vector.1, vector.2, real)
58 }
59
60 pub fn new_axis_angle(axis: Vector3<T>, angle: T) -> Self
65 where T: Mul<T, Output = T> + Div<T, Output = T> + Add<T, Output = T> + F32Fmt + fmt::Debug + One + Two + Copy { let normalized_axis = axis.normalize(None);
67 let half_angle = angle / T::TWO;
69 Quaternion(
70 T::sin_mul(half_angle, normalized_axis.0),
71 T::sin_mul(half_angle, normalized_axis.1),
72 T::sin_mul(half_angle, normalized_axis.2),
73 T::cos_mul(half_angle, T::ONE)
74 )
75 }
76
77 pub fn identity() -> Self
82 where T: Zero + One {
83 Quaternion::ONE }
85
86 pub fn identity_add() -> Self
90 where T: Zero {
91 Quaternion::ZERO }
93
94 pub fn conjugate(&self) -> Self
101 where T: Neg<Output = T> + Copy {
102 Quaternion(-self.0, -self.1, -self.2, self.3)
103 }
104
105 pub fn norm(&self) -> T
112 where T: Add<T, Output = T> + Mul<T, Output = T> + F32Fmt + Copy {
113 (self.0 * self.0 + self.1 * self.1 + self.2 * self.2 + self.3 * self.3).sqrt()
116 }
117
118 pub fn unit_quaternion(&self) -> Self
125 where T: Add<T, Output = T> + Mul<T, Output = T> + Div<T, Output = T> + F32Fmt + Copy {
126 *self / self.norm()
127 }
128
129 pub fn reciprocal(&self) -> Self
136 where T: Add<T, Output = T> + Mul<T, Output = T> + Div<T, Output = T> + Neg<Output = T> + Copy + One {
137 self.conjugate() / (self.0 * self.0 + self.1 * self.1 + self.2 * self.2 + self.3 * self.3)
138 }
139
140 pub fn slerp(self, to: Self, time_stamp: T::F32Fmt) -> Self
141 where T: F32Fmt + One + Mul<T, Output = T> + Add<T, Output = T> + Sub<T, Output = T> + Neg<Output = T> + Copy + Div<T, Output = T>{
142 let self_conj = self.conjugate();
143 let cos_half_angle = (self_conj.3 * to.3 - self_conj.0 * to.0 - self_conj.1 * to.1 - self_conj.2 * to.2).intoF32Fmt();
144 if cos_half_angle.abs() == T::F32Fmt::ONE {
145 return self;
146 }
147 let half_angle = cos_half_angle.acos_mul(T::F32Fmt::ONE);
148
149 Self::fromF32Fmt(
150 (
151 self.intoF32Fmt() * ((T::F32Fmt::ONE - time_stamp) * half_angle).sin_mul(T::F32Fmt::ONE)
152 + to.intoF32Fmt() * (time_stamp * half_angle)
153 ) / (T::F32Fmt::ONE - cos_half_angle).sqrt()
154 )
155 }
156
157 pub fn sin(self) -> Self
158 where T: Copy + F32Fmt + One + Sub<T, Output = T> + Add<T, Output = T> + Mul<T, Output = T> + Neg<Output = T>{
159 let a = self.3; let b = self.0;
186 let c = self.1;
187 let d = self.2;
188 Quaternion::new(
189 a.sin_mul(b.cosh_mul(c.cosh_mul(d.cosh_mul(T::ONE)))) + a.cos_mul(b.sinh_mul(c.sinh_mul(d.sinh_mul(T::ONE)))),
190 -a.sin_mul(b.cosh_mul(c.sinh_mul(d.sinh_mul(T::ONE)))) + a.cos_mul(b.sinh_mul(c.cosh_mul(d.cosh_mul(T::ONE)))),
191 a.cos_mul(b.cosh_mul(c.sinh_mul(d.cosh_mul(T::ONE)))) + a.sin_mul(b.sinh_mul(c.cosh_mul(d.sinh_mul(T::ONE)))),
192 a.cos_mul(b.cosh_mul(c.cosh_mul(d.sinh_mul(T::ONE)))) - a.sin_mul(b.sinh_mul(c.sinh_mul(d.cosh_mul(T::ONE)))),
193 )
194 }
195
196 pub fn cos(self) -> Self{
197 todo!();
199 }
200
201 pub fn tan(self) -> Self{
202 todo!();
203 }
204}
205
206impl Quaternion<f32> {
207 pub fn camera_look_at_v1(pos: Vector3<f32>, look_at: Vector3<f32>) -> Self { let frd_camrel = (look_at - pos).normalize(None);
210 let right_camrel = Vector3::cross_product(axes::NORMAL_Y_AXIS, frd_camrel).normalize(None); Quaternion::from_axes(right_camrel, frd_camrel)
213 }
214
215 pub fn from_axes(left: Vector3<f32>, frd: Vector3<f32>) -> Self { let up = Vector3::cross_product( frd, left); let derived_rot_mat = Matrix3::new( left.into(),
226 up.into(),
227 frd.into(),
228 ).transpose();
229
230 derived_rot_mat.into()
231 }
232
233 pub fn camera_look_at(pos: Vector3<f32>, look_at: Vector3<f32>) -> Quaternion<f32> {
255 Quaternion::look_at_xy(look_at, pos)
256 }
257
258 pub fn f32_identity() -> Self{
259 Quaternion::new( 0.0_f32, 0.0_f32, 0.0_f32, 1.0_f32)
260 }
261}
262
263impl<T> Construct<T> for Quaternion<T> where T: Construct<T> {}
264impl<T> ImaginaryConstruct<T> for Quaternion<T> where T: Construct<T> {}
265impl<T> Rotation<T> for Quaternion<T> where T: Construct<T> {
266 fn look_at_xy(pos: Vector3<T>, look_at: Vector3<T>) -> Self {
274 let frd_camrel = (look_at - pos).normalize(None);
275 let right_camrel = Vector3::cross_product(Self::Y_AXIS, frd_camrel).normalize(None);
276
277 let frd_no_y = Vector3::cross_product(right_camrel, Self::Y_AXIS).normalize(None);let self_x_axis_turn = T::asin_mul(
287 Vector3::dot_product(-Self::Y_AXIS, frd_camrel),
288 T::ONE
289 );
290
291 let self_y_axis_turn = T::atan2_mul(
292 Vector3::dot_product(Self::X_AXIS, frd_no_y),
293 Vector3::dot_product(Self::X_AXIS, right_camrel),
294 T::ONE
295 );
296
297 Quaternion::new_axis_angle(right_camrel, self_x_axis_turn) *
298 Quaternion::new_axis_angle(Self::Y_AXIS, self_y_axis_turn)
299 }
300
301 fn look_at_xz(_pos: Vector3<T>, _look_at: Vector3<T>) -> Self {
302 todo!()
303 }
304
305 fn look_at_yz(_pos: Vector3<T>, _look_at: Vector3<T>) -> Self {
306 todo!()
307 }
308
309 fn look_at_lock(_pos: Vector3<T>, _look_at: Vector3<T>, _locked_axis: Vector3<T>) -> Self {
310 todo!()
311 }
312
313 fn camera_look_at_xy(pos: Vector3<T>, look_at: Vector3<T>) -> Self { Quaternion::look_at_xy(look_at, pos) }
321
322 fn camera_look_at_xz(pos: Vector3<T>, look_at: Vector3<T>) -> Self { Quaternion::look_at_xz(look_at, pos) }
323
324 fn camera_look_at_yz(pos: Vector3<T>, look_at: Vector3<T>) -> Self { Quaternion::look_at_yz(look_at, pos) }
325
326 fn camera_look_at_lock(pos: Vector3<T>, look_at: Vector3<T>, locked_axis: Vector3<T>) -> Self {
327 Quaternion::look_at_lock(look_at, pos, locked_axis)
328 }
329}
330impl<T> F32Fmt for Quaternion<T>
331where T: F32Fmt + Copy + Mul<T, Output = T> + Add<T, Output = T> + Sub<T, Output = T> + Div<T, Output = T> + Neg<Output = T> + One {
332 type F32Fmt = Quaternion<T::F32Fmt>;
333 #[inline]
334 fn intoF32Fmt(self) -> Self::F32Fmt {
335 Quaternion(self.0.intoF32Fmt(), self.1.intoF32Fmt(), self.2.intoF32Fmt(), self.3.intoF32Fmt())
336 }
337 #[inline]
338 fn fromF32Fmt(f32_fmt: Self::F32Fmt) -> Self {
339 let vec = &f32_fmt;
340 Quaternion(T::fromF32Fmt(vec.0), T::fromF32Fmt(vec.1), T::fromF32Fmt(f32_fmt.2), T::fromF32Fmt(f32_fmt.3))
341 }
342
343 fn sqrt(self) -> Self {
344 let v_part = Vector3(self.0, self.1, self.2);
345 let r_part = self.3;
346
347 let block0 = (self.norm() + r_part).f32_const_mul(0.5).sqrt();
348
349 Quaternion::new_vector_real(v_part.unit_vector() * block0, block0)
350 }
351
352 fn cbrt(self) -> Self {
353 todo!();
354 }
355
356 fn f32_const_mul(self, constant: f32) -> Self {
357 Quaternion(
358 self.0.f32_const_mul(constant),
359 self.1.f32_const_mul(constant),
360 self.2.f32_const_mul(constant),
361 self.3.f32_const_mul(constant)
362 )
363 }
364
365 fn sin_mul(self, mul_by: Self) -> Self where Self: Mul<Self, Output = Self> + Sized {
366 self.sin() * mul_by
367 }
368
369 fn cos_mul(self, mul_by: Self) -> Self where Self: Mul<Self, Output = Self> + Sized {
370 self.cos() * mul_by
371 }
372
373 fn tan_mul(self, mul_by: Self) -> Self where Self: Mul<Self, Output = Self> + Sized {
374 self.tan() * mul_by
375 }
376
377 fn asin_mul(self, _mul_by: Self) -> Self where Self: Mul<Self, Output = Self> + Sized {
378 todo!()
379 }
380
381 fn acos_mul(self, _mul_by: Self) -> Self where Self: Mul<Self, Output = Self> + Sized {
382 todo!()
383 }
384
385 fn atan_mul(self, _mul_by: Self) -> Self where Self: Mul<Self, Output = Self> + Sized {
386 todo!()
387 }
388
389 fn atan2_mul(self, _other: Self, _mul_by: Self) -> Self where Self: Mul<Self, Output = Self> + Sized {
390 todo!()
391 }
392
393 fn sinh_mul(self, _mul_by: Self) -> Self where Self: Mul<Self, Output = Self> + Sized {
394 todo!()
395 }
396
397 fn cosh_mul(self, _mul_by: Self) -> Self where Self: Mul<Self, Output = Self> + Sized {
398 todo!()
399 }
400
401 fn tanh_mul(self, _mul_by: Self) -> Self where Self: Mul<Self, Output = Self> + Sized {
402 todo!()
403 }
404}
405
406impl<T> From<Matrix3<T>> for Quaternion<T>
407where T: F32Fmt + Add<T, Output = T> + Sub<T, Output = T> + Div<T, Output = T> + Mul<T, Output = T> + fmt::Debug + Two + One + Zero + Copy {
408 fn from(mat3: Matrix3<T>) -> Self {
409 let axis = mat3.eigen_vector(T::ONE); let trace = mat3.trace();
418 let angle = T::acos_mul((trace - T::ONE) / T::TWO, T::ONE);
419
420 Quaternion::new_axis_angle(axis, angle)
421 }
422}
423impl<T> From<Axes<T>> for Quaternion<T>
424where T: Construct<T> + Copy {
425 fn from(a: Axes<T>) -> Self {
426 Into::<Matrix3<T>>::into(a).into()
427 }
428}
429impl<T> From<Euler<T>> for Quaternion<T>
430where T: Construct<T> + Copy {
431 fn from(e: Euler<T>) -> Self {
432 Into::<Matrix3<T>>::into(e).into()
433 }
434}
435impl<T> From<Rotor<T>> for Quaternion<T>
436where T: Construct<T> + Copy {
437 fn from(r: Rotor<T>) -> Self {
438 Into::<Matrix3<T>>::into(r).into()
439 }
440}
441
442impl<T> From<Quaternion<T>> for Matrix3<T>
443where T: Add<T, Output = T> + Sub<T, Output = T> + Mul<T, Output = T> + Div<T, Output = T> + Neg<Output = T> + Copy + One + Two {
444 fn from(other: Quaternion<T>) -> Matrix3<T> {
445 let i = other.0; let i_squared = i * i;
446 let j = other.1; let j_squared = j * j;
447 let k = other.2; let k_squared = k * k;
448 let r = other.3; let two: T = T::TWO;
453 let one: T = T::ONE;
454 let two_s: T = two / (i_squared + j_squared + k_squared + r * r);
470
471 Matrix3::new(
472 [one - two_s * (j_squared + k_squared), two_s * (i * j - k * r), two_s * (i * k + j * r)],
473 [ two_s * (i * j + k * r), one - two_s * (i_squared + k_squared), two_s * (j * k - i * r)],
474 [ two_s * (i * k - j * r), two_s * (j * k + i * r), one - two_s * (i_squared + j_squared)],
475 )
476 }
477}
478impl<T> From<Quaternion<T>> for Vector4<T> where T: Copy { fn from(other: Quaternion<T>) -> Vector4<T> { Vector4(other.0, other.1, other.2, other.3) } } impl<T> From<Quaternion<T>> for Vector3<T> where T: Copy { fn from(other: Quaternion<T>) -> Vector3<T> { Vector3(other.0, other.1, other.2) } } impl<T> From<Quaternion<T>> for [T; 4] where T: Copy { fn from(other: Quaternion<T>) -> [T; 4] { [other.0, other.1, other.2, other.3] } }
481impl<T> fmt::Debug for Quaternion<T> where T: Copy + fmt::Debug {
482 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
483 write!(f, "{:?}i + {:?}j + {:?}k + {:?}", self.0, self.1, self.2, self.3)
484 }
485}
486
487impl<T> Zero for Quaternion<T> where T: Zero { const ZERO: Self = Quaternion(T::ZERO, T::ZERO, T::ZERO, T::ZERO); }
488impl<T> One for Quaternion<T> where T: One + Zero { const ONE: Self = Quaternion(T::ZERO, T::ZERO, T::ZERO, T::ONE); }
489impl<T> Two for Quaternion<T> where T: Two + Zero { const TWO: Self = Quaternion(T::ZERO, T::ZERO, T::ZERO, T::TWO); }
490
491
492impl<T> Add for Quaternion<T>
493where T: Add<T, Output = T> + Copy {
494 type Output = Self;
495
496 fn add(self, rhs: Self) -> Self::Output {
497 Quaternion(self.0 + rhs.0, self.1 + rhs.1, self.2 + rhs.2, self.3 + rhs.3)
498 }
499}
500impl<T> Add<T> for Quaternion<T>
501where T: Add<T, Output = T> + Copy {
502 type Output = Self;
503
504 fn add(self, rhs: T) -> Self::Output {
505 Quaternion(self.0 + rhs, self.1 + rhs, self.2 + rhs, self.3 + rhs)
506 }
507}
508
509impl<T> Sub for Quaternion<T>
510where T: Sub<T, Output = T> + Copy {
511 type Output = Self;
512
513 fn sub(self, rhs: Self) -> Self::Output {
514 Quaternion(self.0 - rhs.0, self.1 - rhs.1, self.2 - rhs.2, self.3 - rhs.3)
515 }
516}
517impl<T> Sub<T> for Quaternion<T>
518where T: Sub<T, Output = T> + Copy {
519 type Output = Self;
520
521 fn sub(self, rhs: T) -> Self::Output {
522 Quaternion(self.0 - rhs, self.1 - rhs, self.2 - rhs, self.3 - rhs)
523 }
524}
525
526impl<T> Mul for Quaternion<T>
527where T: Sub<T, Output = T> + Mul<T, Output = T> + Add<T, Output = T> + Copy {
528 type Output = Self;
529
530 fn mul(self, rhs: Self) -> Self::Output {
532 let r = self.3 * rhs.3 - self.0 * rhs.0 - self.1 * rhs.1 - self.2 * rhs.2;
544 let i = self.3 * rhs.0 + self.0 * rhs.3 + self.1 * rhs.2 - self.2 * rhs.1;
545 let j = self.3 * rhs.1 - self.0 * rhs.2 + self.1 * rhs.3 + self.2 * rhs.0;
546 let k = self.3 * rhs.2 + self.0 * rhs.1 - self.1 * rhs.0 + self.2 * rhs.3;
547
548 Quaternion(i, j, k, r)
549
550 }
559}
560impl<T> Mul<T> for Quaternion<T>
561where T: Mul<T, Output = T> + Copy {
562 type Output = Self;
563
564 fn mul(self, rhs: T) -> Self::Output {
565 Quaternion(self.0 * rhs, self.1 * rhs, self.2 * rhs, self.3 * rhs)
566 }
567}
568
569impl<T> Div for Quaternion<T>
570where T: Copy + Neg<Output = T> + Sub<T, Output = T> + Add<T, Output = T> + Div<T, Output = T> {
571 type Output = Self;
572
573 #[allow(clippy::many_single_char_names)]
574 fn div(self, rhs: Self) -> Self::Output {
575 let Quaternion(a, b, c, d) = self;
614 let Quaternion(e, f, g, h) = rhs;
615
616 Quaternion(
617 -a/f + b/e - c/h + d/g,
618 -a/g + b/h + c/e - d/f,
619 -a/h - b/g + c/f + d/e,
620 a/e + b/f + c/g + d/h
621 )
622 }
623}
624impl<T> Div<T> for Quaternion<T>
625where T: Div<T, Output = T> + Copy {
626 type Output = Self;
627
628 fn div(self, rhs: T) -> Self::Output {
629 Quaternion(self.0 / rhs, self.1 / rhs, self.2 / rhs, self.3 / rhs)
630 }
631}
632
633impl<T> Rem for Quaternion<T>
634where T: Copy + Neg<Output = T> + Sub<T, Output = T> + Add<T, Output = T> + Rem<T, Output = T> {
635 type Output = Self;
636
637 #[allow(clippy::many_single_char_names)]
639 fn rem(self, rhs: Self) -> Self::Output {
640 let Quaternion(a, b, c, d) = self;
643 let Quaternion(e, f, g, h) = rhs;
644
645 Quaternion(
646 -a%f + b%e - c%h + d%g,
647 -a%g + b%h + c%e - d%f,
648 -a%h - b%g + c%f + d%e,
649 a%e + b%f + c%g + d%h
650 )
651 }
652}
653
654impl<T> Rem<T> for Quaternion<T>
655where T: Rem<T, Output = T> + Copy {
656 type Output = Self;
657
658 fn rem(self, rhs: T) -> Self::Output {
659 Quaternion(self.0 % rhs, self.1 % rhs, self.2 % rhs, self.3 % rhs)
660 }
661}
662
663impl<T> Neg for Quaternion<T>
664where T: Neg<Output = T> + Copy {
665 type Output = Self;
666
667 fn neg(self) -> Self::Output {
668 Quaternion(-self.0, -self.1, -self.2, -self.3)
669 }
670}
671
672impl<T> SignOps for Quaternion<T>
673where T: SignOps + Add<T, Output = T> {
674 fn ptcopysign(self, sign: Self) -> Self {
675 Quaternion(
676 self.0.ptcopysign(sign.0),
677 self.1.ptcopysign(sign.1),
678 self.2.ptcopysign(sign.2),
679 self.3.ptcopysign(sign.3)
680 )
681 }
682
683 fn ptsignum(self) -> i8 {
685 (self.0 + self.1 + self.2 + self.3).ptsignum()
686 }
687
688 fn abs(self) -> Self {
689 Quaternion(
690 self.0.abs(),
691 self.1.abs(),
692 self.2.abs(),
693 self.3.abs()
694 )
695 }
696}