glium_types/
quaternions.rs

1use derive_cmp_ops::{CmpAdd, CmpAddAssign, CmpNeg, CmpSub, CmpSubAssign};
2
3use crate::vectors::{Vec3, Vec4, DVec4, DVec3};
4
5#[derive(Clone, Copy, CmpAdd, CmpSub, CmpAddAssign, CmpSubAssign, CmpNeg, Debug, PartialEq)]
6/// a 4 part vector often used to represent rotations. note that multiplication of quaternions
7/// is applying transformations
8pub struct Quat{
9    pub r: f32,
10    pub i: f32,
11    pub j: f32,
12    pub k: f32
13}
14impl Quat{
15    pub const IDENTITY: Self = Self { r: 1.0, i: 0.0, j: 0.0, k: 0.0 };
16    /// rotation around the x axis in radians
17    pub fn from_x_rot(angle: f32) -> Self{
18        let a = angle / 2.0;
19        Self { r: a.cos(), i: a.sin(), j: 0.0, k: 0.0 }
20    }
21    /// rotation around the y axis in radians
22    pub fn from_y_rot(angle: f32) -> Self{
23        let a = angle / 2.0;
24        Self { r: a.cos(), i: 0.0, j: a.sin(), k: 0.0 }
25    }
26    /// rotation around the z axis in radians
27    pub fn from_z_rot(angle: f32) -> Self{
28        let a = angle / 2.0;
29        Self { r: a.cos(), i: 0.0, j: 0.0, k: a.sin() }
30    }
31    /// rotation around the inputed axis in radians
32    pub fn from_axis_rot(angle: f32, axis: Vec3) -> Self{
33        let a = angle / 2.0;
34        Self{
35            r: a.cos(),
36            i: a.sin() * axis.x,
37            j: a.sin() * axis.y,
38            k: a.sin() * axis.z,
39        }
40    }
41    /// get innverse of a quaternion. panics if all quaternions values are 0
42    pub fn inverse(self) -> Self {
43        let Quat { r, i, j, k } = self;
44        if r == 0.0 && i == 0.0 && j == 0.0 && k == 0.0 {
45            panic!("tried to get inverse of zero quaternion");
46        }
47        let scalar = r*r + i*i + j*j + k*k;
48        Self {
49            r: r / scalar,
50            i: -i / scalar,
51            j: -j / scalar,
52            k: -k / scalar
53        }
54    }
55}
56impl From<Vec4> for Quat {
57    fn from(value: Vec4) -> Self {
58        Self { r: value.x, i: value.y, j: value.z, k: value.w }
59    }
60}
61impl From<DQuat> for Quat {
62    fn from(value: DQuat) -> Self {
63        Self { r: value.r as f32, i: value.i as f32, j: value.j as f32, k: value.k as f32 }
64    }
65}
66impl std::ops::Mul<Quat> for f32 {
67    fn mul(self, rhs: Quat) -> Self::Output {
68        Quat { 
69            r: rhs.r * self, 
70            i: rhs.i * self, 
71            j: rhs.j * self, 
72            k: rhs.k * self
73        }
74    }
75    type Output = Quat;
76}
77impl std::ops::Mul<f32> for Quat {
78    fn mul(self, rhs: f32) -> Self::Output {
79        Self { 
80            r: self.r * rhs, 
81            i: self.i * rhs, 
82            j: self.j * rhs, 
83            k: self.k * rhs
84        }
85    }
86    type Output = Self;
87}
88impl std::ops::MulAssign<f32> for Quat { fn mul_assign(&mut self, rhs: f32) { *self = *self * rhs } }
89impl std::ops::Rem<Quat> for f32 {
90    fn rem(self, rhs: Quat) -> Self::Output {
91        Quat { 
92            r: rhs.r % self, 
93            i: rhs.i % self, 
94            j: rhs.j % self, 
95            k: rhs.k % self
96        }
97    }
98    type Output = Quat;
99}
100impl std::ops::Rem<f32> for Quat {
101    fn rem(self, rhs: f32) -> Self::Output {
102        Self { 
103            r: self.r % rhs, 
104            i: self.i % rhs, 
105            j: self.j % rhs, 
106            k: self.k % rhs
107        }
108    }
109    type Output = Self;
110}
111impl std::ops::RemAssign<f32> for Quat { fn rem_assign(&mut self, rhs: f32) { *self = *self % rhs } }
112impl std::ops::Div<Quat> for f32 {
113    fn div(self, rhs: Quat) -> Self::Output {
114        Quat { 
115            r: rhs.r / self, 
116            i: rhs.i / self, 
117            j: rhs.j / self, 
118            k: rhs.k / self
119        }
120    }
121    type Output = Quat;
122}
123impl std::ops::Div<f32> for Quat {
124    fn div(self, rhs: f32) -> Self::Output { self * (1.0/rhs) }
125    type Output = Self;
126}
127impl std::ops::DivAssign<f32> for Quat { fn div_assign(&mut self, rhs: f32) { *self = *self / rhs } }
128impl std::ops::Mul for Quat {
129    fn mul(self, rhs: Self) -> Self::Output {
130        let a = self;
131        let b = rhs;
132        Self { 
133            r: a.r*b.r - a.i*b.i - a.j*b.j - a.k*b.k, 
134            i: a.r*b.i + a.i*b.r + a.j*b.k - a.k*b.j, 
135            j: a.r*b.j - a.i*b.k + a.j*b.r + a.k*b.i, 
136            k: a.r*b.k + a.i*b.j - a.j*b.i + a.k*b.r
137        }
138    }
139    type Output = Self;
140}
141impl std::ops::MulAssign for Quat { fn mul_assign(&mut self, rhs: Self) { *self = *self * rhs } }
142#[allow(clippy::suspicious_arithmetic_impl)]
143impl std::ops::Div for Quat {
144    fn div(self, rhs: Self) -> Self::Output { self * rhs.inverse() }
145    type Output = Self;
146}
147impl std::ops::DivAssign for Quat { fn div_assign(&mut self, rhs: Self) { *self = *self / rhs } }
148#[test]
149fn quaternion_inverse() {
150    let a = Quat::from_x_rot(3.0);
151    let inv_a = a.inverse();
152    assert!(a * inv_a == Quat { r: 1.0, i: 0.0, j: 0.0, k: 0.0 });
153}
154
155#[derive(Clone, Copy, CmpAdd, CmpSub, CmpAddAssign, CmpSubAssign, CmpNeg, Debug, PartialEq)]
156/// a 4 part double vector often used to represent rotations. note that multiplication of quaternions
157/// is applying transformations
158pub struct DQuat {
159    pub r: f64,
160    pub i: f64,
161    pub j: f64,
162    pub k: f64
163}
164impl DQuat {
165    pub const IDENTITY: Self = Self { r: 1.0, i: 0.0, j: 0.0, k: 0.0 };
166    ///rotation around the x axis in radians
167    pub fn from_x_rot(angle: f64) -> Self {
168        let a = angle / 2.0;
169        Self { r: a.cos(), i: a.sin(), j: 0.0, k: 0.0 }
170    }
171    ///rotation around the y axis in radians
172    pub fn from_y_rot(angle: f64) -> Self {
173        let a = angle / 2.0;
174        Self { r: a.cos(), i: 0.0, j: a.sin(), k: 0.0 }
175    }
176    ///rotation around the z axis in radians
177    pub fn from_z_rot(angle: f64) -> Self {
178        let a = angle / 2.0;
179        Self { r: a.cos(), i: 0.0, j: 0.0, k: a.sin() }
180    }
181    ///rotation around the inputed axis in radians
182    pub fn from_axis_rot(angle: f64, axis: DVec3) -> Self {
183        let a = angle / 2.0;
184        Self{
185            r: a.cos(),
186            i: a.sin() * axis.x,
187            j: a.sin() * axis.y,
188            k: a.sin() * axis.z,
189        }
190    }
191    ///get innverse of a quaternion. panics if all quaternions values are 0
192    pub fn inverse(self) -> Self {
193        let DQuat { r, i, j, k } = self;
194        if r == 0.0 && i == 0.0 && j == 0.0 && k == 0.0 {
195            panic!("tried to get inverse of zero quaternion");
196        }
197        let scalar = r*r + i*i + j*j + k*k;
198        Self {
199            r: r / scalar,
200            i: -i / scalar,
201            j: -j / scalar,
202            k: -k / scalar
203        }
204    }
205}
206impl From<DVec4> for DQuat {
207    fn from(value: DVec4) -> Self {
208        Self { r: value.x, i: value.y, j: value.z, k: value.w }
209    }
210}
211impl From<Quat> for DQuat {
212    fn from(value: Quat) -> Self {
213        Self { r: value.r as f64, i: value.i as f64, j: value.j as f64, k: value.k as f64 }
214    }
215}
216#[test]
217fn dquaternion_inverse() {
218    let a = DQuat::from_x_rot(3.0);
219    let inv_a = a.inverse();
220    assert!(a * inv_a == DQuat { r: 1.0, i: 0.0, j: 0.0, k: 0.0 });
221}
222
223impl std::ops::Mul<DQuat> for f64 {
224    fn mul(self, rhs: DQuat) -> Self::Output {
225        DQuat { 
226            r: rhs.r * self, 
227            i: rhs.i * self, 
228            j: rhs.j * self, 
229            k: rhs.k * self
230        }
231    }
232    type Output = DQuat;
233}
234impl std::ops::Mul<f64> for DQuat {
235    fn mul(self, rhs: f64) -> Self::Output {
236        Self { 
237            r: self.r * rhs, 
238            i: self.i * rhs, 
239            j: self.j * rhs, 
240            k: self.k * rhs
241        }
242    }
243    type Output = Self;
244}
245impl std::ops::MulAssign<f64> for DQuat { fn mul_assign(&mut self, rhs: f64) { *self = *self * rhs } }
246impl std::ops::Rem<DQuat> for f64 {
247    fn rem(self, rhs: DQuat) -> Self::Output {
248        DQuat { 
249            r: rhs.r % self, 
250            i: rhs.i % self, 
251            j: rhs.j % self, 
252            k: rhs.k % self
253        }
254    }
255    type Output = DQuat;
256}
257impl std::ops::Rem<f64> for DQuat {
258    fn rem(self, rhs: f64) -> Self::Output {
259        Self { 
260            r: self.r % rhs, 
261            i: self.i % rhs, 
262            j: self.j % rhs, 
263            k: self.k % rhs
264        }
265    }
266    type Output = Self;
267}
268impl std::ops::RemAssign<f64> for DQuat { fn rem_assign(&mut self, rhs: f64) { *self = *self % rhs } }
269impl std::ops::Div<DQuat> for f64 {
270    fn div(self, rhs: DQuat) -> Self::Output {
271        DQuat { 
272            r: rhs.r / self, 
273            i: rhs.i / self, 
274            j: rhs.j / self, 
275            k: rhs.k / self
276        }
277    }
278    type Output = DQuat;
279}
280impl std::ops::Div<f64> for DQuat {
281    fn div(self, rhs: f64) -> Self::Output { self * (1.0/rhs) }
282    type Output = Self;
283}
284impl std::ops::DivAssign<f64> for DQuat { fn div_assign(&mut self, rhs: f64) { *self = *self / rhs } }
285impl std::ops::Mul for DQuat {
286    fn mul(self, rhs: Self) -> Self::Output {
287        let a = self;
288        let b = rhs;
289        Self { 
290            r: a.r*b.r - a.i*b.i - a.j*b.j - a.k*b.k, 
291            i: a.r*b.i + a.i*b.r + a.j*b.k - a.k*b.j, 
292            j: a.r*b.j - a.i*b.k + a.j*b.r + a.k*b.i, 
293            k: a.r*b.k + a.i*b.j - a.j*b.i + a.k*b.r
294        }
295    }
296    type Output = Self;
297}
298impl std::ops::MulAssign for DQuat { fn mul_assign(&mut self, rhs: Self) { *self = *self * rhs } }
299#[allow(clippy::suspicious_arithmetic_impl)]
300impl std::ops::Div for DQuat {
301    fn div(self, rhs: Self) -> Self::Output { self * rhs.inverse() }
302    type Output = Self;
303}
304impl std::ops::DivAssign for DQuat { fn div_assign(&mut self, rhs: Self) { *self = *self / rhs } }