[go: up one dir, main page]

mint/
rotation.rs

1use crate::vector::Vector3;
2use crate::IntoMint;
3use core::marker::PhantomData;
4
5/// Standard quaternion represented by the scalar and vector parts.
6/// Useful for representing rotation in 3D space.
7/// Corresponds to a right-handed rotation matrix.
8#[derive(Clone, Copy, Debug, Hash, PartialEq, PartialOrd, Eq, Ord)]
9#[repr(C)]
10pub struct Quaternion<T> {
11    /// Vector part of a quaternion.
12    pub v: Vector3<T>,
13    /// Scalar part of a quaternion.
14    pub s: T,
15}
16
17impl<T> IntoMint for Quaternion<T> {
18    type MintType = Quaternion<T>;
19}
20
21impl<T> From<[T; 4]> for Quaternion<T> {
22    fn from([x, y, z, s]: [T; 4]) -> Self {
23        Quaternion {
24            s,
25            v: Vector3::from([x, y, z]),
26        }
27    }
28}
29
30impl<T> From<Quaternion<T>> for [T; 4] {
31    fn from(quaternion: Quaternion<T>) -> [T; 4] {
32        [quaternion.v.x, quaternion.v.y, quaternion.v.z, quaternion.s]
33    }
34}
35
36impl<T> AsRef<[T; 4]> for Quaternion<T> {
37    fn as_ref(&self) -> &[T; 4] {
38        unsafe { ::core::mem::transmute(self) }
39    }
40}
41
42impl<T> AsMut<[T; 4]> for Quaternion<T> {
43    fn as_mut(&mut self) -> &mut [T; 4] {
44        unsafe { ::core::mem::transmute(self) }
45    }
46}
47
48#[cfg(feature = "serde")]
49impl<T> ::serde::Serialize for Quaternion<T>
50where
51    T: ::serde::Serialize,
52{
53    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
54    where
55        S: ::serde::Serializer,
56    {
57        AsRef::<[T; 4]>::as_ref(self).serialize(serializer)
58    }
59}
60
61#[cfg(feature = "serde")]
62impl<'de, T> ::serde::Deserialize<'de> for Quaternion<T>
63where
64    T: ::serde::Deserialize<'de>,
65{
66    fn deserialize<S>(deserializer: S) -> Result<Self, S::Error>
67    where
68        S: ::serde::Deserializer<'de>,
69    {
70        <[T; 4]>::deserialize(deserializer).map(Quaternion::<T>::from)
71    }
72}
73
74/// Abstract set of Euler angles in 3D space. The basis of angles
75/// is defined by the generic parameter `B`.
76///
77/// Note: there are multiple notations of Euler angles. They are
78/// split in two groups:
79///   - intrinsic (also known as "Tait-Bryan angles"): rotate around local axis
80///   - extrinsic (also known as "Proper Euler angles"): rotate around world axis
81/// For each interpretation, different axis may be chosen in different order.
82#[derive(Clone, Copy, Debug, Hash, PartialEq, PartialOrd, Eq, Ord)]
83#[repr(C)]
84pub struct EulerAngles<T, B> {
85    /// First angle of rotation in range [-pi, pi] (_pitch_).
86    pub a: T,
87    /// Second angle of rotation around in range [-pi/2, pi/2] (_yaw_).
88    pub b: T,
89    /// Third angle of rotation in range [-pi, pi] (_roll_).
90    pub c: T,
91    /// Marker for the phantom basis.
92    pub marker: PhantomData<B>,
93}
94
95/// Intrinsic rotation around X, then Y, then Z axis.
96#[derive(Clone, Copy, Debug, Hash, PartialEq, PartialOrd, Eq, Ord)]
97pub enum IntraXYZ {}
98/// Intrinsic rotation around Z, then X, then Z axis.
99#[derive(Clone, Copy, Debug, Hash, PartialEq, PartialOrd, Eq, Ord)]
100pub enum IntraZXZ {}
101/// Intrinsic rotation around Z, then Y, then X axis.
102#[derive(Clone, Copy, Debug, Hash, PartialEq, PartialOrd, Eq, Ord)]
103pub enum IntraZYX {}
104/// Extrinsic rotation around X, then Y, then Z axis.
105#[derive(Clone, Copy, Debug, Hash, PartialEq, PartialOrd, Eq, Ord)]
106pub enum ExtraXYZ {}
107/// Extrinsic rotation around Z, then X, then Z axis.
108#[derive(Clone, Copy, Debug, Hash, PartialEq, PartialOrd, Eq, Ord)]
109pub enum ExtraZXZ {}
110/// Extrinsic rotation around Z, then Y, then X axis.
111#[derive(Clone, Copy, Debug, Hash, PartialEq, PartialOrd, Eq, Ord)]
112pub enum ExtraZYX {}
113
114impl<T, B> From<[T; 3]> for EulerAngles<T, B> {
115    fn from([a, b, c]: [T; 3]) -> Self {
116        EulerAngles {
117            a,
118            b,
119            c,
120            marker: PhantomData,
121        }
122    }
123}
124
125impl<T, B> From<EulerAngles<T, B>> for [T; 3] {
126    fn from(euler: EulerAngles<T, B>) -> [T; 3] {
127        [euler.a, euler.b, euler.c]
128    }
129}
130
131#[cfg(feature = "serde")]
132impl<T, B> ::serde::Serialize for EulerAngles<T, B>
133where
134    T: ::serde::Serialize,
135{
136    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
137    where
138        S: ::serde::Serializer,
139    {
140        [&self.a, &self.b, &self.c].serialize(serializer)
141    }
142}
143
144#[cfg(feature = "serde")]
145impl<'de, T, B> ::serde::Deserialize<'de> for EulerAngles<T, B>
146where
147    T: ::serde::Deserialize<'de>,
148{
149    fn deserialize<S>(deserializer: S) -> Result<Self, S::Error>
150    where
151        S: ::serde::Deserializer<'de>,
152    {
153        <[T; 3]>::deserialize(deserializer).map(EulerAngles::<T, B>::from)
154    }
155}
156
157macro_rules! reverse {
158    ($from:ident -> $to:ident) => {
159        impl<T> From<EulerAngles<T, $from>> for EulerAngles<T, $to> {
160            fn from(other: EulerAngles<T, $from>) -> Self {
161                EulerAngles {
162                    a: other.c,
163                    b: other.b,
164                    c: other.a,
165                    marker: PhantomData,
166                }
167            }
168        }
169    };
170    ($from:ident <-> $to:ident) => {
171        reverse!($from -> $to);
172        reverse!($to -> $from);
173    };
174}
175
176reverse!(IntraXYZ <-> ExtraZYX);
177reverse!(IntraZXZ <-> ExtraZXZ);
178reverse!(IntraZYX <-> ExtraXYZ);