20 #ifndef ANTKEEPER_MATH_EULER_ANGLES_HPP
21 #define ANTKEEPER_MATH_EULER_ANGLES_HPP
86 template <std::
integral T>
89 const auto x =
static_cast<T
>(sequence);
90 return {x & 3, (x >> 2) & 3, x >> 4};
108 template <rotation_sequence Sequence,
class T>
111 constexpr
auto axes = rotation_axes<int>(Sequence);
112 constexpr
auto proper = axes[0] == axes[2];
113 constexpr
auto i = axes[0];
114 constexpr
auto j = axes[1];
115 constexpr
auto k = proper ? 3 - i - j : axes[2];
116 constexpr
auto sign =
static_cast<T
>(((i - j) * (j - k) * (k - i)) >> 1);
121 auto d = q.i[k] *
sign;
122 if constexpr (!proper)
129 const auto aa_bb =
a *
a +
b *
b;
132 angles[1] = std::acos(T{2} * aa_bb / (aa_bb +
c *
c +
d *
d) - T{1});
134 if (
std::abs(angles[1]) <= tolerance)
137 angles[2] = std::atan2(b, a) * T{2};
139 else if (
std::abs(angles[1] - pi<T>) <= tolerance)
142 angles[2] = std::atan2(-d, c) * T{-2};
146 const auto half_sum = std::atan2(b, a);
147 const auto half_diff = std::atan2(-d, c);
149 angles[0] = half_sum + half_diff;
150 angles[2] = half_sum - half_diff;
153 if constexpr (!proper)
156 angles[1] -= half_pi<T>;
165 return euler_from_quat<rotation_sequence::zxz, T>(q, tolerance);
171 return euler_from_quat<rotation_sequence::xyx, T>(q, tolerance);
177 return euler_from_quat<rotation_sequence::yzy, T>(q, tolerance);
183 return euler_from_quat<rotation_sequence::zyz, T>(q, tolerance);
189 return euler_from_quat<rotation_sequence::xzx, T>(q, tolerance);
195 return euler_from_quat<rotation_sequence::yxy, T>(q, tolerance);
201 return euler_from_quat<rotation_sequence::xyz, T>(q, tolerance);
207 return euler_from_quat<rotation_sequence::yzx, T>(q, tolerance);
213 return euler_from_quat<rotation_sequence::zxy, T>(q, tolerance);
219 return euler_from_quat<rotation_sequence::xzy, T>(q, tolerance);
225 return euler_from_quat<rotation_sequence::zyx, T>(q, tolerance);
231 return euler_from_quat<rotation_sequence::yxz, T>(q, tolerance);
240 return euler_zxz_from_quat<T>(q, tolerance);
242 return euler_xyx_from_quat<T>(q, tolerance);
244 return euler_yzy_from_quat<T>(q, tolerance);
246 return euler_zyz_from_quat<T>(q, tolerance);
248 return euler_xzx_from_quat<T>(q, tolerance);
250 return euler_yxy_from_quat<T>(q, tolerance);
252 return euler_xyz_from_quat<T>(q, tolerance);
254 return euler_yzx_from_quat<T>(q, tolerance);
256 return euler_zxy_from_quat<T>(q, tolerance);
258 return euler_xzy_from_quat<T>(q, tolerance);
260 return euler_zyx_from_quat<T>(q, tolerance);
263 return euler_yxz_from_quat<T>(q, tolerance);
282 template <rotation_sequence Sequence,
class T>
285 const auto half_angles = angles * T{0.5};
286 const T cx = std::cos(half_angles.x());
287 const T sx = std::sin(half_angles.x());
288 const T cy = std::cos(half_angles.y());
289 const T sy = std::sin(half_angles.y());
290 const T cz = std::cos(half_angles.z());
291 const T sz = std::sin(half_angles.z());
297 cx * cy * cz - sx * cy * sz,
298 cx * cz * sy + sx * sy * sz,
299 cx * sy * sz - sx * cz * sy,
300 cx * cy * sz + cy * cz * sx
307 cx * cy * cz - sx * cy * sz,
308 cx * cy * sz + cy * cz * sx,
309 cx * cz * sy + sx * sy * sz,
310 cx * sy * sz - sx * cz * sy
317 cx * cy * cz - sx * cy * sz,
318 cx * sy * sz - sx * cz * sy,
319 cx * cy * sz + cy * cz * sx,
320 cx * cz * sy + sx * sy * sz
327 cx * cy * cz - sx * cy * sz,
328 -cx * sy * sz + sx * cz * sy,
329 cx * cz * sy + sx * sy * sz,
330 cx * cy * sz + cy * cz * sx
337 cx * cy * cz - sx * cy * sz,
338 cx * cy * sz + cy * cz * sx,
339 -cx * sy * sz + sx * cz * sy,
340 cx * cz * sy + sx * sy * sz
347 cx * cy * cz - sx * cy * sz,
348 cx * cz * sy + sx * sy * sz,
349 cx * cy * sz + cy * cz * sx,
350 -cx * sy * sz + sx * cz * sy
357 cx * cy * cz + sx * sy * sz,
358 -cx * sy * sz + cy * cz * sx,
359 cx * cz * sy + sx * cy * sz,
360 cx * cy * sz - sx * cz * sy
367 cx * cy * cz + sx * sy * sz,
368 cx * cy * sz - sx * cz * sy,
369 -cx * sy * sz + cy * cz * sx,
370 cx * cz * sy + sx * cy * sz
377 cx * cy * cz + sx * sy * sz,
378 cx * cz * sy + sx * cy * sz,
379 cx * cy * sz - sx * cz * sy,
380 -cx * sy * sz + cy * cz * sx
387 cx * cy * cz - sx * sy * sz,
388 cx * sy * sz + cy * cz * sx,
389 cx * cy * sz + sx * cz * sy,
390 cx * cz * sy - sx * cy * sz
397 cx * cy * cz - sx * sy * sz,
398 cx * cy * sz + sx * cz * sy,
399 cx * cz * sy - sx * cy * sz,
400 cx * sy * sz + cy * cz * sx
407 cx * cy * cz - sx * sy * sz,
408 cx * cz * sy - sx * cy * sz,
409 cx * sy * sz + cy * cz * sx,
410 cx * cy * sz + sx * cz * sy
418 return euler_to_quat<rotation_sequence::zxz, T>(angles);
424 return euler_to_quat<rotation_sequence::xyx, T>(angles);
430 return euler_to_quat<rotation_sequence::yzy, T>(angles);
436 return euler_to_quat<rotation_sequence::zyz, T>(angles);
442 return euler_to_quat<rotation_sequence::xzx, T>(angles);
448 return euler_to_quat<rotation_sequence::yxy, T>(angles);
454 return euler_to_quat<rotation_sequence::xyz, T>(angles);
460 return euler_to_quat<rotation_sequence::yzx, T>(angles);
466 return euler_to_quat<rotation_sequence::zxy, T>(angles);
472 return euler_to_quat<rotation_sequence::xzy, T>(angles);
478 return euler_to_quat<rotation_sequence::zyx, T>(angles);
484 return euler_to_quat<rotation_sequence::yxz, T>(angles);
493 return euler_zxz_to_quat<T>(angles);
495 return euler_xyx_to_quat<T>(angles);
497 return euler_yzy_to_quat<T>(angles);
499 return euler_zyz_to_quat<T>(angles);
501 return euler_xzx_to_quat<T>(angles);
503 return euler_yxy_to_quat<T>(angles);
505 return euler_xyz_to_quat<T>(angles);
507 return euler_yzx_to_quat<T>(angles);
509 return euler_zxy_to_quat<T>(angles);
511 return euler_xzy_to_quat<T>(angles);
513 return euler_zyx_to_quat<T>(angles);
516 return euler_yxz_to_quat<T>(angles);
Mathematical functions and data types.
quat< T > euler_yzy_to_quat(const vec3< T > &angles)
Constructs a quaternion from Euler angles.
vec3< T > euler_yxy_from_quat(const quat< T > &q, T tolerance=T{1e-6})
Derives Euler angles from a unit quaternion.
constexpr vector< T, N > sign(const vector< T, N > &x)
Returns a vector containing the signs of each element.
quat< T > euler_xyz_to_quat(const vec3< T > &angles)
Constructs a quaternion from Euler angles.
constexpr vec3< T > rotation_axes(rotation_sequence sequence) noexcept
Returns the indices of the axes of a rotation sequence.
vec3< T > euler_xzx_from_quat(const quat< T > &q, T tolerance=T{1e-6})
Derives Euler angles from a unit quaternion.
quat< T > euler_xzx_to_quat(const vec3< T > &angles)
Constructs a quaternion from Euler angles.
quat< T > euler_yxy_to_quat(const vec3< T > &angles)
Constructs a quaternion from Euler angles.
vec3< T > euler_from_quat(const quat< T > &q, T tolerance=T{1e-6})
Derives Euler angles from a unit quaternion.
vec3< T > euler_zyz_from_quat(const quat< T > &q, T tolerance=T{1e-6})
Derives Euler angles from a unit quaternion.
quat< T > euler_yxz_to_quat(const vec3< T > &angles)
Constructs a quaternion from Euler angles.
vec3< T > euler_zxz_from_quat(const quat< T > &q, T tolerance=T{1e-6})
Derives Euler angles from a unit quaternion.
constexpr vector< T, N > abs(const vector< T, N > &x)
Returns the absolute values of each element.
quat< T > euler_yzx_to_quat(const vec3< T > &angles)
Constructs a quaternion from Euler angles.
quat< T > euler_zyz_to_quat(const vec3< T > &angles)
Constructs a quaternion from Euler angles.
quat< T > euler_zxz_to_quat(const vec3< T > &angles)
Constructs a quaternion from Euler angles.
vec3< T > euler_xyx_from_quat(const quat< T > &q, T tolerance=T{1e-6})
Derives Euler angles from a unit quaternion.
quat< T > euler_xzy_to_quat(const vec3< T > &angles)
Constructs a quaternion from Euler angles.
vec3< T > euler_xyz_from_quat(const quat< T > &q, T tolerance=T{1e-6})
Derives Euler angles from a unit quaternion.
rotation_sequence
Rotation sequences of proper Euler and Tait-Bryan angles.
@ zxz
z-x-z rotation sequence (proper Euler angles).
@ zxy
z-x-y rotation sequence (Tait-Bryan angles).
@ yzx
y-z-x rotation sequence (Tait-Bryan angles).
@ yxz
y-x-z rotation sequence (Tait-Bryan angles).
@ zyz
z-y-z rotation sequence (proper Euler angles).
@ yzy
y-z-y rotation sequence (proper Euler angles).
@ xzx
x-z-x rotation sequence (proper Euler angles).
@ yxy
y-x-y rotation sequence (proper Euler angles).
@ xyz
x-y-z rotation sequence (Tait-Bryan angles).
@ xzy
x-z-y rotation sequence (Tait-Bryan angles).
@ xyx
x-y-x rotation sequence (proper Euler angles).
@ zyx
z-y-x rotation sequence (Tait-Bryan angles).
quat< T > euler_to_quat(const vec3< T > &angles)
Constructs a quaternion from Euler angles.
quat< T > euler_zxy_to_quat(const vec3< T > &angles)
Constructs a quaternion from Euler angles.
vec3< T > euler_zyx_from_quat(const quat< T > &q, T tolerance=T{1e-6})
Derives Euler angles from a unit quaternion.
vec3< T > euler_yxz_from_quat(const quat< T > &q, T tolerance=T{1e-6})
Derives Euler angles from a unit quaternion.
vec3< T > euler_zxy_from_quat(const quat< T > &q, T tolerance=T{1e-6})
Derives Euler angles from a unit quaternion.
vec3< T > euler_yzy_from_quat(const quat< T > &q, T tolerance=T{1e-6})
Derives Euler angles from a unit quaternion.
quat< T > euler_xyx_to_quat(const vec3< T > &angles)
Constructs a quaternion from Euler angles.
quat< T > euler_zyx_to_quat(const vec3< T > &angles)
Constructs a quaternion from Euler angles.
vec3< T > euler_yzx_from_quat(const quat< T > &q, T tolerance=T{1e-6})
Derives Euler angles from a unit quaternion.
vec3< T > euler_xzy_from_quat(const quat< T > &q, T tolerance=T{1e-6})
Derives Euler angles from a unit quaternion.
Quaternion composed of a real scalar part and imaginary vector part.