quaternion_core/
generics.rs

1//! 四元数と純虚四元数で共通する処理をまとめる
2
3use crate::pfs;
4use super::{Vector3, Quaternion, Float};
5
6
7/// This trait provides operations common to Quaternions and Pure Quaternions (Vector3).
8/// 
9/// This is to allow functions such as `add`, `dot` and `negate` to take
10/// both `Vector3` and `Quaternion` types as arguments. 
11/// You can use this trait directly, but it is easier to see if you use
12/// the one provided as a function (i.e., write `add(a, b)` instead of `a.add(b)`).
13pub trait QuaternionOps<T>: Copy {
14    fn sum(self) -> T;
15    /// `self + rhs`
16    fn add(self, rhs: Self) -> Self;
17    /// `self - rhs`
18    fn sub(self, rhs: Self) -> Self;
19    /// `s * self`
20    fn scale(self, s: T) -> Self;
21    /// `s * self + b`
22    fn scale_add(self, s: T, b: Self) -> Self;
23    /// `self ∘ rhs`
24    fn hadamard(self, rhs: Self) -> Self;
25    /// `self ∘ b + c`
26    fn hadamard_add(self, b: Self, c: Self) -> Self;
27    fn dot(self, b: Self) -> T;
28    fn norm(self) -> T;
29    /// `-self`
30    fn negate(self) -> Self;
31    /// `self * rhs`
32    fn mul(self, rhs: Self) -> Quaternion<T>;
33    fn inv(self) -> Self;
34    fn exp(self) -> Quaternion<T>;
35}
36
37impl<T: Float> QuaternionOps<T> for Vector3<T> {
38    #[inline]
39    fn sum(self) -> T {
40        self[0] + self[1] + self[2]
41    }
42
43    #[inline]
44    fn add(self, rhs: Vector3<T>) -> Vector3<T> {
45        [
46            self[0] + rhs[0], 
47            self[1] + rhs[1], 
48            self[2] + rhs[2] 
49        ]
50    }
51
52    #[inline]
53    fn sub(self, rhs: Vector3<T>) -> Vector3<T> {
54        [
55            self[0] - rhs[0], 
56            self[1] - rhs[1], 
57            self[2] - rhs[2]
58        ]
59    }
60
61    #[inline]
62    fn scale(self, s: T) -> Vector3<T> {
63        [
64            s * self[0],
65            s * self[1],
66            s * self[2]
67        ]
68    }
69
70    #[inline]
71    fn scale_add(self, s: T, b: Vector3<T>) -> Vector3<T> {
72        [
73            pfs::mul_add(s, self[0], b[0]),
74            pfs::mul_add(s, self[1], b[1]),
75            pfs::mul_add(s, self[2], b[2]),
76        ]
77    }
78
79    #[inline]
80    fn hadamard(self, rhs: Vector3<T>) -> Vector3<T> {
81        [
82            self[0] * rhs[0],
83            self[1] * rhs[1],
84            self[2] * rhs[2]
85        ]
86    }
87
88    #[inline]
89    fn hadamard_add(self, b: Vector3<T>, c: Vector3<T>) -> Vector3<T> {
90        [
91            pfs::mul_add(self[0], b[0], c[0]),
92            pfs::mul_add(self[1], b[1], c[1]),
93            pfs::mul_add(self[2], b[2], c[2]),
94        ]
95    }
96
97    #[inline]
98    fn dot(self, b: Vector3<T>) -> T {
99        #[cfg(feature = "fma")]
100        {
101            pfs::mul_add(self[0], b[0], pfs::mul_add(self[1], b[1], self[2] * b[2]))
102        }
103
104        #[cfg(not(feature = "fma"))]
105        {
106            self.hadamard(b).sum()
107        }
108    }
109
110    #[inline]
111    fn norm(self) -> T {
112        #[cfg(feature = "norm-sqrt")]
113        {
114            super::dot(self, self).sqrt()
115        }
116
117        #[cfg(not(feature = "norm-sqrt"))]
118        {
119            let mut s = self[0];
120            for val in self.iter().skip(1) {
121                s = s.hypot(*val);
122            }
123            s
124        }
125    }
126
127    #[inline]
128    fn negate(self) -> Vector3<T> {
129        [ -self[0], -self[1], -self[2] ]
130    }
131
132    // Product of Pure Quaternions
133    #[inline]
134    fn mul(self, rhs: Vector3<T>) -> Quaternion<T> {
135        ( -super::dot(self, rhs), super::cross(self, rhs) )
136    }
137
138    // 零ベクトルで特異点
139    #[inline]
140    fn inv(self) -> Vector3<T> {
141        self.negate().scale( super::dot(self, self).recip() )
142    }
143
144    #[inline]
145    fn exp(self) -> Quaternion<T> {
146        let norm_v = self.norm();
147        ( norm_v.cos(), self.scale( pfs::sinc(norm_v) ) )
148    }
149}
150
151impl<T: Float> QuaternionOps<T> for Quaternion<T> {
152    #[inline]
153    fn sum(self) -> T {
154        self.0 + self.1.sum()
155    }
156
157    #[inline]
158    fn add(self, rhs: Quaternion<T>) -> Quaternion<T> {
159        ( self.0 + rhs.0, self.1.add(rhs.1) )
160    }
161
162    #[inline]
163    fn sub(self, rhs: Quaternion<T>) -> Quaternion<T> {
164        ( self.0 - rhs.0,  self.1.sub(rhs.1) )
165    }
166
167    #[inline]
168    fn scale(self, s: T) -> Quaternion<T> {
169        ( s * self.0, self.1.scale(s) )
170    }
171
172    #[inline]
173    fn scale_add(self, s: T, b: Quaternion<T>) -> Quaternion<T> {
174        ( pfs::mul_add(s, self.0, b.0), self.1.scale_add(s, b.1) )
175    }
176
177    #[inline]
178    fn hadamard(self, rhs: Quaternion<T>) -> Quaternion<T> {
179        ( self.0 * rhs.0, self.1.hadamard(rhs.1) )
180    }
181
182    #[inline]
183    fn hadamard_add(self, b: Quaternion<T>, c: Quaternion<T>) -> Quaternion<T> {
184        ( pfs::mul_add(self.0, b.0, c.0), self.1.hadamard_add(b.1, c.1) )
185    }
186
187    #[inline]
188    fn dot(self, b: Quaternion<T>) -> T {
189        #[cfg(feature = "fma")]
190        {
191            pfs::mul_add(self.0, b.0, self.1.dot(b.1))
192        }
193
194        #[cfg(not(feature = "fma"))]
195        {
196            self.hadamard(b).sum()
197        }
198    }
199
200    #[inline]
201    fn norm(self) -> T {
202        #[cfg(feature = "norm-sqrt")]
203        {
204            super::dot(self, self).sqrt()
205        }
206
207        #[cfg(not(feature = "norm-sqrt"))]
208        {
209            let mut s = self.0;
210            for val in self.1 {
211                s = s.hypot(val)
212            }
213            s
214        }
215    }
216
217    #[inline]
218    fn negate(self) -> Quaternion<T> {
219        ( -self.0, self.1.negate() )
220    }
221
222    #[inline]
223    fn mul(self, rhs: Quaternion<T>) -> Quaternion<T> {
224        let self0_b = rhs.scale(self.0);
225        (
226            self0_b.0 - super::dot(self.1, rhs.1),
227            self.1.scale_add(rhs.0, self0_b.1).add( super::cross(self.1, rhs.1) )
228        )
229    }
230
231    #[inline]
232    fn inv(self) -> Quaternion<T> {
233        super::conj(self).scale( super::dot(self, self).recip() )
234    }
235
236    #[inline]
237    fn exp(self) -> Quaternion<T> {
238        let norm_v = self.1.norm();
239        let coef = self.0.exp();
240        ( coef * norm_v.cos(), self.1.scale(coef * pfs::sinc(norm_v)) )
241    }
242}