1use crate::pfs;
4use super::{Vector3, Quaternion, Float};
5
6
7pub trait QuaternionOps<T>: Copy {
14 fn sum(self) -> T;
15 fn add(self, rhs: Self) -> Self;
17 fn sub(self, rhs: Self) -> Self;
19 fn scale(self, s: T) -> Self;
21 fn scale_add(self, s: T, b: Self) -> Self;
23 fn hadamard(self, rhs: Self) -> Self;
25 fn hadamard_add(self, b: Self, c: Self) -> Self;
27 fn dot(self, b: Self) -> T;
28 fn norm(self) -> T;
29 fn negate(self) -> Self;
31 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 #[inline]
134 fn mul(self, rhs: Vector3<T>) -> Quaternion<T> {
135 ( -super::dot(self, rhs), super::cross(self, rhs) )
136 }
137
138 #[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}