1use super::{Vector3, Quaternion, Float, pfs::mul_add};
4
5
6pub trait QuaternionOps<T>: Copy {
13 fn sum(self) -> T;
14 fn add(self, rhs: Self) -> Self;
16 fn sub(self, rhs: Self) -> Self;
18 fn scale(self, s: T) -> Self;
20 fn scale_add(self, s: T, b: Self) -> Self;
22 fn hadamard(self, rhs: Self) -> Self;
24 fn hadamard_add(self, b: Self, c: Self) -> Self;
26 fn dot(self, b: Self) -> T;
27 fn norm(self) -> T;
28 fn negate(self) -> Self;
30 fn mul(self, rhs: Self) -> Quaternion<T>;
32 fn inv(self) -> Self;
33 fn exp(self) -> Quaternion<T>;
34}
35
36impl<T: Float> QuaternionOps<T> for Vector3<T> {
37 #[inline]
38 fn sum(self) -> T {
39 self[0] + self[1] + self[2]
40 }
41
42 #[inline]
43 fn add(self, rhs: Vector3<T>) -> Vector3<T> {
44 [
45 self[0] + rhs[0],
46 self[1] + rhs[1],
47 self[2] + rhs[2]
48 ]
49 }
50
51 #[inline]
52 fn sub(self, rhs: Vector3<T>) -> Vector3<T> {
53 [
54 self[0] - rhs[0],
55 self[1] - rhs[1],
56 self[2] - rhs[2]
57 ]
58 }
59
60 #[inline]
61 fn scale(self, s: T) -> Vector3<T> {
62 [
63 s * self[0],
64 s * self[1],
65 s * self[2]
66 ]
67 }
68
69 #[inline]
70 fn scale_add(self, s: T, b: Vector3<T>) -> Vector3<T> {
71 [
72 mul_add(s, self[0], b[0]),
73 mul_add(s, self[1], b[1]),
74 mul_add(s, self[2], b[2]),
75 ]
76 }
77
78 #[inline]
79 fn hadamard(self, rhs: Vector3<T>) -> Vector3<T> {
80 [
81 self[0] * rhs[0],
82 self[1] * rhs[1],
83 self[2] * rhs[2]
84 ]
85 }
86
87 #[inline]
88 fn hadamard_add(self, b: Vector3<T>, c: Vector3<T>) -> Vector3<T> {
89 [
90 mul_add(self[0], b[0], c[0]),
91 mul_add(self[1], b[1], c[1]),
92 mul_add(self[2], b[2], c[2]),
93 ]
94 }
95
96 #[inline]
97 fn dot(self, b: Vector3<T>) -> T {
98 #[cfg(feature = "fma")]
99 {
100 mul_add(self[0], b[0], mul_add(self[1], b[1], self[2] * b[2]))
101 }
102
103 #[cfg(not(feature = "fma"))]
104 {
105 self.hadamard(b).sum()
106 }
107 }
108
109 #[inline]
110 fn norm(self) -> T {
111 #[cfg(feature = "norm-sqrt")]
112 {
113 super::dot(self, self).sqrt()
114 }
115
116 #[cfg(not(feature = "norm-sqrt"))]
117 {
118 let mut s = self[0];
119 for val in self.iter().skip(1) {
120 s = s.hypot(*val);
121 }
122 s
123 }
124 }
125
126 #[inline]
127 fn negate(self) -> Vector3<T> {
128 [ -self[0], -self[1], -self[2] ]
129 }
130
131 #[inline]
133 fn mul(self, rhs: Vector3<T>) -> Quaternion<T> {
134 ( -super::dot(self, rhs), super::cross(self, rhs) )
135 }
136
137 #[inline]
139 fn inv(self) -> Vector3<T> {
140 self.negate().scale( super::dot(self, self).recip() )
141 }
142
143 #[inline]
144 fn exp(self) -> Quaternion<T> {
145 let norm_v = self.norm();
146 let (sin, cos) = norm_v.sin_cos();
147 ( cos, self.scale(sin / 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 ( 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 ( 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 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 (sin, cos) = norm_v.sin_cos();
240 let coef = self.0.exp();
241 ( coef * cos, self.1.scale((coef * sin) / norm_v) )
242 }
243}