tesseract++
0.0.1
N-dimensional tensor library for embedded systems
Loading...
Searching...
No Matches
core
include
fused
fused_quaternion.h
Go to the documentation of this file.
1
// #ifndef FUSEDQUATERNION_H
2
// #define FUSEDQUATERNION_H
3
4
// #include "fused/fused_vector.h"
5
// #include "fused/BaseExpr.h"
6
// #include "fused/microkernels/microkernel_base.h"
7
// #include "config.h"
8
// #include <cmath>
9
10
// /**
11
// * @brief Quaternion class using expression templates for SIMD optimization
12
// *
13
// * Storage order: [w, x, y, z] where w is scalar part, (x,y,z) is vector part
14
// * Follows Hamilton convention: i² = j² = k² = ijk = -1
15
// */
16
// template <typename T>
17
// class FusedQuaternion : public BaseExpr<FusedQuaternion<T>, T>
18
// {
19
// public:
20
// // Compile-time constants for expression template compatibility
21
// static constexpr my_size_t NumDims = 1;
22
// static constexpr my_size_t Dim[] = {4};
23
// static constexpr my_size_t TotalSize = 4;
24
25
// using Self = FusedQuaternion<T>;
26
// using value_type = T;
27
// using VecType = typename Microkernel<T, BITS, DefaultArch>::VecType;
28
// using microkernel = Microkernel<T, BITS, DefaultArch>;
29
// static constexpr my_size_t simdWidth = microkernel::simdWidth;
30
31
// // ========================
32
// // Constructors
33
// // ========================
34
35
// FusedQuaternion() noexcept
36
// : data_()
37
// {
38
// // Initialize to identity quaternion
39
// data_(0) = T{1}; // w
40
// data_(1) = T{0}; // x
41
// data_(2) = T{0}; // y
42
// data_(3) = T{0}; // z
43
// }
44
45
// FusedQuaternion(T w, T x, T y, T z) noexcept
46
// : data_()
47
// {
48
// data_(0) = w;
49
// data_(1) = x;
50
// data_(2) = y;
51
// data_(3) = z;
52
// }
53
54
// explicit FusedQuaternion(T initValue) noexcept
55
// : data_(initValue) {}
56
57
// // Construct from scalar and vector part
58
// template <my_size_t N>
59
// FusedQuaternion(T scalar, const FusedTensorND<T, N> &vec) noexcept
60
// {
61
// static_assert(N == 3, "Vector part must be 3D");
62
// data_(0) = scalar;
63
// data_(1) = vec(0);
64
// data_(2) = vec(1);
65
// data_(3) = vec(2);
66
// }
67
68
// // Copy constructor
69
// FusedQuaternion(const FusedQuaternion &other) noexcept
70
// : data_(other.data_) {}
71
72
// // Move constructor
73
// FusedQuaternion(FusedQuaternion &&other) noexcept
74
// : data_(move(other.data_)) {}
75
76
// // ========================
77
// // Assignment from expressions (enables SIMD fusion)
78
// // ========================
79
80
// template <typename Expr>
81
// FusedQuaternion &operator=(const BaseExpr<Expr, T> &expr)
82
// {
83
// const auto &e = expr.derived();
84
85
// // Compile-time dimension check
86
// static_assert(Expr::TotalSize == 4, "Expression must have 4 elements for quaternion assignment");
87
88
// if constexpr (!is_same_v<DefaultArch, GenericArch> && simdWidth >= 4)
89
// {
90
// // Single SIMD load for all 4 components
91
// auto vec = e.evalu(0);
92
// microkernel::store(data_.data(), vec);
93
// }
94
// else
95
// {
96
// // Scalar fallback
97
// my_size_t indices[1];
98
// for (my_size_t i = 0; i < 4; ++i)
99
// {
100
// indices[0] = i;
101
// data_(i) = e(indices);
102
// }
103
// }
104
// return *this;
105
// }
106
107
// FusedQuaternion &operator=(const FusedQuaternion &other) noexcept
108
// {
109
// if (this != &other)
110
// {
111
// data_ = other.data_;
112
// }
113
// return *this;
114
// }
115
116
// FusedQuaternion &operator=(FusedQuaternion &&other) noexcept
117
// {
118
// if (this != &other)
119
// {
120
// data_ = move(other.data_);
121
// }
122
// return *this;
123
// }
124
125
// // ========================
126
// // Expression template interface
127
// // ========================
128
129
// // SIMD evaluation - loads all 4 components at once if possible
130
// VecType evalu(my_size_t flat) const noexcept
131
// {
132
// return microkernel::load(data_.data() + flat);
133
// }
134
135
// // Scalar access for expression evaluation
136
// inline T operator()(const my_size_t *indices) const noexcept
137
// {
138
// return data_(indices[0]);
139
// }
140
141
// inline T &operator()(const my_size_t *indices) noexcept
142
// {
143
// return data_(indices[0]);
144
// }
145
146
// // ========================
147
// // Component accessors
148
// // ========================
149
150
// FORCE_INLINE T &w() noexcept { return data_(0); }
151
// FORCE_INLINE T &x() noexcept { return data_(1); }
152
// FORCE_INLINE T &y() noexcept { return data_(2); }
153
// FORCE_INLINE T &z() noexcept { return data_(3); }
154
155
// FORCE_INLINE const T &w() const noexcept { return data_(0); }
156
// FORCE_INLINE const T &x() const noexcept { return data_(1); }
157
// FORCE_INLINE const T &y() const noexcept { return data_(2); }
158
// FORCE_INLINE const T &z() const noexcept { return data_(3); }
159
160
// // Index access
161
// FORCE_INLINE T &operator[](my_size_t i) noexcept { return data_(i); }
162
// FORCE_INLINE const T &operator[](my_size_t i) const noexcept { return data_(i); }
163
164
// // Raw data pointer (for SIMD operations)
165
// FORCE_INLINE T *data() noexcept { return data_.data(); }
166
// FORCE_INLINE const T *data() const noexcept { return data_.data(); }
167
168
// // ========================
169
// // Quaternion-specific operations
170
// // ========================
171
172
// // Conjugate: q* = (w, -x, -y, -z)
173
// FusedQuaternion conjugate() const noexcept
174
// {
175
// return FusedQuaternion(w(), -x(), -y(), -z());
176
// }
177
178
// // Squared norm: |q|² = w² + x² + y² + z²
179
// T normSquared() const noexcept
180
// {
181
// if constexpr (!is_same_v<DefaultArch, GenericArch> && simdWidth >= 4)
182
// {
183
// // SIMD dot product
184
// VecType v = microkernel::load(data_.data());
185
// VecType sq = microkernel::mul(v, v);
186
// return microkernel::horizontal_sum(sq);
187
// }
188
// else
189
// {
190
// return w() * w() + x() * x() + y() * y() + z() * z();
191
// }
192
// }
193
194
// // Norm: |q| = sqrt(w² + x² + y² + z²)
195
// T norm() const noexcept
196
// {
197
// return std::sqrt(normSquared());
198
// }
199
200
// // Normalize in-place
201
// FusedQuaternion &normalize()
202
// {
203
// T n = norm();
204
// if (n > PRECISION_TOLERANCE)
205
// {
206
// T invNorm = T{1} / n;
207
// if constexpr (!is_same_v<DefaultArch, GenericArch> && simdWidth >= 4)
208
// {
209
// VecType v = microkernel::load(data_.data());
210
// VecType scale = microkernel::broadcast(invNorm);
211
// microkernel::store(data_.data(), microkernel::mul(v, scale));
212
// }
213
// else
214
// {
215
// data_(0) *= invNorm;
216
// data_(1) *= invNorm;
217
// data_(2) *= invNorm;
218
// data_(3) *= invNorm;
219
// }
220
// }
221
// return *this;
222
// }
223
224
// // Return normalized copy
225
// FusedQuaternion normalized() const
226
// {
227
// FusedQuaternion result(*this);
228
// result.normalize();
229
// return result;
230
// }
231
232
// // Inverse: q⁻¹ = q* / |q|²
233
// FusedQuaternion inverse() const
234
// {
235
// T ns = normSquared();
236
// if (ns < PRECISION_TOLERANCE)
237
// {
238
// MyErrorHandler::error("Cannot invert quaternion with zero norm");
239
// }
240
// T invNormSq = T{1} / ns;
241
// return FusedQuaternion(
242
// w() * invNormSq,
243
// -x() * invNormSq,
244
// -y() * invNormSq,
245
// -z() * invNormSq);
246
// }
247
248
// // ========================
249
// // Hamilton product: p * q
250
// // ========================
251
252
// FusedQuaternion operator*(const FusedQuaternion &q) const noexcept
253
// {
254
// // Hamilton product formula:
255
// // (p.w * q.w - p.x * q.x - p.y * q.y - p.z * q.z,
256
// // p.w * q.x + p.x * q.w + p.y * q.z - p.z * q.y,
257
// // p.w * q.y - p.x * q.z + p.y * q.w + p.z * q.x,
258
// // p.w * q.z + p.x * q.y - p.y * q.x + p.z * q.w)
259
260
// const T pw = w(), px = x(), py = y(), pz = z();
261
// const T qw = q.w(), qx = q.x(), qy = q.y(), qz = q.z();
262
263
// return FusedQuaternion(
264
// pw * qw - px * qx - py * qy - pz * qz, // w
265
// pw * qx + px * qw + py * qz - pz * qy, // x
266
// pw * qy - px * qz + py * qw + pz * qx, // y
267
// pw * qz + px * qy - py * qx + pz * qw // z
268
// );
269
// }
270
271
// FusedQuaternion &operator*=(const FusedQuaternion &q) noexcept
272
// {
273
// *this = *this * q;
274
// return *this;
275
// }
276
277
// // ========================
278
// // Vector rotation: v' = q * v * q⁻¹
279
// // ========================
280
281
// template <my_size_t N>
282
// FusedTensorND<T, 3> rotate(const FusedTensorND<T, N> &v) const
283
// {
284
// static_assert(N == 3, "Can only rotate 3D vectors");
285
286
// // Optimized rotation formula (avoiding full quaternion multiplication):
287
// // v' = v + 2w(u × v) + 2(u × (u × v))
288
// // where u = (x, y, z) is the vector part of the quaternion
289
290
// const T vx = v(0), vy = v(1), vz = v(2);
291
// const T ux = x(), uy = y(), uz = z();
292
293
// // t = 2 * (u × v)
294
// T tx = T{2} * (uy * vz - uz * vy);
295
// T ty = T{2} * (uz * vx - ux * vz);
296
// T tz = T{2} * (ux * vy - uy * vx);
297
298
// // v' = v + w*t + (u × t)
299
// FusedTensorND<T, 3> result;
300
// result(0) = vx + w() * tx + (uy * tz - uz * ty);
301
// result(1) = vy + w() * ty + (uz * tx - ux * tz);
302
// result(2) = vz + w() * tz + (ux * ty - uy * tx);
303
304
// return result;
305
// }
306
307
// // ========================
308
// // Static factory methods
309
// // ========================
310
311
// static FusedQuaternion identity() noexcept
312
// {
313
// return FusedQuaternion(T{1}, T{0}, T{0}, T{0});
314
// }
315
316
// // Create from axis-angle representation
317
// template <my_size_t N>
318
// static FusedQuaternion fromAxisAngle(const FusedTensorND<T, N> &axis, T angle)
319
// {
320
// static_assert(N == 3, "Axis must be 3D");
321
322
// T halfAngle = angle * T{0.5};
323
// T s = std::sin(halfAngle);
324
// T c = std::cos(halfAngle);
325
326
// // Normalize axis
327
// T axisNorm = std::sqrt(axis(0) * axis(0) + axis(1) * axis(1) + axis(2) * axis(2));
328
// if (axisNorm < PRECISION_TOLERANCE)
329
// {
330
// return identity();
331
// }
332
// T invNorm = T{1} / axisNorm;
333
334
// return FusedQuaternion(
335
// c,
336
// axis(0) * invNorm * s,
337
// axis(1) * invNorm * s,
338
// axis(2) * invNorm * s);
339
// }
340
341
// // Create from Euler angles (ZYX convention: yaw, pitch, roll)
342
// static FusedQuaternion fromEulerAngles(T roll, T pitch, T yaw)
343
// {
344
// T cr = std::cos(roll * T{0.5});
345
// T sr = std::sin(roll * T{0.5});
346
// T cp = std::cos(pitch * T{0.5});
347
// T sp = std::sin(pitch * T{0.5});
348
// T cy = std::cos(yaw * T{0.5});
349
// T sy = std::sin(yaw * T{0.5});
350
351
// return FusedQuaternion(
352
// cr * cp * cy + sr * sp * sy, // w
353
// sr * cp * cy - cr * sp * sy, // x
354
// cr * sp * cy + sr * cp * sy, // y
355
// cr * cp * sy - sr * sp * cy // z
356
// );
357
// }
358
359
// // Convert to Euler angles (returns roll, pitch, yaw)
360
// FusedTensorND<T, 3> toEulerAngles() const
361
// {
362
// FusedTensorND<T, 3> angles;
363
364
// // Roll (x-axis rotation)
365
// T sinr_cosp = T{2} * (w() * x() + y() * z());
366
// T cosr_cosp = T{1} - T{2} * (x() * x() + y() * y());
367
// angles(0) = std::atan2(sinr_cosp, cosr_cosp);
368
369
// // Pitch (y-axis rotation)
370
// T sinp = T{2} * (w() * y() - z() * x());
371
// if (std::abs(sinp) >= T{1})
372
// angles(1) = std::copysign(T{3.14159265358979323846} / T{2}, sinp);
373
// else
374
// angles(1) = std::asin(sinp);
375
376
// // Yaw (z-axis rotation)
377
// T siny_cosp = T{2} * (w() * z() + x() * y());
378
// T cosy_cosp = T{1} - T{2} * (y() * y() + z() * z());
379
// angles(2) = std::atan2(siny_cosp, cosy_cosp);
380
381
// return angles;
382
// }
383
384
// // Spherical linear interpolation (SLERP)
385
// static FusedQuaternion slerp(const FusedQuaternion &q0, const FusedQuaternion &q1, T t)
386
// {
387
// // Compute dot product
388
// T dot = q0.w() * q1.w() + q0.x() * q1.x() + q0.y() * q1.y() + q0.z() * q1.z();
389
390
// FusedQuaternion q1_adj = q1;
391
392
// // If dot < 0, negate one quaternion to take shorter path
393
// if (dot < T{0})
394
// {
395
// q1_adj = FusedQuaternion(-q1.w(), -q1.x(), -q1.y(), -q1.z());
396
// dot = -dot;
397
// }
398
399
// // If quaternions are very close, use linear interpolation
400
// if (dot > T{0.9995})
401
// {
402
// FusedQuaternion result(
403
// q0.w() + t * (q1_adj.w() - q0.w()),
404
// q0.x() + t * (q1_adj.x() - q0.x()),
405
// q0.y() + t * (q1_adj.y() - q0.y()),
406
// q0.z() + t * (q1_adj.z() - q0.z()));
407
// return result.normalized();
408
// }
409
410
// T theta_0 = std::acos(dot);
411
// T theta = theta_0 * t;
412
// T sin_theta = std::sin(theta);
413
// T sin_theta_0 = std::sin(theta_0);
414
415
// T s0 = std::cos(theta) - dot * sin_theta / sin_theta_0;
416
// T s1 = sin_theta / sin_theta_0;
417
418
// return FusedQuaternion(
419
// s0 * q0.w() + s1 * q1_adj.w(),
420
// s0 * q0.x() + s1 * q1_adj.x(),
421
// s0 * q0.y() + s1 * q1_adj.y(),
422
// s0 * q0.z() + s1 * q1_adj.z());
423
// }
424
425
// // ========================
426
// // Utility functions
427
// // ========================
428
429
// bool isUnit(T tolerance = PRECISION_TOLERANCE) const noexcept
430
// {
431
// return std::abs(normSquared() - T{1}) < tolerance;
432
// }
433
434
// FORCE_INLINE constexpr my_size_t getTotalSize() const noexcept
435
// {
436
// return TotalSize;
437
// }
438
439
// FORCE_INLINE constexpr my_size_t getNumDims() const noexcept
440
// {
441
// return NumDims;
442
// }
443
444
// FORCE_INLINE my_size_t getDim(my_size_t i) const noexcept
445
// {
446
// return (i == 0) ? 4 : 0;
447
// }
448
449
// void print() const
450
// {
451
// MyErrorHandler::log("Quaternion(w=");
452
// MyErrorHandler::log(w());
453
// MyErrorHandler::log(", x=");
454
// MyErrorHandler::log(x());
455
// MyErrorHandler::log(", y=");
456
// MyErrorHandler::log(y());
457
// MyErrorHandler::log(", z=");
458
// MyErrorHandler::log(z());
459
// MyErrorHandler::log(")\n");
460
// }
461
462
// private:
463
// // Storage: 4-element vector [w, x, y, z]
464
// FusedTensorND<T, 4> data_;
465
// };
466
467
// // ========================
468
// // Type alias for common types
469
// // ========================
470
// using Quaternionf = FusedQuaternion<float>;
471
// using Quaterniond = FusedQuaternion<double>;
472
473
// #endif // FUSEDQUATERNION_H
Generated by
1.9.8