2#ifndef LIBSBX_MATH_QUATERNION_HPP_
3#define LIBSBX_MATH_QUATERNION_HPP_
10#include <yaml-cpp/yaml.h>
12#include <fmt/format.h>
17#include <libsbx/math/vector3.hpp>
18#include <libsbx/math/vector4.hpp>
19#include <libsbx/math/matrix4x4.hpp>
24template<
floating_po
int Type>
27 template<
floating_po
int Other>
30 template<
floating_po
int Other>
33 template<
floating_po
int Other>
36 template<
floating_po
int Other>
41 using value_type = Type;
42 using reference = value_type&;
43 using const_reference =
const value_type&;
44 using size_type = std::size_t;
45 using length_type = std::float_t;
50 inline static constexpr basic_quaternion identity{vector_type::zero, value_type{1}};
52 template<
floating_po
int Other = value_type>
55 template<
floating_po
int Complex = value_type,
floating_po
int Scalar = value_type>
58 template<
floating_po
int Other = value_type>
61 template<
floating_po
int Other = value_type>
64 template<
floating_po
int Complex = value_type,
floating_po
int Scalar = value_type>
67 template<
floating_po
int Other = value_type>
70 template<
floating_po
int Other = value_type>
73 template<
floating_po
int Other = value_type>
74 [[nodiscard]]
static constexpr auto wxyz(Other w, Other x, Other y, Other z)
noexcept ->
basic_quaternion {
85 if (length_squared < math::epsilonf) {
86 return basic_quaternion::identity;
89 const auto inverse_length_squared = 1.0f / length_squared;
100 if(length <=
static_cast<value_type
>(0)) {
101 return basic_quaternion{
static_cast<value_type
>(0),
static_cast<value_type
>(0),
static_cast<value_type
>(0),
static_cast<value_type
>(1)};
104 const auto one_over_length =
static_cast<value_type
>(1) / length;
110 return lhs.x() * rhs.x() + lhs.y() * rhs.y() + lhs.z() * rhs.z() + lhs.w() * rhs.w();
114 return start * (1.0f - t) + end * t;
127 utility::assert_that(a >= 0.0f && a <= 1.0f,
"Interpolation factor out of bounds in quaternion slerp");
131 auto cos_theta = dot(x, y);
135 if(cos_theta <
static_cast<value_type
>(0)) {
137 cos_theta = -cos_theta;
141 if(cos_theta >
static_cast<value_type
>(1) - math::epsilon_v<value_type>) {
143 return basic_quaternion::wxyz(
144 math::mix(x.w(), z.w(), a),
145 math::mix(x.x(), z.x(), a),
146 math::mix(x.y(), z.y(), a),
147 math::mix(x.z(), z.z(), a)
151 const auto angle = std::acos(cos_theta);
152 return (std::sin((
static_cast<value_type
>(1) - a) *
angle) * x + std::sin(a *
angle) * z) / std::sin(
angle);
162 const auto sinr_cosp = 2.0f * (w * x + y * z);
163 const auto cosr_cosp = 1.0f - 2.0f * (x * x + y * y);
164 auto roll = std::atan2(sinr_cosp, cosr_cosp);
166 const auto sinp = 2.0f * (w * y - z * x);
169 if (std::abs(sinp) >= 1.0f) {
170 pitch = std::copysign(3.14159265358979323846f / 2.0f, sinp);
172 pitch = std::asin(sinp);
175 const auto siny_cosp = 2.0f * (w * z + x * y);
176 const auto cosy_cosp = 1.0f - 2.0f * (y * y + z * z);
178 auto yaw = std::atan2(siny_cosp, cosy_cosp);
180 return math::vector3{to_degrees(radian{roll}).value(),
to_degrees(radian{pitch}).value(),
to_degrees(radian{yaw}).value()};
183 template<
floating_po
int Other = value_type>
184 constexpr auto operator+=(
const basic_quaternion<Other>& other)
noexcept -> basic_quaternion&;
186 template<
floating_po
int Other = value_type>
187 constexpr auto operator-=(
const basic_quaternion<Other>& other)
noexcept -> basic_quaternion&;
189 template<
floating_po
int Other = value_type>
190 constexpr auto operator*=(Other value)
noexcept -> basic_quaternion&;
192 constexpr auto operator*(
const vector_type& vector)
const noexcept -> vector_type {
193 const auto t = vector_type::cross(_complex, vector) * 2.0f;
195 return vector + (t * _scalar) + vector3::cross(_complex, t);
198 template<
floating_po
int Other = value_type>
199 constexpr auto operator*=(
const basic_quaternion<Other>& other)
noexcept -> basic_quaternion&;
201 template<
floating_po
int Other = value_type>
202 constexpr auto operator/=(Other value)
noexcept -> basic_quaternion&;
204 [[nodiscard]]
constexpr auto x() noexcept -> reference;
206 [[nodiscard]] constexpr auto x() const noexcept -> const_reference;
208 [[nodiscard]] constexpr auto y() noexcept -> reference;
210 [[nodiscard]] constexpr auto y() const noexcept -> const_reference;
212 [[nodiscard]] constexpr auto z() noexcept -> reference;
214 [[nodiscard]] constexpr auto z() const noexcept -> const_reference;
216 [[nodiscard]] constexpr auto w() noexcept -> reference;
218 [[nodiscard]] constexpr auto w() const noexcept -> const_reference;
220 [[nodiscard]] constexpr auto complex() noexcept -> vector_type&;
222 [[nodiscard]] constexpr auto complex() const noexcept -> const vector_type&;
224 [[nodiscard]] constexpr auto scalar() noexcept -> reference;
226 [[nodiscard]] constexpr auto scalar() const noexcept -> const_reference;
228 [[nodiscard]] constexpr auto length_squared() const noexcept -> length_type;
230 [[nodiscard]] constexpr auto length() const noexcept -> length_type;
232 constexpr auto normalize() noexcept -> basic_quaternion&;
236 vector_type _complex;
241template<floating_point Lhs, floating_point Rhs>
242[[nodiscard]] constexpr auto operator==(const basic_quaternion<Lhs>& lhs, const basic_quaternion<Rhs>& rhs) noexcept ->
bool;
244template<floating_point Lhs, floating_point Rhs>
245[[nodiscard]] constexpr auto operator+(basic_quaternion<Lhs> lhs, const basic_quaternion<Rhs>& rhs) noexcept -> basic_quaternion<Lhs>;
247template<floating_point Lhs, floating_point Rhs>
248[[nodiscard]] constexpr auto operator-(basic_quaternion<Lhs> lhs, const basic_quaternion<Rhs>& rhs) noexcept -> basic_quaternion<Lhs>;
250template<floating_point Type>
251[[nodiscard]] constexpr auto operator-(basic_quaternion<Type> quaternion) noexcept -> basic_quaternion<Type>;
253template<floating_point Lhs, floating_point Rhs>
254[[nodiscard]] constexpr auto operator*(basic_quaternion<Lhs> lhs, Rhs rhs) noexcept -> basic_quaternion<Lhs>;
256template<floating_point Lhs, floating_point Rhs>
257[[nodiscard]] constexpr auto operator*(Lhs lhs, basic_quaternion<Rhs> rhs) noexcept -> basic_quaternion<Rhs>;
259template<floating_point Lhs, floating_point Rhs>
260[[nodiscard]] constexpr auto operator*(basic_quaternion<Lhs> lhs, const basic_quaternion<Rhs>& rhs) noexcept -> basic_quaternion<Lhs>;
262template<floating_point Lhs, floating_point Rhs>
263[[nodiscard]] constexpr auto operator/(basic_quaternion<Lhs> lhs, Rhs rhs) noexcept -> basic_quaternion<Lhs>;
266using quaternionf = basic_quaternion<std::float_t>;
269using quaternion = quaternionf;
273template<sbx::math::floating_point Type>
274struct std::hash<sbx::math::basic_quaternion<Type>> {
280template<sbx::math::
floating_po
int Type>
281struct YAML::convert<sbx::math::basic_quaternion<Type>> {
289template<sbx::math::
floating_po
int Type>
291 return out << YAML::convert<sbx::math::basic_quaternion<Type>>::encode(quaternion);
294template<sbx::math::
floating_po
int Type>
295struct fmt::formatter<sbx::math::basic_quaternion<Type>> {
297 template<
typename ParseContext>
298 constexpr auto parse(ParseContext& context) ->
decltype(context.begin());
300 template<
typename FormatContext>
305#include <libsbx/math/quaternion.ipp>
Angle types and utilities.
constexpr auto to_degrees(const basic_radian< Type > &radian) noexcept -> basic_degree< Type >
Converts radians to degrees.
Definition: angle.ipp:412
Unified angle type stored internally in radians.
Definition: angle.hpp:591
Definition: matrix3x3.hpp:26
Definition: matrix4x4.hpp:26
Definition: quaternion.hpp:25
static constexpr auto slerp(const basic_quaternion &x, basic_quaternion y, const value_type a) noexcept -> basic_quaternion
Spherical linear interpolation between two quaternions.
Definition: quaternion.hpp:126
Definition: vector3.hpp:23
Concept for scalar numeric types.
Definition: concepts.hpp:150
Generic math algorithms and helpers.
Core numeric concepts and type traits.