xcal
基于 C++23 的现代图形渲染引擎
载入中...
搜索中...
未找到
quaternion.hpp
浏览该文件的文档.
1
8#pragma once
9#ifndef XCMATH_QUATERNION_HPP
10#define XCMATH_QUATERNION_HPP
11
12#include <cmath>
13#include <type_traits>
14
15#include "./vec.hpp"
16
17namespace xcmath {
18template <typename _Tp, size_t _rows, size_t _cols>
19class mat;
20
26template <typename _Tp>
27class quaternion : public vec<_Tp, 4> {
28 public:
32 using ItemType = _Tp;
33
38
44 template <class _T>
46
50 constexpr static auto datatype = TypeName<DataType>;
51
55 constexpr static auto itemtype = TypeName<ItemType>;
56
60 constexpr static auto length = 4;
61
62 quaternion() = default;
63 quaternion(_Tp r, _Tp i, _Tp j, _Tp k) {
64 this->r() = r;
65 this->j() = j;
66 this->i() = i;
67 this->k() = k;
68 }
69
73 using vec<_Tp, 4>::operator[];
74
78 using vec<_Tp, 4>::operator=;
79
80 template <typename _OTp>
81 requires(std::is_convertible_v<ItemType, _OTp>)
82 constexpr inline operator Self<_OTp>() const {
83 Self<_OTp> ret;
84 ret.r() = (_OTp)r();
85 ret.i() = (_OTp)i();
86 ret.j() = (_OTp)j();
87 ret.k() = (_OTp)k();
88 return ret;
89 }
90
97 template <class _T>
98 requires std::is_convertible_v<_T, _Tp>
99 constexpr quaternion(const _T &r) {
100 this->r() = r;
101 this->i() = 0;
102 this->j() = 0;
103 this->k() = 0;
104 }
105
113 template <class _T>
114 requires std::is_arithmetic_v<_Tp>
115 constexpr quaternion(const vec3<_Tp> &axis, const _T &angle) {
116 _T half_angle = angle / 2;
117 _T s = std::sin(half_angle);
118 this->r() = std::cos(half_angle);
119 this->i() = axis.x() * s;
120 this->j() = axis.y() * s;
121 this->k() = axis.z() * s;
122 }
123
130 constexpr quaternion<_Tp> operator*(const quaternion<_Tp> &other) const {
131 quaternion<_Tp> res;
132 res.r() = r() * other.r() - i() * other.i() - j() * other.j() -
133 k() * other.k();
134 res.i() = r() * other.i() + i() * other.r() + j() * other.k() -
135 k() * other.j();
136 res.j() = r() * other.j() - i() * other.k() + j() * other.r() +
137 k() * other.i();
138 res.k() = r() * other.k() + i() * other.j() - j() * other.i() +
139 k() * other.r();
140 return res;
141 }
142
149 constexpr quaternion<_Tp> operator/(const quaternion<_Tp> &other) const {
150 quaternion<_Tp> res;
151 _Tp norm = other.norm();
152 res.r() = (r() * other.r() + i() * other.i() + j() * other.j() +
153 k() * other.k()) /
154 norm;
155 res.i() = (r() * other.i() - i() * other.r() - j() * other.k() +
156 k() * other.j()) /
157 norm;
158 res.j() = (r() * other.j() + i() * other.k() - j() * other.r() -
159 k() * other.i()) /
160 norm;
161 res.k() = (r() * other.k() - i() * other.j() + j() * other.i() -
162 k() * other.r()) /
163 norm;
164 return res;
165 }
166
172 constexpr _Tp norm() const {
173 return r() * r() + i() * i() + j() * j() + k() * k();
174 }
175
181 constexpr vec3<_Tp> v() { return vec3<_Tp>{i(), j(), k()}; }
182
189 quaternion<_Tp> res;
190 _Tp norm = this->norm();
191 res.r() = r() / norm;
192 res.i() = -i() / norm;
193 res.j() = -j() / norm;
194 res.k() = -k() / norm;
195 return res;
196 }
197
198 public:
204 constexpr mat<_Tp, 3, 3> to_mat() const;
205
212 static constexpr quaternion<_Tp> from_mat(const mat<_Tp, 3, 3> &mat);
213
214 public:
220 constexpr inline _Tp &r() { return this->data[3]; }
221
227 constexpr inline _Tp &i() { return this->data[0]; }
228
234 constexpr inline _Tp &j() { return this->data[1]; }
235
241 constexpr inline _Tp &k() { return this->data[2]; }
242
248 constexpr inline const _Tp &r() const { return this->data[3]; }
249
255 constexpr inline const _Tp &i() const { return this->data[0]; }
256
262 constexpr inline const _Tp &j() const { return this->data[1]; }
263
269 constexpr inline const _Tp &k() const { return this->data[2]; }
270
279 template <class _ItemType>
280 requires(!std::is_same_v<_ItemType, Self<_Tp>>)
281 auto operator+(const _ItemType &other) {
282 quaternion<decltype(r() + other)> res;
283 res.r() = r() + other;
284 res.i() = i();
285 res.j() = j();
286 res.k() = k();
287 return res;
288 }
289
298 template <class _ItemType>
299 requires(!std::is_same_v<_ItemType, Self<_Tp>>)
300 auto operator-(const _ItemType &other) {
301 quaternion<decltype(r() + other)> res;
302 res.r() = r() - other;
303 res.i() = i();
304 res.j() = j();
305 res.k() = k();
306 return res;
307 }
308 template <class _ItemType>
309 auto operator-(const Self<_ItemType> &other) {
310 Self<decltype(r() + other.r())> res;
311 res.r() = r() - other.r();
312 res.i() = i() - other.i();
313 res.j() = j() - other.j();
314 res.k() = k() - other.k();
315 return res;
316 }
317 template <class _ItemType>
318 auto operator+(const Self<_ItemType> &other) {
319 Self<decltype(r() - other.r())> res;
320 res.r() = r() + other.r();
321 res.i() = i() + other.i();
322 res.j() = j() + other.j();
323 res.k() = k() + other.k();
324 return res;
325 }
326};
327
337template <class _Tp, class _ItemType>
338 requires(!std::is_same_v<_Tp, quaternion<_ItemType>>)
339auto operator+(const _Tp &other, const quaternion<_ItemType> &v) {
340 quaternion<decltype(_Tp{} + _ItemType{})> res;
341 res.r() = other + v.r();
342 res.i() = v.i();
343 res.j() = v.j();
344 res.k() = v.k();
345 return res;
346}
347
357template <class _Tp, class _ItemType>
358 requires(!std::is_same_v<_Tp, quaternion<_ItemType>>)
359auto operator-(const _Tp &other, const quaternion<_ItemType> &v) {
360 quaternion<decltype(_Tp{} - _ItemType{})> res;
361 res.r() = other - v.r();
362 res.i() = -v.i();
363 res.j() = -v.j();
364 res.k() = -v.k();
365 return res;
366}
367
374template <typename T>
376 T one{};
377 ++one;
378 return mat<T, 3, 3>{
379 vec<T, 3>{one - 2 * j() * j() - 2 * k() * k(),
380 2 * i() * j() - 2 * r() * k(), 2 * r() * j() + 2 * i() * k()},
381 vec<T, 3>{2 * i() * j() + 2 * r() * k(),
382 one - 2 * i() * i() - 2 * k() * k(),
383 2 * j() * k() - 2 * r() * i()},
384 vec<T, 3>{2 * r() * j() - 2 * i() * k(), 2 * j() * k() + 2 * r() * i(),
385 one - 2 * i() * i() - 2 * j() * j()},
386 };
387}
388
396template <typename T>
398 quaternion<T> res;
399 T tr = mat[0][0] + mat[1][1] + mat[2][2];
400 if (tr > 0) {
401 T S = std::sqrt(tr + 1) * 2; // S=4*qw
402 res.r() = 0.25 * S;
403 res.i() = (mat[2][1] - mat[1][2]) / S;
404 res.j() = (mat[0][2] - mat[2][0]) / S;
405 res.k() = (mat[1][0] - mat[0][1]) / S;
406 } else if ((mat[0][0] > mat[1][1]) && (mat[0][0] > mat[2][2])) {
407 T S = std::sqrt(1.0 + mat[0][0] - mat[1][1] - mat[2][2]) * 2; // S=4*qx
408 res.r() = (mat[2][1] - mat[1][2]) / S;
409 res.i() = 0.25 * S;
410 res.j() = (mat[0][1] + mat[1][0]) / S;
411 res.k() = (mat[0][2] + mat[2][0]) / S;
412 } else if (mat[1][1] > mat[2][2]) {
413 T S = std::sqrt(1.0 + mat[1][1] - mat[0][0] - mat[2][2]) * 2; // S=4*qy
414 res.r() = (mat[0][2] - mat[2][0]) / S;
415 res.i() = (mat[0][1] + mat[1][0]) / S;
416 res.j() = 0.25 * S;
417 res.k() = (mat[1][2] + mat[2][1]) / S;
418 } else {
419 T S = std::sqrt(1.0 + mat[2][2] - mat[0][0] - mat[1][1]) * 2; // S=4*qz
420 res.r() = (mat[1][0] - mat[0][1]) / S;
421 res.i() = (mat[0][2] + mat[2][0]) / S;
422 res.j() = (mat[1][2] + mat[2][1]) / S;
423 res.k() = 0.25 * S;
424 }
425 return res;
426}
427constexpr inline quaternion<int> operator""_qi(unsigned long long i) {
428 auto res = quaternion<int>(0);
429 res.i() = i;
430 return res;
431}
432constexpr inline quaternion<int> operator""_qj(unsigned long long j) {
433 auto res = quaternion<int>(0);
434 res.j() = j;
435 return res;
436}
437constexpr inline quaternion<int> operator""_qk(unsigned long long k) {
438 auto res = quaternion<int>(0);
439 res.k() = k;
440 return res;
441}
442
443constexpr inline quaternion<float> operator""_qi(long double i) {
444 auto res = quaternion<float>(0);
445 res.i() = i;
446 return res;
447}
448constexpr inline quaternion<float> operator""_qj(long double j) {
449 auto res = quaternion<float>(0);
450 res.j() = j;
451 return res;
452}
453constexpr inline quaternion<float> operator""_qk(long double k) {
454 auto res = quaternion<float>(0);
455 res.k() = k;
456 return res;
457}
458
459} // namespace xcmath
460
461#endif // XCMATH_QUATERNION_HPP
Matrix class template
Definition mat.hpp:27
Quaternion class template
quaternion(_Tp r, _Tp i, _Tp j, _Tp k)
auto operator-(const Self< _ItemType > &other)
constexpr const _Tp & i() const
Get i-component of the quaternion (const version)
static constexpr auto datatype
Name of the data type
VecInfo< ItemType >::DataType DataType
Type of data stored in the vector
constexpr _Tp & r()
Get scalar part of the quaternion
quaternion()=default
constexpr vec3< _Tp > v()
Get vector part of the quaternion
constexpr quaternion< _Tp > inverse()
Compute inverse of the quaternion
constexpr const _Tp & j() const
Get j-component of the quaternion (const version)
constexpr mat< _Tp, 3, 3 > to_mat() const
Convert quaternion to rotation matrix
constexpr _Tp & i()
Get i-component of the quaternion
_Tp ItemType
Type of elements in the vector
constexpr const _Tp & r() const
Get scalar part of the quaternion (const version)
constexpr quaternion(const vec3< _Tp > &axis, const _T &angle)
Construct a quaternion from an axis and angle
constexpr _Tp & k()
Get k-component of the quaternion
static constexpr auto itemtype
Name of the item type
constexpr quaternion< _Tp > operator*(const quaternion< _Tp > &other) const
Quaternion multiplication operator
constexpr const _Tp & k() const
Get k-component of the quaternion (const version)
constexpr quaternion< _Tp > operator/(const quaternion< _Tp > &other) const
Quaternion division operator
constexpr quaternion(const _T &r)
Construct a quaternion from a scalar
constexpr _Tp norm() const
Compute norm of the quaternion
static constexpr quaternion< _Tp > from_mat(const mat< _Tp, 3, 3 > &mat)
Create quaternion from rotation matrix
constexpr _Tp & j()
Get j-component of the quaternion
auto operator+(const Self< _ItemType > &other)
static constexpr auto length
Length of the vector
Vector class template
Definition vec.hpp:206
constexpr _Tp angle(const vec< _Tp, _length > &other) const
Compute angle with another vector
Definition vec.hpp:687
constexpr _Tp & x()
Get the item at index 0
Definition vec.hpp:454
_Tp data[_length]
Component storage array
Definition vec.hpp:212
constexpr _Tp & y()
Get the item at index 1
Definition vec.hpp:465
constexpr _Tp & z()
Get the item at index 2
Definition vec.hpp:476
Compiler-specific type information handling for MSVC
Definition complex.hpp:12
decltype([]() { if constexpr(Vec< _Tp >) return VecInfo< typename _Tp::ItemType >::Zero DataType
Definition vec.hpp:137