gamemath/quat.rs
1use mat4::Mat4;
2use std::ops::{Add, AddAssign, Mul, MulAssign};
3use vec3::Vec3;
4use vec4::Vec4;
5
6/// A quaternion data type used for representing spatial rotation in a 3D environment.
7#[derive(Copy, Clone, Debug, PartialEq)]
8pub struct Quat {
9    /// The X/first component of the quaternion.
10    pub x: f32,
11    /// The Y/second component of the quaternion.
12    pub y: f32,
13    /// The Z/third component of the quaternion.
14    pub z: f32,
15    /// The W/fourth component of the quaternion.
16    pub w: f32,
17}
18
19impl Quat {
20    /// Constructs an identity quaternion.
21    ///
22    /// # Examples
23    ///
24    /// ```
25    /// use gamemath::Quat;
26    ///
27    /// let q = Quat::identity();
28    ///
29    /// assert_eq!(q, (0.0, 0.0, 0.0, 1.0).into());
30    /// ```
31    pub fn identity() -> Quat {
32        Self::default()
33    }
34
35    /// Constructs a rotation quaternion from an angle and an axis.
36    ///
37    /// # Examples
38    ///
39    /// ```
40    /// use gamemath::{Vec3, Quat};
41    ///
42    /// let q = Quat::rotation(1.0, Vec3::new(1.0, 2.0, 3.0));
43    ///
44    /// assert_eq!(q, (0.12813187, 0.25626373, 0.38439557, 0.87758255).into());
45    /// ```
46    pub fn rotation(radians: f32, axis: Vec3<f32>) -> Quat {
47        let a = axis.normalized();
48        let r = radians / 2.0;
49        let s = r.sin();
50
51        Quat {
52            x: a.x * s,
53            y: a.y * s,
54            z: a.z * s,
55            w: r.cos(),
56        }
57    }
58
59    /// Calculate and returns a quaternion representing the calling object rotated by an angle
60    /// around an axis.
61    ///
62    /// # Examples
63    ///
64    /// ```
65    /// use gamemath::{Vec3, Quat};
66    ///
67    /// let q = Quat::identity();
68    ///
69    /// assert_eq!(q.rotated(1.0, Vec3::new(1.0, 2.0, 3.0)), (0.12813187, 0.25626373, 0.38439557, 0.87758255).into());
70    /// ```
71    pub fn rotated(&self, radians: f32, axis: Vec3<f32>) -> Quat {
72        *self * Quat::rotation(radians, axis)
73    }
74
75    /// Applies a rotation around and axis by an angle on the calling `Quat` object.
76    ///
77    /// # Examples
78    ///
79    /// ```
80    /// use gamemath::{Vec3, Quat};
81    ///
82    /// let mut q = Quat::identity();
83    ///
84    /// q.rotate(1.0, Vec3::new(1.0, 2.0, 3.0));
85    ///
86    /// assert_eq!(q, (0.12813187, 0.25626373, 0.38439557, 0.87758255).into());
87    /// ```
88    pub fn rotate(&mut self, radians: f32, axis: Vec3<f32>) {
89        *self *= Quat::rotation(radians, axis);
90    }
91
92    /// Calculates the squared length/magnitude/norm of a `Quat`.
93    /// This saves an expensive square root calculation compared to calculating the actual length,
94    /// and comparing two squared lengths can therefore often be cheaper than, and yield the same
95    /// result as, computing two real lengths.
96    ///
97    /// # Examples
98    ///
99    /// ```
100    /// use gamemath::Quat;
101    ///
102    /// let q: Quat = (1.0, 2.0, 3.0, 4.0).into();
103    ///
104    /// assert_eq!(q.length_squared(), 30.0);
105    pub fn length_squared(&self) -> f32 {
106        self.x * self.x + self.y * self.y + self.z * self.z + self.w * self.w
107    }
108
109    /// Calculates the real length/magnitude/norm of a `Quat`.
110    /// This results in an expensive square root calculation, and you might want to consider using
111    /// a squared length instead when possible.
112    ///
113    /// # Examples
114    ///
115    /// ```
116    /// use gamemath::Quat;
117    ///
118    /// let q: Quat = (1.0, 4.0, 4.0, 16.0).into();
119    ///
120    /// assert_eq!(q.length(), 17.0);
121    pub fn length(&self) -> f32 {
122        self.length_squared().sqrt()
123    }
124
125    /// Calculates and returns the unit quaternion representation of a `Quat`.
126    /// This results in an an expensive square root calculation.
127    ///
128    /// # Examples
129    ///
130    /// ```
131    /// use gamemath::Quat;
132    ///
133    /// let q: Quat = (1.0, 2.0, 2.0, 4.0).into();
134    ///
135    /// assert_eq!(q.normalized(), (0.2, 0.4, 0.4, 0.8).into());
136    pub fn normalized(&self) -> Quat {
137        let f = 1.0 / self.length();
138
139        Quat {
140            x: self.x * f,
141            y: self.y * f,
142            z: self.z * f,
143            w: self.w * f,
144        }
145    }
146
147    /// Normalizes a `Quat` into its unit quaternion representation.
148    /// This results in an an expensive square root calculation.
149    ///
150    /// # Examples
151    ///
152    /// ```
153    /// use gamemath::Quat;
154    ///
155    /// let mut q: Quat = (1.0, 2.0, 2.0, 4.0).into();
156    ///
157    /// q.normalize();
158    ///
159    /// assert_eq!(q, (0.2, 0.4, 0.4, 0.8).into());
160    pub fn normalize(&mut self) {
161        *self = self.normalized();
162    }
163
164    /// Calculates and returns a `Mat4` object representing the rotation of the calling `Quat`
165    /// object.
166    ///
167    /// # Examples
168    ///
169    /// ```
170    /// use gamemath::{Vec3, Mat4, Quat};
171    ///
172    /// let q = Quat::rotation(1.0, Vec3::new(1.0, 2.0, 3.0));
173    ///
174    /// assert_eq!(q.extract_matrix(), (( 0.5731379,  0.74034876, -0.35127854, 0.0),
175    ///                                 (-0.6090066,  0.67164457,  0.42190588, 0.0),
176    ///                                 ( 0.5482918, -0.027879298, 0.8358222,  0.0),
177    ///                                 ( 0.0,        0.0,         0.0,        1.0)).into());
178    /// ```
179    pub fn extract_matrix(&self) -> Mat4 {
180        let mut result = Mat4::identity();
181        let x = self.x;
182        let y = self.y;
183        let z = self.z;
184        let w = self.w;
185        let x2 = x + x;
186        let y2 = y + y;
187        let z2 = z + z;
188        let xx = x * x2;
189        let yx = y * x2;
190        let yy = y * y2;
191        let zx = z * x2;
192        let zy = z * y2;
193        let zz = z * z2;
194        let wx = w * x2;
195        let wy = w * y2;
196        let wz = w * z2;
197
198        result[0][0] = 1.0 - yy - zz;
199        result[0][1] = yx + wz;
200        result[0][2] = zx - wy;
201        result[1][0] = yx - wz;
202        result[1][1] = 1.0 - xx - zz;
203        result[1][2] = zy + wx;
204        result[2][0] = zx + wy;
205        result[2][1] = zy - wx;
206        result[2][2] = 1.0 - xx - yy;
207
208        result
209    }
210}
211
212impl Default for Quat {
213    fn default() -> Quat {
214        Quat {
215            x: 0.0,
216            y: 0.0,
217            z: 0.0,
218            w: 1.0,
219        }
220    }
221}
222
223impl From<f32> for Quat {
224    fn from(value: f32) -> Quat {
225        Quat {
226            x: 0.0,
227            y: 0.0,
228            z: 0.0,
229            w: value,
230        }
231    }
232}
233
234impl From<Vec4<f32>> for Quat {
235    fn from(vec: Vec4<f32>) -> Quat {
236        Quat {
237            x: vec.x,
238            y: vec.y,
239            z: vec.z,
240            w: vec.w,
241        }
242    }
243}
244
245impl From<(f32, f32, f32, f32)> for Quat {
246    fn from(tuple: (f32, f32, f32, f32)) -> Quat {
247        Quat {
248            x: tuple.0,
249            y: tuple.1,
250            z: tuple.2,
251            w: tuple.3,
252        }
253    }
254}
255
256impl From<[f32; 4]> for Quat {
257    fn from(slice: [f32; 4]) -> Quat {
258        Quat {
259            x: slice[0],
260            y: slice[1],
261            z: slice[2],
262            w: slice[3],
263        }
264    }
265}
266
267impl Mul<Quat> for Quat {
268    type Output = Quat;
269
270    fn mul(self, right: Quat) -> Quat {
271        Quat {
272            x: (right.w * self.x) + (right.x * self.w) + (right.y * self.z) - (right.z * self.y),
273            y: (right.w * self.y) + (right.y * self.w) + (right.z * self.x) - (right.x * self.z),
274            z: (right.w * self.z) + (right.z * self.w) + (right.x * self.y) - (right.y * self.x),
275            w: (right.w * self.w) - (right.x * self.x) - (right.y * self.y) - (right.z * self.z),
276        }
277    }
278}
279
280impl MulAssign<Quat> for Quat {
281    fn mul_assign(&mut self, right: Quat) {
282        *self = *self * right;
283    }
284}
285
286impl Add<Quat> for Quat {
287    type Output = Quat;
288
289    fn add(self, right: Quat) -> Quat {
290        Quat {
291            x: self.x + right.x,
292            y: self.y + right.y,
293            z: self.z + right.z,
294            w: self.w + right.w,
295        }
296    }
297}
298
299impl AddAssign<Quat> for Quat {
300    fn add_assign(&mut self, right: Quat) {
301        *self = *self + right;
302    }
303}