opynsim
Unofficial C++ Documentation
Loading...
Searching...
No Matches
quaternion_functions.h
Go to the documentation of this file.
1#pragma once
2
12
13#include <concepts>
14#include <type_traits>
15#include <utility>
16
17namespace osc
18{
19 // returns a vector containing `isnan(qv)` for each `qv` in `q`
20 template<std::floating_point T>
22 {
23 return {isnan(q.w), isnan(q.x), isnan(q.y), isnan(q.z)};
24 }
25
26 template<typename T>
27 requires std::is_arithmetic_v<T>
28 constexpr Qua<T> conjugate(const Qua<T>& q)
29 {
30 return Qua<T>::wxyz(q.w, -q.x, -q.y, -q.z);
31 }
32
33 template<typename T>
34 requires std::is_arithmetic_v<T>
35 constexpr T dot(const Qua<T>& a, const Qua<T>& b)
36 {
37 return (a.w*b.w + a.x*b.x) + (a.y*b.y + a.z*b.z);
38 }
39
40 template<typename T>
41 requires std::is_arithmetic_v<T>
42 constexpr Qua<T> inverse(const Qua<T>& q)
43 {
44 return conjugate(q) / dot(q, q);
45 }
46
47 template<typename T>
48 T length(const Qua<T>& q)
49 {
50 return sqrt(dot(q, q));
51 }
52
53 // returns a normalized version of the provided argument
54 template<std::floating_point T>
56 {
57 const T len = length(q);
58
59 if (len <= static_cast<T>(0)) { // uh oh
60 return Qua<T>::wxyz(
61 static_cast<T>(1),
62 static_cast<T>(0),
63 static_cast<T>(0),
64 static_cast<T>(0)
65 );
66 }
67
68 const T one_over_len = static_cast<T>(1) / len;
69 return Qua<T>::wxyz(q.w * one_over_len, q.x * one_over_len, q.y * one_over_len, q.z * one_over_len);
70 }
71
72 template<typename T>
74 {
75 const T four_x_squared_minus_1 = m[0][0] - m[1][1] - m[2][2];
76 const T four_y_squared_minus_1 = m[1][1] - m[0][0] - m[2][2];
77 const T four_z_squared_minus_1 = m[2][2] - m[0][0] - m[1][1];
78 const T four_w_squared_minus_1 = m[0][0] + m[1][1] + m[2][2];
79
80 int biggest_index = 0;
81 T four_biggest_squared_minus_1 = four_w_squared_minus_1;
82 if (four_x_squared_minus_1 > four_biggest_squared_minus_1) {
83 four_biggest_squared_minus_1 = four_x_squared_minus_1;
84 biggest_index = 1;
85 }
86 if (four_y_squared_minus_1 > four_biggest_squared_minus_1) {
87 four_biggest_squared_minus_1 = four_y_squared_minus_1;
88 biggest_index = 2;
89 }
90 if (four_z_squared_minus_1 > four_biggest_squared_minus_1) {
91 four_biggest_squared_minus_1 = four_z_squared_minus_1;
92 biggest_index = 3;
93 }
94
95 const T biggest_val = sqrt(four_biggest_squared_minus_1 + static_cast<T>(1)) * static_cast<T>(0.5);
96 const T mult = static_cast<T>(0.25) / biggest_val;
97
98 switch(biggest_index) {
99 case 0:
100 return Qua<T>::wxyz(biggest_val, (m[1][2] - m[2][1]) * mult, (m[2][0] - m[0][2]) * mult, (m[0][1] - m[1][0]) * mult);
101 case 1:
102 return Qua<T>::wxyz((m[1][2] - m[2][1]) * mult, biggest_val, (m[0][1] + m[1][0]) * mult, (m[2][0] + m[0][2]) * mult);
103 case 2:
104 return Qua<T>::wxyz((m[2][0] - m[0][2]) * mult, (m[0][1] + m[1][0]) * mult, biggest_val, (m[1][2] + m[2][1]) * mult);
105 case 3:
106 return Qua<T>::wxyz((m[0][1] - m[1][0]) * mult, (m[2][0] + m[0][2]) * mult, (m[1][2] + m[2][1]) * mult, biggest_val);
107 default:
108 std::unreachable();
109 }
110 }
111
112 template<typename T>
117
118 template<typename T>
120 {
121 const T qxx(q.x * q.x);
122 const T qyy(q.y * q.y);
123 const T qzz(q.z * q.z);
124 const T qxz(q.x * q.z);
125 const T qxy(q.x * q.y);
126 const T qyz(q.y * q.z);
127 const T qwx(q.w * q.x);
128 const T qwy(q.w * q.y);
129 const T qwz(q.w * q.z);
130
131 Matrix<T, 3, 3> rv(T(1));
132
133 rv[0][0] = T(1) - T(2) * (qyy + qzz);
134 rv[0][1] = T(2) * (qxy + qwz);
135 rv[0][2] = T(2) * (qxz - qwy);
136
137 rv[1][0] = T(2) * (qxy - qwz);
138 rv[1][1] = T(1) - T(2) * (qxx + qzz);
139 rv[1][2] = T(2) * (qyz + qwx);
140
141 rv[2][0] = T(2) * (qxz + qwy);
142 rv[2][1] = T(2) * (qyz - qwx);
143 rv[2][2] = T(1) - T(2) * (qxx + qyy);
144
145 return rv;
146 }
147
148 template<typename T>
150 {
152 }
153
154 template<typename T>
156 {
157 return Qua<T>::wxyz(
158 static_cast<T>(1),
159 static_cast<T>(0),
160 static_cast<T>(0),
161 static_cast<T>(0)
162 );
163 }
164
165 template<
166 std::floating_point T,
167 AngularUnitTraits Units,
168 std::convertible_to<const Vector<T, 3>&> VectorLike
169 >
170 Qua<T> angle_axis(Angle<T, Units> angle, VectorLike&& axis)
171 {
172 const T s = sin(angle * static_cast<T>(0.5));
173 return Qua<T>(cos(angle * static_cast<T>(0.5)), static_cast<const Vector<T, 3>&>(axis) * s);
174 }
175
176 template<
177 std::floating_point T,
178 AngularUnitTraits Units
179 >
181 {
182 return angle_axis(angle, direction.direction_vector<T>());
183 }
184
185 // computes the rotation from `origin` to `destination`
186 template<typename T>
187 Qua<T> rotation(const Vector<T, 3>& origin, const Vector<T, 3>& destination)
188 {
189 const T cos_theta = dot(origin, destination);
190 if (cos_theta >= static_cast<T>(1) - epsilon_v<T>) {
191 // origin and destination point in the same direction
192 return quaternion_identity<T>();
193 }
194
195 Vector<T, 3> rotation_axis;
196 if (cos_theta < static_cast<T>(-1) + epsilon_v<T>) {
197 // special case when vectors in opposite directions :
198 // there is no "ideal" rotation axis
199 // So guess one; any will do as long as it's perpendicular to start
200 // This implementation favors a rotation around the Up axis (Y),
201 // since it's often what you want to do.
202 rotation_axis = cross(Vector<T, 3>(0, 0, 1), origin);
203 if (length2(rotation_axis) < epsilon_v<T>) { // bad luck, they were parallel, try again!
204 rotation_axis = cross(Vector<T, 3>(1, 0, 0), origin);
205 }
206
207 rotation_axis = normalize(rotation_axis);
208 return angle_axis(Degrees{180}, rotation_axis);
209 }
210
211 // Implementation from Stan Melax's Game Programming Gems 1 article
212 rotation_axis = cross(origin, destination);
213
214 const T s = sqrt((T(1) + cos_theta) * static_cast<T>(2));
215 const T invs = static_cast<T>(1) / s;
216
217 return Qua<T>::wxyz(
218 s * static_cast<T>(0.5f),
219 rotation_axis.x() * invs,
220 rotation_axis.y() * invs,
221 rotation_axis.z() * invs
222 );
223 }
224
225 template<typename T>
227 const Vector<T, 3>& x,
228 const Vector<T, 3>& y,
229 const Vector<T, 3>& z)
230 {
231 return quaternion_cast(Matrix<T, 3, 3>(x, y, z));
232 }
233
234 template<typename T>
236 {
237 const T y = static_cast<T>(2) * (q.y * q.z + q.w * q.x);
238 const T x = q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z;
239
241 //avoid atan2(0,0) - handle singularity - Matiis
242 return static_cast<T>(2) * atan2(q.x, q.w);
243 }
244
245 return atan2(y, x);
246 }
247
248 template<typename T>
250 {
251 return asin(clamp(static_cast<T>(-2) * (q.x * q.z - q.w * q.y), static_cast<T>(-1), static_cast<T>(1)));
252 }
253
254 template<typename T>
256 {
257 const T y = static_cast<T>(2) * (q.x * q.y + q.w * q.z);
258 const T x = q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z;
259
261 //avoid atan2(0,0) - handle singularity - Matiis
262 return RadiansT<T>{0};
263 }
264
265 return atan2(y, x);
266 }
267
268 template<typename T>
270 {
271 return Vector<RadiansT<T>, 3>(pitch(x), yaw(x), roll(x));
272 }
273}
Definition angle.h:26
Definition coordinate_direction.h:16
constexpr Vector< T, 3 > direction_vector() const
Definition coordinate_direction.h:90
Definition vector.h:63
constexpr reference x()
Returns (*this)[0]
Definition vector.h:157
constexpr reference z()
Returns (*this)[2]
Definition vector.h:167
constexpr reference y()
Returns (*this)[1]
Definition vector.h:162
Definition custom_decoration_generator.h:5
bool equal_within_epsilon(T x, T y)
Definition common_functions.h:265
RadiansT< T > pitch(const Qua< T > &q)
Definition quaternion_functions.h:235
constexpr Angle< Rep, Units > clamp(const Angle< Rep, Units > &v, const AngleMin &min, const AngleMax &max)
Definition angle.h:320
Qua< T > quaternion_from_xyz(const Vector< T, 3 > &x, const Vector< T, 3 > &y, const Vector< T, 3 > &z)
Definition quaternion_functions.h:226
GenType cos(GenType v)
Definition trigonometric_functions.h:37
RadiansT< T > roll(const Qua< T > &q)
Definition quaternion_functions.h:255
constexpr Matrix< T, 4, 4 > matrix4x4_cast(const Qua< T > &q)
Definition quaternion_functions.h:149
T length(const Vector< T, N > &v)
Definition geometric_functions.h:62
Qua< T > quaternion_cast(const Matrix< T, 3, 3 > &m)
Definition quaternion_functions.h:73
Vector< RadiansT< T >, 3 > to_euler_angles(const Qua< T > &x)
Definition quaternion_functions.h:269
constexpr T dot(T x, T y)
Definition geometric_functions.h:31
constexpr Matrix< T, 3, 3 > matrix3x3_cast(const Qua< T > &q)
Definition quaternion_functions.h:119
constexpr T length2(const Vector< T, N > &v)
Definition geometric_functions.h:69
Qua< T > rotation(const Vector< T, 3 > &origin, const Vector< T, 3 > &destination)
Definition quaternion_functions.h:187
RadiansT< T > yaw(const Qua< T > &q)
Definition quaternion_functions.h:249
GenType sin(GenType v)
Definition trigonometric_functions.h:13
constexpr Qua< T > quaternion_identity()
Definition quaternion_functions.h:155
T inverse(const Matrix< T, 3, 3 > &m)
Definition matrix_functions.h:158
constexpr Qua< T > conjugate(const Qua< T > &q)
Definition quaternion_functions.h:28
constexpr bool all_of(const Vector< bool, N > &v)
Definition functors.h:48
Vector< T, N > normalize(const Vector< T, N > &v)
Definition geometric_functions.h:76
bool isnan(T num)
Definition common_functions.h:319
Qua< T > angle_axis(Angle< T, Units > angle, VectorLike &&axis)
Definition quaternion_functions.h:170
RadiansT< Rep > atan2(Rep x, Rep y)
Definition trigonometric_functions.h:103
T sqrt(T num)
Definition geometric_functions.h:16
RadiansT< Rep > asin(Rep num)
Definition trigonometric_functions.h:97
constexpr CoordinateDirection cross(CoordinateDirection x, CoordinateDirection y)
Definition coordinate_direction.h:124
Definition matrix.h:15
Definition qua.h:22
T w
Definition qua.h:184
static constexpr Qua< T > wxyz(T w, T x, T y, T z)
Definition qua.h:34
T y
Definition qua.h:186
T x
Definition qua.h:185
T z
Definition qua.h:187