Maipa's Standard Library Extension 1.5.6
mstd
Loading...
Searching...
No Matches
quat.hpp
1/*
2 * mstd - Maipa's Standard Library
3 *
4 * Licensed under the BSD 3-Clause License with Attribution Requirement.
5 * See the LICENSE file for details: https://github.com/MAIPA01/mstd/blob/main/LICENSE
6 *
7 * Copyright (c) 2025, Patryk Antosik (MAIPA01)
8 *
9 * Tested and fixed by Muppetsg2 (https://github.com/Muppetsg2)
10 * Good reference site: https://www.tobynorris.com/work/prog/csharp/quatview/help/orientations_and_quaternions.htm
11 */
12
13#pragma once
14#ifndef _MSTD_QUAT_HPP_
15 #define _MSTD_QUAT_HPP_
16
17 #include <mstd/config.hpp>
18
20_MSTD_WARNING("this is only available for c++17 and greater!");
21 #else
22
23 #include <mstd/vec.hpp>
24
25namespace mstd {
27 template<arithmetic T>
28 #else
29 template<class T, std::enable_if_t<std::is_arithmetic_v<T>, bool> >
30 #endif
31 class quat {
32 public:
33 using value_type = T;
34 using vec_type = vec<3, T>;
35
36 T s;
38
39 #pragma region CONSTRUCTORS
40
41 _MSTD_CONSTEXPR20 quat() : s(0), v() {}
42
43 _MSTD_CONSTEXPR20 quat(const T& scalar, const vec_type& vector) : s(scalar), v(vector) {}
44
45 _MSTD_CONSTEXPR20 quat(const T& scalar, const T& x, const T& y, const T& z) : s(scalar), v(x, y, z) {}
47 template<arithmetic OT>
48 #else
49 template<class OT, std::enable_if_t<std::is_arithmetic_v<OT>, bool> = true>
50 #endif
51 _MSTD_CONSTEXPR20 quat(const quat<OT>& other) : s(other.s), v(other.v) {
52 }
53
54 #pragma endregion // CONSTRUCTORS
55
56 #pragma region DESTRUCTOR
57 _MSTD_CONSTEXPR20 ~quat() = default;
58 #pragma endregion // DESTRUCTOR
59
60 #pragma region ASSIGN
62 template<arithmetic OT>
63 #else
64 template<class OT, std::enable_if_t<std::is_arithmetic_v<OT>, bool> = true>
65 #endif
66 _MSTD_CONSTEXPR20 quat<T>& operator=(const quat<OT>& other) {
67 s = static_cast<T>(other.s);
68 v = other.v;
69 return *this;
70 }
71
72 #pragma endregion // ASSIGN
73
74 #pragma region PREDEFINED_QUATERNIONS
75
76 static _MSTD_CONSTEXPR20 quat<T> rotation(const vec_type& axis, const T& radians) {
77 _MSTD_CONSTEXPR17 const double half = 0.5;
78
79 quat<T> q;
80 if (!axis.is_zero()) {
81 q = quat<T>(static_cast<T>(std::cos(radians * half)),
82 axis.normalized() * static_cast<T>(std::sin(radians * half)));
83 }
84 else { q = quat<T>(static_cast<T>(std::cos(radians * half)), axis); }
85 if (q.magnitude() != static_cast<T>(0)) { q.normalize(); }
86 return q;
87 }
88
89 static _MSTD_CONSTEXPR20 quat<T> from_euler_angels(const vec_type& eulerAngels) {
90 return from_radians({ deg_to_rad(eulerAngels[0]), deg_to_rad(eulerAngels[1]), deg_to_rad(eulerAngels[2]) });
91 }
92
93 static _MSTD_CONSTEXPR20 quat<T> from_radians(const vec_type& radians) {
94 quat<T> qx = rotation(vec_type(static_cast<T>(1), static_cast<T>(0), static_cast<T>(0)), radians[0]);
95 quat<T> qy = rotation(vec_type(static_cast<T>(0), static_cast<T>(1), static_cast<T>(0)), radians[1]);
96 quat<T> qz = rotation(vec_type(static_cast<T>(0), static_cast<T>(0), static_cast<T>(1)), radians[2]);
97
98 // ZYX convention
99 quat<T> q = qz * qy * qx;
100 if (q.magnitude() != static_cast<T>(0)) { q.normalize(); }
101 return q;
102 }
103
104 #pragma endregion // PREDEFINED_QUATERNIONS
105
106 #pragma region QUATERNION_OPERATIONS
107
108 _MSTD_CONSTEXPR20 T magnitude() const { return std::sqrt((s * s) + v.dot(v)); }
109
111 T m = magnitude();
112 *this /= m;
113 return *this;
114 }
115
117 quat<T> res = *this;
118 return res.normalize();
119 }
120
122 v *= -1;
123 return *this;
124 }
125
127 quat<T> res = *this;
128 return res.conjugate();
129 }
130
132 T magnitudes = magnitude();
133 magnitudes *= magnitudes;
134 magnitudes = static_cast<T>(1.0 / magnitudes);
135
136 conjugate();
137
138 s *= magnitudes;
139 v *= magnitudes;
140
141 return *this;
142 }
143
144 _MSTD_CONSTEXPR20 quat<T> inverted() const {
145 quat<T> res = *this;
146 return res.invert();
147 }
148
150 _MSTD_CONSTEXPR17 const double two = 2.0;
151 _MSTD_CONSTEXPR17 const double half = 0.5;
152
153 vec_type res;
154 quat<T> q = *this;
155
156 if (q.magnitude() != static_cast<T>(0)) { q.normalize(); }
157
158 // roll (x-axis rotation)
159 T sinxCosp = static_cast<T>(two * ((q.s * q.v[0]) + (q.v[1] * q.v[2])));
160 T cosxCosp = static_cast<T>(1.0 - (two * ((q.v[0] * q.v[0]) + (q.v[1] * q.v[1]))));
161 res[0] = static_cast<T>(std::atan2(sinxCosp, cosxCosp));
162
163 // pitch (y-axis rotation)
164 T siny = static_cast<T>(std::sqrt(1.0 + (two * ((q.s * q.v[1]) - (q.v[0] * q.v[2])))));
165 T cosy = static_cast<T>(std::sqrt(1.0 - (two * ((q.s * q.v[1]) - (q.v[0] * q.v[2])))));
166 res[1] = static_cast<T>((two * std::atan2(siny, cosy)) - (M_PI * half));
167
168 // yaw (z-axis rotation)
169 T sinzCosp = static_cast<T>(two * ((q.s * q.v[2]) + (q.v[0] * q.v[1])));
170 T coszCosp = static_cast<T>(1.0 - (two * ((q.v[1] * q.v[1]) + (q.v[2] * q.v[2]))));
171 res[2] = static_cast<T>(std::atan2(sinzCosp, coszCosp));
172
173 return res;
174 }
175
177 vec_type res = to_radians();
178 res[0] = rad_to_deg(res[0]);
179 res[1] = rad_to_deg(res[1]);
180 res[2] = rad_to_deg(res[2]);
181 return res;
182 }
183
184 _MSTD_CONSTEXPR20 T scalar(const quat<T>& other) { return (s * other.s) + v.dot(other.v); }
185
186 #pragma endregion // QUATERNION_OPERATIONS
187
188 #pragma region OPERATORS
189
190 _MSTD_CONSTEXPR20 quat<T>& operator+=(const quat<T>& other) {
191 s += other.s;
192 v += other.v;
193 return *this;
194 }
195
196 _MSTD_CONSTEXPR20 quat<T>& operator-=(const quat<T>& other) {
197 s -= other.s;
198 v -= other.v;
199 return *this;
200 }
201
202 _MSTD_CONSTEXPR20 quat<T>& operator*=(const quat<T>& other) {
203 T t = s;
204 s = (s * other.s) - v.dot(other.v);
205 v = (other.v * t) + (v * other.s) + v.cross(other.v);
206 return *this;
207 }
208
209 _MSTD_CONSTEXPR20 quat<T>& operator*=(const vec_type& other) {
210 quat<T> p(static_cast<T>(0), other);
211 *this = p;
212 return *this;
213 }
214
215 _MSTD_CONSTEXPR20 quat<T>& operator*=(const T& other) {
216 s *= other;
217 v *= other;
218 return *this;
219 }
220
221 _MSTD_CONSTEXPR20 quat<T>& operator/=(const quat<T>& other) {
222 *this *= other.inverted();
223 return *this;
224 }
225
226 _MSTD_CONSTEXPR20 quat<T>& operator/=(const T& other) {
227 if (other == static_cast<T>(0)) { return *this; }
228 s /= other;
229 v /= other;
230 return *this;
231 }
232
233 _MSTD_CONSTEXPR20 quat<T> operator+(const quat<T>& other) const {
234 quat<T> res = *this;
235 return res += other;
236 }
237
238 _MSTD_CONSTEXPR20 quat<T> operator-(const quat<T>& other) const {
239 quat<T> res = *this;
240 return res -= other;
241 }
242
243 _MSTD_CONSTEXPR20 quat<T> operator*(const quat<T>& other) const {
244 quat<T> res = *this;
245 return res *= other;
246 }
247
248 _MSTD_CONSTEXPR20 quat<T> operator*(const vec_type& other) const {
249 quat<T> res = *this;
250 return res *= other;
251 }
252
253 friend _MSTD_CONSTEXPR20 quat<T> operator*(const vec_type& other, const quat<T>& quaternion) {
254 return quaternion * other;
255 }
256
257 _MSTD_CONSTEXPR20 quat<T> operator*(const T& other) const {
258 quat<T> res = *this;
259 return res *= other;
260 }
261
262 friend _MSTD_CONSTEXPR20 quat<T> operator*(const T& other, const quat<T>& quaternion) { return quaternion * other; }
263
264 _MSTD_CONSTEXPR20 quat<T> operator/(const quat<T>& other) const {
265 quat<T> res = *this;
266 return res /= other;
267 }
268
269 _MSTD_CONSTEXPR20 quat<T> operator/(const T& other) const {
270 quat<T> res = *this;
271 return res /= other;
272 }
273
274 _MSTD_CONSTEXPR20 quat<T> operator-() const { return *this * -1; }
275
276 _MSTD_CONSTEXPR20 quat<T> operator+() const { return quat<T>(*this); }
277
279 s -= 1;
280 --v;
281 return *this;
282 }
283
285 quat<T> old = *this;
286 operator--();
287 return old;
288 }
289
291 s += 1;
292 ++v;
293 return *this;
294 }
295
297 quat<T> old = *this;
298 operator++();
299 return old;
300 }
301
302 _MSTD_CONSTEXPR20 bool operator==(const quat<T>& other) const { return s == other.s && v == other.v; }
303
304 _MSTD_CONSTEXPR20 bool operator!=(const quat<T>& other) const { return s != other.s || v != other.v; }
305
306 friend std::ostream& operator<<(std::ostream& str, const quat<T>& quaternion) {
307 return str << "(" << std::to_string(quaternion.s) << ", " << quaternion.v << ")";
308 }
309
310 #pragma endregion // OPERATORS
311 };
312} // namespace mstd
313 #endif
314#endif
_MSTD_CONSTEXPR20 quat< T > operator*(const vec_type &other) const
Definition quat.hpp:248
_MSTD_CONSTEXPR20 quat()
Definition quat.hpp:41
_MSTD_CONSTEXPR20 quat< T > operator-(const quat< T > &other) const
Definition quat.hpp:238
_MSTD_CONSTEXPR20 quat< T > & operator/=(const T &other)
Definition quat.hpp:226
_MSTD_CONSTEXPR20 quat< T > inverted() const
Definition quat.hpp:144
_MSTD_CONSTEXPR20 quat< T > & operator*=(const vec_type &other)
Definition quat.hpp:209
friend _MSTD_CONSTEXPR20 quat< T > operator*(const vec_type &other, const quat< T > &quaternion)
Definition quat.hpp:253
friend _MSTD_CONSTEXPR20 quat< T > operator*(const T &other, const quat< T > &quaternion)
Definition quat.hpp:262
vec< 3, T > vec_type
Definition quat.hpp:34
_MSTD_CONSTEXPR20 quat< T > & operator/=(const quat< T > &other)
Definition quat.hpp:221
_MSTD_CONSTEXPR20 quat(const T &scalar, const T &x, const T &y, const T &z)
Definition quat.hpp:45
_MSTD_CONSTEXPR20 ~quat()=default
_MSTD_CONSTEXPR20 quat< T > operator*(const quat< T > &other) const
Definition quat.hpp:243
T s
Definition quat.hpp:36
_MSTD_CONSTEXPR20 quat< T > operator++(int)
Definition quat.hpp:296
_MSTD_CONSTEXPR20 quat< T > operator--(int)
Definition quat.hpp:284
_MSTD_CONSTEXPR20 bool operator!=(const quat< T > &other) const
Definition quat.hpp:304
_MSTD_CONSTEXPR20 vec_type to_radians() const
Definition quat.hpp:149
_MSTD_CONSTEXPR20 quat< T > & operator*=(const T &other)
Definition quat.hpp:215
_MSTD_CONSTEXPR20 quat< T > conjugated() const
Definition quat.hpp:126
_MSTD_CONSTEXPR20 vec_type to_euler_angles() const
Definition quat.hpp:176
_MSTD_CONSTEXPR20 quat< T > & normalize()
Definition quat.hpp:110
_MSTD_CONSTEXPR20 quat< T > operator-() const
Definition quat.hpp:274
_MSTD_CONSTEXPR20 quat< T > & operator++()
Definition quat.hpp:290
_MSTD_CONSTEXPR20 T magnitude() const
Definition quat.hpp:108
_MSTD_CONSTEXPR20 quat< T > & operator--()
Definition quat.hpp:278
static _MSTD_CONSTEXPR20 quat< T > from_radians(const vec_type &radians)
Definition quat.hpp:93
vec_type v
Definition quat.hpp:37
_MSTD_CONSTEXPR20 quat(const T &scalar, const vec_type &vector)
Definition quat.hpp:43
_MSTD_CONSTEXPR20 quat< T > & invert()
Definition quat.hpp:131
_MSTD_CONSTEXPR20 bool operator==(const quat< T > &other) const
Definition quat.hpp:302
_MSTD_CONSTEXPR20 quat< T > operator/(const T &other) const
Definition quat.hpp:269
_MSTD_CONSTEXPR20 quat< T > operator*(const T &other) const
Definition quat.hpp:257
_MSTD_CONSTEXPR20 quat< T > operator+() const
Definition quat.hpp:276
_MSTD_CONSTEXPR20 quat< T > & operator*=(const quat< T > &other)
Definition quat.hpp:202
_MSTD_CONSTEXPR20 quat< T > normalized() const
Definition quat.hpp:116
_MSTD_CONSTEXPR20 quat< T > & operator+=(const quat< T > &other)
Definition quat.hpp:190
_MSTD_CONSTEXPR20 quat< T > & conjugate()
Definition quat.hpp:121
_MSTD_CONSTEXPR20 quat< T > & operator-=(const quat< T > &other)
Definition quat.hpp:196
T value_type
Definition quat.hpp:33
static _MSTD_CONSTEXPR20 quat< T > rotation(const vec_type &axis, const T &radians)
Definition quat.hpp:76
_MSTD_CONSTEXPR20 quat< T > operator/(const quat< T > &other) const
Definition quat.hpp:264
_MSTD_CONSTEXPR20 T scalar(const quat< T > &other)
Definition quat.hpp:184
_MSTD_CONSTEXPR20 quat< T > operator+(const quat< T > &other) const
Definition quat.hpp:233
static _MSTD_CONSTEXPR20 quat< T > from_euler_angels(const vec_type &eulerAngels)
Definition quat.hpp:89
_MSTD_CONSTEXPR20 quat(const quat< OT > &other)
Definition quat.hpp:51
_MSTD_CONSTEXPR20 quat< T > & operator=(const quat< OT > &other)
Definition quat.hpp:66
#define _MSTD_HAS_CXX17
Definition config.hpp:45
#define _MSTD_CONSTEXPR17
Definition config.hpp:76
#define _MSTD_HAS_CXX20
Definition config.hpp:52
#define _MSTD_CONSTEXPR20
Definition config.hpp:84
Definition arithmetic_types.hpp:23