diff --git a/source/blender/blenlib/BLI_math_angle_types.hh b/source/blender/blenlib/BLI_math_angle_types.hh index 556f47e9769..f76d3009df8 100644 --- a/source/blender/blenlib/BLI_math_angle_types.hh +++ b/source/blender/blenlib/BLI_math_angle_types.hh @@ -19,33 +19,31 @@ namespace blender::math { -namespace detail { - /** - * A `blender::math::AngleRadian` is a typical radian angle. + * A `blender::math::AngleRadianBase` is a typical radian angle. * - Storage : `1 * sizeof(T)` * - Range : [-inf..inf] * - Fast : Everything not slow. * - Slow : `cos()`, `sin()`, `tan()`, `AngleRadian(cos, sin)` */ -template struct AngleRadian { +template struct AngleRadianBase { private: T value_; public: - AngleRadian() = default; + AngleRadianBase() = default; - AngleRadian(const T &radian) : value_(radian){}; - explicit AngleRadian(const T &cos, const T &sin) : value_(math::atan2(sin, cos)){}; + AngleRadianBase(const T &radian) : value_(radian){}; + explicit AngleRadianBase(const T &cos, const T &sin) : value_(math::atan2(sin, cos)){}; /** Static functions. */ - static AngleRadian identity() + static AngleRadianBase identity() { return 0; } - static AngleRadian from_degree(const T °rees) + static AngleRadianBase from_degree(const T °rees) { return degrees * T(M_PI / 180.0); } @@ -81,7 +79,7 @@ template struct AngleRadian { /** * Return the angle wrapped inside [-pi..pi] interval. Basically `(angle + pi) % 2pi - pi`. */ - AngleRadian wrapped() const + AngleRadianBase wrapped() const { return math::mod_periodic(value_ + T(M_PI), T(2 * M_PI)) - T(M_PI); } @@ -92,80 +90,80 @@ template struct AngleRadian { * This means the interpolation between the returned value and \a reference will always take the * shortest path. */ - AngleRadian wrapped_around(const AngleRadian &reference) const + AngleRadianBase wrapped_around(const AngleRadianBase &reference) const { return reference + (*this - reference).wrapped(); } /** Operators. */ - friend AngleRadian operator+(const AngleRadian &a, const AngleRadian &b) + friend AngleRadianBase operator+(const AngleRadianBase &a, const AngleRadianBase &b) { return a.value_ + b.value_; } - friend AngleRadian operator-(const AngleRadian &a, const AngleRadian &b) + friend AngleRadianBase operator-(const AngleRadianBase &a, const AngleRadianBase &b) { return a.value_ - b.value_; } - friend AngleRadian operator*(const AngleRadian &a, const AngleRadian &b) + friend AngleRadianBase operator*(const AngleRadianBase &a, const AngleRadianBase &b) { return a.value_ * b.value_; } - friend AngleRadian operator/(const AngleRadian &a, const AngleRadian &b) + friend AngleRadianBase operator/(const AngleRadianBase &a, const AngleRadianBase &b) { return a.value_ / b.value_; } - friend AngleRadian operator-(const AngleRadian &a) + friend AngleRadianBase operator-(const AngleRadianBase &a) { return -a.value_; } - AngleRadian &operator+=(const AngleRadian &b) + AngleRadianBase &operator+=(const AngleRadianBase &b) { value_ += b.value_; return *this; } - AngleRadian &operator-=(const AngleRadian &b) + AngleRadianBase &operator-=(const AngleRadianBase &b) { value_ -= b.value_; return *this; } - AngleRadian &operator*=(const AngleRadian &b) + AngleRadianBase &operator*=(const AngleRadianBase &b) { value_ *= b.value_; return *this; } - AngleRadian &operator/=(const AngleRadian &b) + AngleRadianBase &operator/=(const AngleRadianBase &b) { value_ /= b.value_; return *this; } - friend bool operator==(const AngleRadian &a, const AngleRadian &b) + friend bool operator==(const AngleRadianBase &a, const AngleRadianBase &b) { return a.value_ == b.value_; } - friend bool operator!=(const AngleRadian &a, const AngleRadian &b) + friend bool operator!=(const AngleRadianBase &a, const AngleRadianBase &b) { return !(a == b); } - friend std::ostream &operator<<(std::ostream &stream, const AngleRadian &rot) + friend std::ostream &operator<<(std::ostream &stream, const AngleRadianBase &rot) { return stream << "AngleRadian(" << rot.value_ << ")"; } }; /** - * A `blender::math::AngleCartesian` stores the angle as cosine + sine tuple. + * A `blender::math::AngleCartesianBase` stores the angle as cosine + sine tuple. * - Storage : `2 * sizeof(T)` * - Range : [-pi..pi] * - Fast : `cos()`, `sin()`, `tan()`, `AngleCartesian(cos, sin)` @@ -175,18 +173,18 @@ template struct AngleRadian { * advantage when trigonometric values of an angle are required but not directly the angle itself. * It is also a nice shortcut for using the trigonometric identities. */ -template struct AngleCartesian { +template struct AngleCartesianBase { private: T cos_; T sin_; public: - AngleCartesian() = default; + AngleCartesianBase() = default; /** * Create an angle from a (x, y) position on the unit circle. */ - AngleCartesian(const T &x, const T &y) : cos_(x), sin_(y) + AngleCartesianBase(const T &x, const T &y) : cos_(x), sin_(y) { BLI_assert(math::abs(x * x + y * y - T(1)) < T(1e-4)); } @@ -194,34 +192,34 @@ template struct AngleCartesian { /** * Create an angle from a radian value. */ - explicit AngleCartesian(const T &radian) - : AngleCartesian(math::cos(radian), math::sin(radian)){}; - explicit AngleCartesian(const AngleRadian &angle) - : AngleCartesian(math::cos(angle.radian()), math::sin(angle.radian())){}; + explicit AngleCartesianBase(const T &radian) + : AngleCartesianBase(math::cos(radian), math::sin(radian)){}; + explicit AngleCartesianBase(const AngleRadianBase &angle) + : AngleCartesianBase(math::cos(angle.radian()), math::sin(angle.radian())){}; /** Static functions. */ - static AngleCartesian identity() + static AngleCartesianBase identity() { return {1, 0}; } - static AngleCartesian from_degree(const T °rees) + static AngleCartesianBase from_degree(const T °rees) { - return AngleCartesian(degrees * T(M_PI / 180.0)); + return AngleCartesianBase(degrees * T(M_PI / 180.0)); } /** * Create an angle from a (x, y) position on the 2D plane. * Fallback to identity if (x, y) is origin (0, 0). */ - static AngleCartesian from_point(const T &x, const T &y) + static AngleCartesianBase from_point(const T &x, const T &y) { T norm = math::sqrt(x * x + y * y); if (norm == 0) { return identity(); } - return AngleCartesian(x / norm, y / norm); + return AngleCartesianBase(x / norm, y / norm); } /** Conversions. */ @@ -273,17 +271,17 @@ template struct AngleCartesian { * purpose of this class). */ - friend AngleCartesian operator+(const AngleCartesian &a, const AngleCartesian &b) + friend AngleCartesianBase operator+(const AngleCartesianBase &a, const AngleCartesianBase &b) { return {a.cos_ * b.cos_ - a.sin_ * b.sin_, a.sin_ * b.cos_ + a.cos_ * b.sin_}; } - friend AngleCartesian operator-(const AngleCartesian &a, const AngleCartesian &b) + friend AngleCartesianBase operator-(const AngleCartesianBase &a, const AngleCartesianBase &b) { return {a.cos_ * b.cos_ + a.sin_ * b.sin_, a.sin_ * b.cos_ - a.cos_ * b.sin_}; } - friend AngleCartesian operator*(const AngleCartesian &a, const T &b) + friend AngleCartesianBase operator*(const AngleCartesianBase &a, const T &b) { if (b == T(2)) { return {a.cos_ * a.cos_ - a.sin_ * a.sin_, T(2) * a.sin_ * a.cos_}; @@ -293,24 +291,24 @@ template struct AngleCartesian { T(3) * a.sin_ - T(4) * (a.sin_ * a.sin_ * a.sin_)}; } BLI_assert_msg(0, - "Arbitrary angle product isn't supported with AngleCartesian for " - "performance reason. Use AngleRadian instead."); + "Arbitrary angle product isn't supported with AngleCartesianBase for " + "performance reason. Use AngleRadianBase instead."); return identity(); } - friend AngleCartesian operator*(const T &b, const AngleCartesian &a) + friend AngleCartesianBase operator*(const T &b, const AngleCartesianBase &a) { return a * b; } - friend AngleCartesian operator/(const AngleCartesian &a, const T &divisor) + friend AngleCartesianBase operator/(const AngleCartesianBase &a, const T &divisor) { if (divisor == T(2)) { /* Still costly but faster than using `atan()`. */ - AngleCartesian result = {math::sqrt((T(1) + a.cos_) / T(2)), - math::sqrt((T(1) - a.cos_) / T(2))}; + AngleCartesianBase result = {math::sqrt((T(1) + a.cos_) / T(2)), + math::sqrt((T(1) - a.cos_) / T(2))}; /* Recover sign only for sine. Cosine of half angle is given to be positive or 0 since the - * angle stored in #AngleCartesian is in the range [-pi..pi]. */ + * angle stored in #AngleCartesianBase is in the range [-pi..pi]. */ /* TODO(fclem): Could use copysign here. */ if (a.sin_ < T(0)) { result.sin_ = -result.sin_; @@ -318,58 +316,56 @@ template struct AngleCartesian { return result; } BLI_assert_msg(0, - "Arbitrary angle quotient isn't supported with AngleCartesian for " - "performance reason. Use AngleRadian instead."); + "Arbitrary angle quotient isn't supported with AngleCartesianBase for " + "performance reason. Use AngleRadianBase instead."); return identity(); } - friend AngleCartesian operator-(const AngleCartesian &a) + friend AngleCartesianBase operator-(const AngleCartesianBase &a) { return {a.cos_, -a.sin_}; } - AngleCartesian &operator+=(const AngleCartesian &b) + AngleCartesianBase &operator+=(const AngleCartesianBase &b) { *this = *this + b; return *this; } - AngleCartesian &operator*=(const T &b) + AngleCartesianBase &operator*=(const T &b) { *this = *this * b; return *this; } - AngleCartesian &operator-=(const AngleCartesian &b) + AngleCartesianBase &operator-=(const AngleCartesianBase &b) { *this = *this - b; return *this; } - AngleCartesian &operator/=(const T &b) + AngleCartesianBase &operator/=(const T &b) { *this = *this / b; return *this; } - friend bool operator==(const AngleCartesian &a, const AngleCartesian &b) + friend bool operator==(const AngleCartesianBase &a, const AngleCartesianBase &b) { return a.cos_ == b.cos_ && a.sin_ == b.sin_; } - friend bool operator!=(const AngleCartesian &a, const AngleCartesian &b) + friend bool operator!=(const AngleCartesianBase &a, const AngleCartesianBase &b) { return !(a == b); } - friend std::ostream &operator<<(std::ostream &stream, const AngleCartesian &rot) + friend std::ostream &operator<<(std::ostream &stream, const AngleCartesianBase &rot) { return stream << "AngleCartesian(x=" << rot.cos_ << ", y=" << rot.sin_ << ")"; } }; -} // namespace detail - /** * A `blender::math::AngleFraction` stores a radian angle as quotient. * - Storage : `2 * sizeof(int64_t)` @@ -385,7 +381,7 @@ template struct AngleCartesian { * not as cheap as a `AngleRadian`. Another nice property is that the `cos()` and `sin()` functions * give symmetric results around the circle. * - * NOTE: Prefer converting to `blender::math::AngleCartesian` if both `cos()` and `sin()` + * NOTE: Prefer converting to `blender::math::AngleCartesianBase` if both `cos()` and `sin()` * are needed. This will save some computation. * * Any operation becomes undefined if either the numerator or the denominator overflows. @@ -611,7 +607,7 @@ template struct AngleFraction { << ")"; } - operator detail::AngleCartesian() const + operator AngleCartesianBase() const { AngleFraction a = this->wrapped(); BLI_assert(abs(a.numerator_) <= a.denominator_); @@ -698,51 +694,51 @@ template struct AngleFraction { if (is_negative) { y = -y; } - return detail::AngleCartesian(x, y); + return AngleCartesianBase(x, y); } }; -template T cos(const detail::AngleRadian &a) +template T cos(const AngleRadianBase &a) { return cos(a.radian()); } -template T sin(const detail::AngleRadian &a) +template T sin(const AngleRadianBase &a) { return sin(a.radian()); } -template T tan(const detail::AngleRadian &a) +template T tan(const AngleRadianBase &a) { return tan(a.radian()); } -template T cos(const detail::AngleCartesian &a) +template T cos(const AngleCartesianBase &a) { return a.cos(); } -template T sin(const detail::AngleCartesian &a) +template T sin(const AngleCartesianBase &a) { return a.sin(); } -template T tan(const detail::AngleCartesian &a) +template T tan(const AngleCartesianBase &a) { return a.tan(); } template T cos(const AngleFraction &a) { - return cos(detail::AngleCartesian(a)); + return cos(AngleCartesianBase(a)); } template T sin(const AngleFraction &a) { - return sin(detail::AngleCartesian(a)); + return sin(AngleCartesianBase(a)); } template T tan(const AngleFraction &a) { - return tan(detail::AngleCartesian(a)); + return tan(AngleCartesianBase(a)); } -using AngleRadian = math::detail::AngleRadian; -using AngleCartesian = math::detail::AngleCartesian; +using AngleRadian = AngleRadianBase; +using AngleCartesian = AngleCartesianBase; } // namespace blender::math diff --git a/source/blender/blenlib/BLI_math_axis_angle.hh b/source/blender/blenlib/BLI_math_axis_angle.hh index 3f036ce9ee5..d37d9da5d81 100644 --- a/source/blender/blenlib/BLI_math_axis_angle.hh +++ b/source/blender/blenlib/BLI_math_axis_angle.hh @@ -13,14 +13,14 @@ #include "BLI_math_matrix.hh" #include "BLI_math_quaternion.hh" -namespace blender::math::detail { +namespace blender::math { /* -------------------------------------------------------------------- */ /** \name Constructors * \{ */ template -AxisAngle::AxisAngle(const VecBase &axis, const AngleT &angle) +AxisAngleBase::AxisAngleBase(const VecBase &axis, const AngleT &angle) { BLI_assert(is_unit_scale(axis)); axis_ = axis; @@ -28,14 +28,14 @@ AxisAngle::AxisAngle(const VecBase &axis, const AngleT &angle) } template -AxisAngle::AxisAngle(const AxisSigned axis, const AngleT &angle) +AxisAngleBase::AxisAngleBase(const AxisSigned axis, const AngleT &angle) { axis_ = to_vector>(axis); angle_ = angle; } template -AxisAngle::AxisAngle(const VecBase &from, const VecBase &to) +AxisAngleBase::AxisAngleBase(const VecBase &from, const VecBase &to) { BLI_assert(is_unit_scale(from)); BLI_assert(is_unit_scale(to)); @@ -61,16 +61,12 @@ AxisAngle::AxisAngle(const VecBase &from, const VecBase & /** \} */ -} // namespace blender::math::detail - -namespace blender::math { - /* -------------------------------------------------------------------- */ /** \name Conversion to Quaternions * \{ */ template -detail::Quaternion to_quaternion(const detail::AxisAngle &axis_angle) +QuaternionBase to_quaternion(const AxisAngleBase &axis_angle) { BLI_assert(math::is_unit_scale(axis_angle.axis())); @@ -79,7 +75,7 @@ detail::Quaternion to_quaternion(const detail::AxisAngle &axis_ang T hc = math::cos(half_angle); VecBase xyz = axis_angle.axis() * hs; - return detail::Quaternion(hc, xyz.x, xyz.y, xyz.z); + return QuaternionBase(hc, xyz.x, xyz.y, xyz.z); } /** \} */ @@ -89,25 +85,25 @@ detail::Quaternion to_quaternion(const detail::AxisAngle &axis_ang * \{ */ template -detail::Euler3 to_euler(const detail::AxisAngle &axis_angle, EulerOrder order) +Euler3Base to_euler(const AxisAngleBase &axis_angle, EulerOrder order) { /* Use quaternions as intermediate representation for now... */ return to_euler(to_quaternion(axis_angle), order); } template -detail::EulerXYZ to_euler(const detail::AxisAngle &axis_angle) +EulerXYZBase to_euler(const AxisAngleBase &axis_angle) { /* Check easy and exact conversions first. */ const VecBase axis = axis_angle.axis(); if (axis.x == T(1)) { - return detail::EulerXYZ(T(axis_angle.angle()), T(0), T(0)); + return EulerXYZBase(T(axis_angle.angle()), T(0), T(0)); } else if (axis.y == T(1)) { - return detail::EulerXYZ(T(0), T(axis_angle.angle()), T(0)); + return EulerXYZBase(T(0), T(axis_angle.angle()), T(0)); } else if (axis.z == T(1)) { - return detail::EulerXYZ(T(0), T(0), T(axis_angle.angle())); + return EulerXYZBase(T(0), T(0), T(axis_angle.angle())); } /* Use quaternions as intermediate representation for now... */ return to_euler(to_quaternion(axis_angle)); diff --git a/source/blender/blenlib/BLI_math_axis_angle_types.hh b/source/blender/blenlib/BLI_math_axis_angle_types.hh index 9257bf17372..68423ac48d1 100644 --- a/source/blender/blenlib/BLI_math_axis_angle_types.hh +++ b/source/blender/blenlib/BLI_math_axis_angle_types.hh @@ -14,8 +14,8 @@ * 2D operations and are thus faster. * * Interpolation isn't possible between two `blender::math::AxisAngle`; they must be - * converted to other rotation types for that. Converting to `blender::math::Quaternion` is the - * fastest and more correct option. + * converted to other rotation types for that. Converting to `blender::math::QuaternionBase` is + * the fastest and more correct option. */ #include "BLI_math_angle_types.hh" @@ -25,9 +25,7 @@ namespace blender::math { -namespace detail { - -template struct AxisAngle { +template struct AxisAngleBase { using vec3_type = VecBase; private: @@ -36,29 +34,29 @@ template struct AxisAngle { AngleT angle_ = AngleT::identity(); public: - AxisAngle() = default; + AxisAngleBase() = default; /** * Create a rotation from a basis axis and an angle. */ - AxisAngle(const AxisSigned axis, const AngleT &angle); + AxisAngleBase(const AxisSigned axis, const AngleT &angle); /** * Create a rotation from an axis and an angle. * \note `axis` have to be normalized. */ - AxisAngle(const vec3_type &axis, const AngleT &angle); + AxisAngleBase(const vec3_type &axis, const AngleT &angle); /** * Create a rotation from 2 normalized vectors. * \note `from` and `to` must be normalized. * \note Consider using `AxisAngleCartesian` for faster conversion to other rotation. */ - AxisAngle(const vec3_type &from, const vec3_type &to); + AxisAngleBase(const vec3_type &from, const vec3_type &to); /** Static functions. */ - static AxisAngle identity() + static AxisAngleBase identity() { return {}; } @@ -77,26 +75,24 @@ template struct AxisAngle { /** Operators. */ - friend bool operator==(const AxisAngle &a, const AxisAngle &b) + friend bool operator==(const AxisAngleBase &a, const AxisAngleBase &b) { return (a.axis() == b.axis()) && (a.angle() == b.angle()); } - friend bool operator!=(const AxisAngle &a, const AxisAngle &b) + friend bool operator!=(const AxisAngleBase &a, const AxisAngleBase &b) { return (a != b); } - friend std::ostream &operator<<(std::ostream &stream, const AxisAngle &rot) + friend std::ostream &operator<<(std::ostream &stream, const AxisAngleBase &rot) { return stream << "AxisAngle(axis=" << rot.axis() << ", angle=" << rot.angle() << ")"; } }; -}; // namespace detail - -using AxisAngle = math::detail::AxisAngle>; -using AxisAngleCartesian = math::detail::AxisAngle>; +using AxisAngle = AxisAngleBase>; +using AxisAngleCartesian = AxisAngleBase>; } // namespace blender::math diff --git a/source/blender/blenlib/BLI_math_euler.hh b/source/blender/blenlib/BLI_math_euler.hh index 77d2e9462fa..3a529023f37 100644 --- a/source/blender/blenlib/BLI_math_euler.hh +++ b/source/blender/blenlib/BLI_math_euler.hh @@ -14,43 +14,40 @@ #include "BLI_math_matrix.hh" #include "BLI_math_quaternion.hh" -namespace blender::math::detail { +namespace blender::math { /* -------------------------------------------------------------------- */ /** \name EulerXYZ * \{ */ -template EulerXYZ EulerXYZ::wrapped() const +template EulerXYZBase EulerXYZBase::wrapped() const { - EulerXYZ result(*this); - result.x() = AngleRadian(result.x()).wrapped().radian(); - result.y() = AngleRadian(result.y()).wrapped().radian(); - result.z() = AngleRadian(result.z()).wrapped().radian(); + EulerXYZBase result(*this); + result.x() = AngleRadianBase(result.x()).wrapped().radian(); + result.y() = AngleRadianBase(result.y()).wrapped().radian(); + result.z() = AngleRadianBase(result.z()).wrapped().radian(); return result; } -template EulerXYZ EulerXYZ::wrapped_around(const EulerXYZ &reference) const +template +EulerXYZBase EulerXYZBase::wrapped_around(const EulerXYZBase &reference) const { - EulerXYZ result(*this); - result.x() = AngleRadian(result.x()).wrapped_around(reference.x()).radian(); - result.y() = AngleRadian(result.y()).wrapped_around(reference.y()).radian(); - result.z() = AngleRadian(result.z()).wrapped_around(reference.z()).radian(); + EulerXYZBase result(*this); + result.x() = AngleRadianBase(result.x()).wrapped_around(reference.x()).radian(); + result.y() = AngleRadianBase(result.y()).wrapped_around(reference.y()).radian(); + result.z() = AngleRadianBase(result.z()).wrapped_around(reference.z()).radian(); return result; } /** \} */ -} // namespace blender::math::detail - -namespace blender::math { - /* -------------------------------------------------------------------- */ /** \name Conversion to Quaternions * \{ */ -template detail::Quaternion to_quaternion(const detail::EulerXYZ &eul) +template QuaternionBase to_quaternion(const EulerXYZBase &eul) { - using AngleT = typename detail::EulerXYZ::AngleT; + using AngleT = typename EulerXYZBase::AngleT; const AngleT h_angle_i = eul.x() / 2; const AngleT h_angle_j = eul.y() / 2; const AngleT h_angle_k = eul.z() / 2; @@ -65,7 +62,7 @@ template detail::Quaternion to_quaternion(const detail::EulerXYZ< const T sin_cos = sin_i * cos_k; const T sin_sin = sin_i * sin_k; - detail::Quaternion quat; + QuaternionBase quat; quat.w = cos_j * cos_cos + sin_j * sin_sin; quat.x = cos_j * sin_cos - sin_j * cos_sin; quat.y = cos_j * sin_sin + sin_j * cos_cos; @@ -73,14 +70,14 @@ template detail::Quaternion to_quaternion(const detail::EulerXYZ< return quat; } -template detail::Quaternion to_quaternion(const detail::Euler3 &eulO) +template QuaternionBase to_quaternion(const Euler3Base &eulO) { /* Swizzle to XYZ. */ - detail::EulerXYZ eul_xyz{eulO.ijk()}; + EulerXYZBase eul_xyz{eulO.ijk()}; /* Flip with parity. */ eul_xyz.y() = eulO.parity() ? -eul_xyz.y() : eul_xyz.y(); /* Quaternion conversion. */ - detail::Quaternion quat = to_quaternion(eul_xyz); + QuaternionBase quat = to_quaternion(eul_xyz); /* Swizzle back from XYZ. */ VecBase quat_xyz; quat_xyz[eulO.i_index()] = quat.x; @@ -97,14 +94,14 @@ template detail::Quaternion to_quaternion(const detail::Euler3 * \{ */ template -detail::AxisAngle to_axis_angle(const detail::EulerXYZ &euler) +AxisAngleBase to_axis_angle(const EulerXYZBase &euler) { /* Use quaternions as intermediate representation for now... */ return to_axis_angle(to_quaternion(euler)); } template -detail::AxisAngle to_axis_angle(const detail::Euler3 &euler) +AxisAngleBase to_axis_angle(const Euler3Base &euler) { /* Use quaternions as intermediate representation for now... */ return to_axis_angle(to_quaternion(euler)); diff --git a/source/blender/blenlib/BLI_math_euler_types.hh b/source/blender/blenlib/BLI_math_euler_types.hh index f073e1cb69c..a7c18e304e3 100644 --- a/source/blender/blenlib/BLI_math_euler_types.hh +++ b/source/blender/blenlib/BLI_math_euler_types.hh @@ -43,14 +43,12 @@ enum EulerOrder { std::ostream &operator<<(std::ostream &stream, EulerOrder order); -namespace detail { - /* -------------------------------------------------------------------- */ /** \name EulerBase * \{ */ template struct EulerBase { - using AngleT = AngleRadian; + using AngleT = AngleRadianBase; protected: /** @@ -130,24 +128,24 @@ template struct EulerBase { /** \name EulerXYZ * \{ */ -template struct EulerXYZ : public EulerBase { - using AngleT = AngleRadian; +template struct EulerXYZBase : public EulerBase { + using AngleT = AngleRadianBase; public: - EulerXYZ() = default; + EulerXYZBase() = default; /** * Create an euler x,y,z rotation from a triple of radian angle. */ - template EulerXYZ(const VecBase &vec) : EulerBase(vec){}; + template EulerXYZBase(const VecBase &vec) : EulerBase(vec){}; - EulerXYZ(const AngleT &x, const AngleT &y, const AngleT &z) : EulerBase(x, y, z){}; + EulerXYZBase(const AngleT &x, const AngleT &y, const AngleT &z) : EulerBase(x, y, z){}; /** * Create a rotation from an basis axis and an angle. * This sets a single component of the euler triple, the others are left to 0. */ - EulerXYZ(const Axis axis, const AngleT &angle) + EulerXYZBase(const Axis axis, const AngleT &angle) { *this = identity(); this->xyz_[axis] = angle; @@ -155,9 +153,11 @@ template struct EulerXYZ : public EulerBase { /** Static functions. */ - static EulerXYZ identity() + static EulerXYZBase identity() { - return {AngleRadian::identity(), AngleRadian::identity(), AngleRadian::identity()}; + return {AngleRadianBase::identity(), + AngleRadianBase::identity(), + AngleRadianBase::identity()}; } /** Methods. */ @@ -165,7 +165,7 @@ template struct EulerXYZ : public EulerBase { /** * Return this euler orientation but with angles wrapped inside [-pi..pi] range. */ - EulerXYZ wrapped() const; + EulerXYZBase wrapped() const; /** * Return this euler orientation but wrapped around \a reference. @@ -173,21 +173,21 @@ template struct EulerXYZ : public EulerBase { * This means the interpolation between the returned value and \a reference will always take the * shortest path. The angle between them will not be more than pi. */ - EulerXYZ wrapped_around(const EulerXYZ &reference) const; + EulerXYZBase wrapped_around(const EulerXYZBase &reference) const; /** Operators. */ - friend EulerXYZ operator-(const EulerXYZ &a) + friend EulerXYZBase operator-(const EulerXYZBase &a) { return {-a.xyz_.x, -a.xyz_.y, -a.xyz_.z}; } - friend bool operator==(const EulerXYZ &a, const EulerXYZ &b) + friend bool operator==(const EulerXYZBase &a, const EulerXYZBase &b) { return a.xyz_ == b.xyz_; } - friend std::ostream &operator<<(std::ostream &stream, const EulerXYZ &rot) + friend std::ostream &operator<<(std::ostream &stream, const EulerXYZBase &rot) { return stream << "EulerXYZ" << static_cast>(rot); } @@ -199,8 +199,8 @@ template struct EulerXYZ : public EulerBase { /** \name Euler3 * \{ */ -template struct Euler3 : public EulerBase { - using AngleT = AngleRadian; +template struct Euler3Base : public EulerBase { + using AngleT = AngleRadianBase; private: /** Axes order from applying the rotation. */ @@ -211,12 +211,12 @@ template struct Euler3 : public EulerBase { */ class Swizzle { private: - Euler3 &eul_; + Euler3Base &eul_; public: - explicit Swizzle(Euler3 &eul) : eul_(eul){}; + explicit Swizzle(Euler3Base &eul) : eul_(eul){}; - Euler3 &operator=(const VecBase &angles) + Euler3Base &operator=(const VecBase &angles) { eul_.xyz_.x = angles[eul_.i_index()]; eul_.xyz_.y = angles[eul_.j_index()]; @@ -236,7 +236,7 @@ template struct Euler3 : public EulerBase { }; public: - Euler3() = delete; + Euler3Base() = delete; /** * Create an euler rotation with \a order rotation ordering @@ -244,16 +244,16 @@ template struct Euler3 : public EulerBase { * eg: If \a order is `EulerOrder::ZXY` then `angles.z` will be the angle of the first rotation. */ template - Euler3(const VecBase &angles_xyz, EulerOrder order) + Euler3Base(const VecBase &angles_xyz, EulerOrder order) : EulerBase(angles_xyz), order_(order){}; - Euler3(const AngleT &x, const AngleT &y, const AngleT &z, EulerOrder order) + Euler3Base(const AngleT &x, const AngleT &y, const AngleT &z, EulerOrder order) : EulerBase(x, y, z), order_(order){}; /** * Create a rotation around a single euler axis and an angle. */ - Euler3(const Axis axis, AngleT angle, EulerOrder order) : EulerBase(), order_(order) + Euler3Base(const Axis axis, AngleT angle, EulerOrder order) : EulerBase(), order_(order) { this->xyz_[axis] = angle; } @@ -262,7 +262,7 @@ template struct Euler3 : public EulerBase { * Defines rotation order but not the rotation values. * Used for conversion from other rotation types. */ - Euler3(EulerOrder order) : order_(order){}; + Euler3Base(EulerOrder order) : order_(order){}; /** Methods. */ @@ -319,24 +319,25 @@ template struct Euler3 : public EulerBase { * This means the interpolation between the returned value and \a reference will always take the * shortest path. The angle between them will not be more than pi. */ - Euler3 wrapped_around(const Euler3 &reference) const + Euler3Base wrapped_around(const Euler3Base &reference) const { - return {VecBase(EulerXYZ(this->xyz_).wrapped_around(reference.xyz_)), order_}; + return {VecBase(EulerXYZBase(this->xyz_).wrapped_around(reference.xyz_)), + order_}; } /** Operators. */ - friend Euler3 operator-(const Euler3 &a) + friend Euler3Base operator-(const Euler3Base &a) { return {-a.xyz_, a.order_}; } - friend bool operator==(const Euler3 &a, const Euler3 &b) + friend bool operator==(const Euler3Base &a, const Euler3Base &b) { return a.xyz_ == b.xyz_ && a.order_ == b.order_; } - friend std::ostream &operator<<(std::ostream &stream, const Euler3 &rot) + friend std::ostream &operator<<(std::ostream &stream, const Euler3Base &rot) { return stream << "Euler3_" << rot.order_ << rot.xyz_; } @@ -432,10 +433,8 @@ template struct Euler3 : public EulerBase { /** \} */ -} // namespace detail - -using EulerXYZ = math::detail::EulerXYZ; -using Euler3 = math::detail::Euler3; +using EulerXYZ = EulerXYZBase; +using Euler3 = Euler3Base; } // namespace blender::math diff --git a/source/blender/blenlib/BLI_math_matrix.hh b/source/blender/blenlib/BLI_math_matrix.hh index 26922d0f65e..19ed2fe1726 100644 --- a/source/blender/blenlib/BLI_math_matrix.hh +++ b/source/blender/blenlib/BLI_math_matrix.hh @@ -256,14 +256,12 @@ template * Extract euler rotation from transform matrix. * \return the rotation with the smallest values from the potential candidates. */ +template [[nodiscard]] inline EulerXYZBase to_euler(const MatBase &mat); +template [[nodiscard]] inline EulerXYZBase to_euler(const MatBase &mat); template -[[nodiscard]] inline detail::EulerXYZ to_euler(const MatBase &mat); +[[nodiscard]] inline Euler3Base to_euler(const MatBase &mat, EulerOrder order); template -[[nodiscard]] inline detail::EulerXYZ to_euler(const MatBase &mat); -template -[[nodiscard]] inline detail::Euler3 to_euler(const MatBase &mat, EulerOrder order); -template -[[nodiscard]] inline detail::Euler3 to_euler(const MatBase &mat, EulerOrder order); +[[nodiscard]] inline Euler3Base to_euler(const MatBase &mat, EulerOrder order); /** * Extract euler rotation from transform matrix. @@ -273,25 +271,25 @@ template * \note this correspond to the C API "to_compatible" functions. */ template -[[nodiscard]] inline detail::EulerXYZ to_nearest_euler(const MatBase &mat, - const detail::EulerXYZ &reference); +[[nodiscard]] inline EulerXYZBase to_nearest_euler(const MatBase &mat, + const EulerXYZBase &reference); template -[[nodiscard]] inline detail::EulerXYZ to_nearest_euler(const MatBase &mat, - const detail::EulerXYZ &reference); +[[nodiscard]] inline EulerXYZBase to_nearest_euler(const MatBase &mat, + const EulerXYZBase &reference); template -[[nodiscard]] inline detail::Euler3 to_nearest_euler(const MatBase &mat, - const detail::Euler3 &reference); +[[nodiscard]] inline Euler3Base to_nearest_euler(const MatBase &mat, + const Euler3Base &reference); template -[[nodiscard]] inline detail::Euler3 to_nearest_euler(const MatBase &mat, - const detail::Euler3 &reference); +[[nodiscard]] inline Euler3Base to_nearest_euler(const MatBase &mat, + const Euler3Base &reference); /** * Extract quaternion rotation from transform matrix. */ template -[[nodiscard]] inline detail::Quaternion to_quaternion(const MatBase &mat); +[[nodiscard]] inline QuaternionBase to_quaternion(const MatBase &mat); template -[[nodiscard]] inline detail::Quaternion to_quaternion(const MatBase &mat); +[[nodiscard]] inline QuaternionBase to_quaternion(const MatBase &mat); /** * Extract quaternion rotation from transform matrix. @@ -516,25 +514,25 @@ inline bool is_zero(const MatBase &mat) namespace detail { template -[[nodiscard]] MatBase from_rotation(const AngleRadian &rotation); +[[nodiscard]] MatBase from_rotation(const AngleRadianBase &rotation); template -[[nodiscard]] MatBase from_rotation(const EulerXYZ &rotation); +[[nodiscard]] MatBase from_rotation(const EulerXYZBase &rotation); template -[[nodiscard]] MatBase from_rotation(const Euler3 &rotation); +[[nodiscard]] MatBase from_rotation(const Euler3Base &rotation); template -[[nodiscard]] MatBase from_rotation(const Quaternion &rotation); +[[nodiscard]] MatBase from_rotation(const QuaternionBase &rotation); template -[[nodiscard]] MatBase from_rotation(const DualQuaternion &rotation); +[[nodiscard]] MatBase from_rotation(const DualQuaternionBase &rotation); template [[nodiscard]] MatBase from_rotation(const CartesianBasis &rotation); template -[[nodiscard]] MatBase from_rotation(const AxisAngle &rotation); +[[nodiscard]] MatBase from_rotation(const AxisAngleBase &rotation); } // namespace detail @@ -591,7 +589,7 @@ template template [[nodiscard]] MatBase rotate(const MatBase &mat, - const detail::AxisAngle &rotation) + const AxisAngleBase &rotation) { using MatT = MatBase; using Vec3T = typename MatT::vec3_type; @@ -707,9 +705,7 @@ template namespace detail { template -void normalized_to_eul2(const MatBase &mat, - detail::EulerXYZ &eul1, - detail::EulerXYZ &eul2) +void normalized_to_eul2(const MatBase &mat, EulerXYZBase &eul1, EulerXYZBase &eul2) { BLI_assert(math::is_unit_scale(mat)); @@ -732,9 +728,7 @@ void normalized_to_eul2(const MatBase &mat, } } template -void normalized_to_eul2(const MatBase &mat, - detail::Euler3 &eul1, - detail::Euler3 &eul2) +void normalized_to_eul2(const MatBase &mat, Euler3Base &eul1, Euler3Base &eul2) { BLI_assert(math::is_unit_scale(mat)); const int i_index = eul1.i_index(); @@ -767,22 +761,22 @@ void normalized_to_eul2(const MatBase &mat, /* Using explicit template instantiations in order to reduce compilation time. */ extern template void normalized_to_eul2(const float3x3 &mat, - detail::Euler3 &eul1, - detail::Euler3 &eul2); + Euler3Base &eul1, + Euler3Base &eul2); extern template void normalized_to_eul2(const float3x3 &mat, - detail::EulerXYZ &eul1, - detail::EulerXYZ &eul2); + EulerXYZBase &eul1, + EulerXYZBase &eul2); extern template void normalized_to_eul2(const double3x3 &mat, - detail::EulerXYZ &eul1, - detail::EulerXYZ &eul2); + EulerXYZBase &eul1, + EulerXYZBase &eul2); -template detail::Quaternion normalized_to_quat_fast(const MatBase &mat) +template QuaternionBase normalized_to_quat_fast(const MatBase &mat) { BLI_assert(math::is_unit_scale(mat)); /* Caller must ensure matrices aren't negative for valid results, see: #24291, #94231. */ BLI_assert(!math::is_negative(mat)); - detail::Quaternion q; + QuaternionBase q; /* Method outlined by Mike Day, ref: https://math.stackexchange.com/a/3183435/220949 * with an additional `sqrtf(..)` for higher precision result. @@ -865,12 +859,11 @@ template detail::Quaternion normalized_to_quat_fast(const MatBase return q; } -template -detail::Quaternion normalized_to_quat_with_checks(const MatBase &mat) +template QuaternionBase normalized_to_quat_with_checks(const MatBase &mat) { const T det = math::determinant(mat); if (UNLIKELY(!isfinite(det))) { - return detail::Quaternion::identity(); + return QuaternionBase::identity(); } else if (UNLIKELY(det < T(0))) { return normalized_to_quat_fast(-mat); @@ -879,11 +872,11 @@ detail::Quaternion normalized_to_quat_with_checks(const MatBase &mat } /* Using explicit template instantiations in order to reduce compilation time. */ -extern template Quaternion normalized_to_quat_with_checks(const float3x3 &mat); -extern template Quaternion normalized_to_quat_with_checks(const double3x3 &mat); +extern template QuaternionBase normalized_to_quat_with_checks(const float3x3 &mat); +extern template QuaternionBase normalized_to_quat_with_checks(const double3x3 &mat); template -MatBase from_rotation(const EulerXYZ &rotation) +MatBase from_rotation(const EulerXYZBase &rotation) { using MatT = MatBase; using DoublePrecision = typename TypeTraits::DoublePrecision; @@ -914,14 +907,14 @@ MatBase from_rotation(const EulerXYZ &rotation) } template -MatBase from_rotation(const Euler3 &rotation) +MatBase from_rotation(const Euler3Base &rotation) { using MatT = MatBase; const int i_index = rotation.i_index(); const int j_index = rotation.j_index(); const int k_index = rotation.k_index(); #if 1 /* Reference. */ - EulerXYZ euler_xyz(rotation.ijk()); + EulerXYZBase euler_xyz(rotation.ijk()); const MatT mat = from_rotation(rotation.parity() ? -euler_xyz : euler_xyz); MatT result = MatT::identity(); result[i_index][i_index] = mat[0][0]; @@ -940,7 +933,7 @@ MatBase from_rotation(const Euler3 &rotation) } template -MatBase from_rotation(const Quaternion &rotation) +MatBase from_rotation(const QuaternionBase &rotation) { using MatT = MatBase; using DoublePrecision = typename TypeTraits::DoublePrecision; @@ -976,7 +969,7 @@ MatBase from_rotation(const Quaternion &rotation) /* Not technically speaking a simple rotation, but a whole transform. */ template -[[nodiscard]] MatBase from_rotation(const DualQuaternion &rotation) +[[nodiscard]] MatBase from_rotation(const DualQuaternionBase &rotation) { using MatT = MatBase; BLI_assert(is_normalized(rotation)); @@ -987,8 +980,8 @@ template * Trinity College Dublin, Czech Technical University in Prague */ /* Follow the paper notation. */ - const Quaternion &c0 = rotation.quat; - const Quaternion &ce = rotation.trans; + const QuaternionBase &c0 = rotation.quat; + const QuaternionBase &ce = rotation.trans; const T &w0 = c0.w, &x0 = c0.x, &y0 = c0.y, &z0 = c0.z; const T &we = ce.w, &xe = ce.x, &ye = ce.y, &ze = ce.z; /* Rotation. */ @@ -1016,7 +1009,7 @@ MatBase from_rotation(const CartesianBasis &rotation) } template -MatBase from_rotation(const AxisAngle &rotation) +MatBase from_rotation(const AxisAngleBase &rotation) { using MatT = MatBase; using Vec3T = typename MatT::vec3_type; @@ -1045,7 +1038,7 @@ MatBase from_rotation(const AxisAngle &rotation) } template -MatBase from_rotation(const AngleRadian &rotation) +MatBase from_rotation(const AngleRadianBase &rotation) { using MatT = MatBase; const T cos_i = cos(rotation); @@ -1061,34 +1054,34 @@ MatBase from_rotation(const AngleRadian &rotation) } /* Using explicit template instantiations in order to reduce compilation time. */ -extern template MatBase from_rotation(const AngleRadian &rotation); -extern template MatBase from_rotation(const AngleRadian &rotation); -extern template MatBase from_rotation(const EulerXYZ &rotation); -extern template MatBase from_rotation(const EulerXYZ &rotation); -extern template MatBase from_rotation(const Euler3 &rotation); -extern template MatBase from_rotation(const Euler3 &rotation); -extern template MatBase from_rotation(const Quaternion &rotation); -extern template MatBase from_rotation(const Quaternion &rotation); -extern template MatBase from_rotation(const math::AxisAngle &rotation); -extern template MatBase from_rotation(const math::AxisAngle &rotation); -extern template MatBase from_rotation(const math::AxisAngleCartesian &rotation); -extern template MatBase from_rotation(const math::AxisAngleCartesian &rotation); +extern template MatBase from_rotation(const AngleRadian &rotation); +extern template MatBase from_rotation(const AngleRadian &rotation); +extern template MatBase from_rotation(const EulerXYZ &rotation); +extern template MatBase from_rotation(const EulerXYZ &rotation); +extern template MatBase from_rotation(const Euler3 &rotation); +extern template MatBase from_rotation(const Euler3 &rotation); +extern template MatBase from_rotation(const Quaternion &rotation); +extern template MatBase from_rotation(const Quaternion &rotation); +extern template MatBase from_rotation(const AxisAngle &rotation); +extern template MatBase from_rotation(const AxisAngle &rotation); +extern template MatBase from_rotation(const AxisAngleCartesian &rotation); +extern template MatBase from_rotation(const AxisAngleCartesian &rotation); } // namespace detail template -[[nodiscard]] inline detail::Euler3 to_euler(const MatBase &mat, EulerOrder order) +[[nodiscard]] inline Euler3Base to_euler(const MatBase &mat, EulerOrder order) { - detail::Euler3 eul1(order), eul2(order); + Euler3Base eul1(order), eul2(order); detail::normalized_to_eul2(mat, eul1, eul2); /* Return best, which is just the one with lowest values in it. */ return (length_manhattan(VecBase(eul1)) > length_manhattan(VecBase(eul2))) ? eul2 : eul1; } -template [[nodiscard]] inline detail::EulerXYZ to_euler(const MatBase &mat) +template [[nodiscard]] inline EulerXYZBase to_euler(const MatBase &mat) { - detail::EulerXYZ eul1, eul2; + EulerXYZBase eul1, eul2; detail::normalized_to_eul2(mat, eul1, eul2); /* Return best, which is just the one with lowest values in it. */ return (length_manhattan(VecBase(eul1)) > length_manhattan(VecBase(eul2))) ? eul2 : @@ -1096,23 +1089,23 @@ template [[nodiscard]] inline detail::EulerXYZ to_euler(const Mat } template -[[nodiscard]] inline detail::Euler3 to_euler(const MatBase &mat, EulerOrder order) +[[nodiscard]] inline Euler3Base to_euler(const MatBase &mat, EulerOrder order) { /* TODO(fclem): Avoid the copy with 3x3 ref. */ return to_euler(MatBase(mat), order); } -template [[nodiscard]] inline detail::EulerXYZ to_euler(const MatBase &mat) +template [[nodiscard]] inline EulerXYZBase to_euler(const MatBase &mat) { /* TODO(fclem): Avoid the copy with 3x3 ref. */ return to_euler(MatBase(mat)); } template -[[nodiscard]] inline detail::Euler3 to_nearest_euler(const MatBase &mat, - const detail::Euler3 &reference) +[[nodiscard]] inline Euler3Base to_nearest_euler(const MatBase &mat, + const Euler3Base &reference) { - detail::Euler3 eul1(reference.order()), eul2(reference.order()); + Euler3Base eul1(reference.order()), eul2(reference.order()); detail::normalized_to_eul2(mat, eul1, eul2); eul1 = eul1.wrapped_around(reference); eul2 = eul2.wrapped_around(reference); @@ -1124,10 +1117,10 @@ template } template -[[nodiscard]] inline detail::EulerXYZ to_nearest_euler(const MatBase &mat, - const detail::EulerXYZ &reference) +[[nodiscard]] inline EulerXYZBase to_nearest_euler(const MatBase &mat, + const EulerXYZBase &reference) { - detail::EulerXYZ eul1, eul2; + EulerXYZBase eul1, eul2; detail::normalized_to_eul2(mat, eul1, eul2); eul1 = eul1.wrapped_around(reference); eul2 = eul2.wrapped_around(reference); @@ -1139,29 +1132,29 @@ template } template -[[nodiscard]] inline detail::Euler3 to_nearest_euler(const MatBase &mat, - const detail::Euler3 &reference) +[[nodiscard]] inline Euler3Base to_nearest_euler(const MatBase &mat, + const Euler3Base &reference) { /* TODO(fclem): Avoid the copy with 3x3 ref. */ return to_euler(MatBase(mat), reference); } template -[[nodiscard]] inline detail::EulerXYZ to_nearest_euler(const MatBase &mat, - const detail::EulerXYZ &reference) +[[nodiscard]] inline EulerXYZBase to_nearest_euler(const MatBase &mat, + const EulerXYZBase &reference) { /* TODO(fclem): Avoid the copy with 3x3 ref. */ return to_euler(MatBase(mat), reference); } template -[[nodiscard]] inline detail::Quaternion to_quaternion(const MatBase &mat) +[[nodiscard]] inline QuaternionBase to_quaternion(const MatBase &mat) { return detail::normalized_to_quat_with_checks(mat); } template -[[nodiscard]] inline detail::Quaternion to_quaternion(const MatBase &mat) +[[nodiscard]] inline QuaternionBase to_quaternion(const MatBase &mat) { /* TODO(fclem): Avoid the copy with 3x3 ref. */ return to_quaternion(MatBase(mat)); @@ -1195,19 +1188,19 @@ template namespace detail { template -inline void to_rotation(const MatBase &mat, detail::Quaternion &r_rotation) +inline void to_rotation(const MatBase &mat, QuaternionBase &r_rotation) { r_rotation = to_quaternion(mat); } template -inline void to_rotation(const MatBase &mat, detail::EulerXYZ &r_rotation) +inline void to_rotation(const MatBase &mat, EulerXYZBase &r_rotation) { r_rotation = to_euler(mat); } template -inline void to_rotation(const MatBase &mat, detail::Euler3 &r_rotation) +inline void to_rotation(const MatBase &mat, Euler3Base &r_rotation) { r_rotation = to_euler(mat, r_rotation.order()); } diff --git a/source/blender/blenlib/BLI_math_quaternion.hh b/source/blender/blenlib/BLI_math_quaternion.hh index 217819d5a6d..02383d03d7c 100644 --- a/source/blender/blenlib/BLI_math_quaternion.hh +++ b/source/blender/blenlib/BLI_math_quaternion.hh @@ -24,37 +24,34 @@ namespace blender::math { * Equivalent to component wise multiplication followed by summation of the result. */ template -[[nodiscard]] inline T dot(const detail::Quaternion &a, const detail::Quaternion &b); +[[nodiscard]] inline T dot(const QuaternionBase &a, const QuaternionBase &b); /** * Raise a unit #Quaternion \a q to the real \a y exponent. * \note This only works on unit quaternions and y != 0. * \note This is not a per component power. */ -template -[[nodiscard]] detail::Quaternion pow(const detail::Quaternion &q, const T &y); +template [[nodiscard]] QuaternionBase pow(const QuaternionBase &q, const T &y); /** * Return the conjugate of the given quaternion. * If the quaternion \a q represent the rotation from A to B, * then the conjugate of \a q represents the rotation from B to A. */ -template -[[nodiscard]] inline detail::Quaternion conjugate(const detail::Quaternion &a); +template [[nodiscard]] inline QuaternionBase conjugate(const QuaternionBase &a); /** * Negate the quaternion if real component (w) is negative. */ template -[[nodiscard]] inline detail::Quaternion canonicalize(const detail::Quaternion &q); +[[nodiscard]] inline QuaternionBase canonicalize(const QuaternionBase &q); /** * Return invert of \a q or identity if \a q is ill-formed. * The invert allows quaternion division. * \note The inverse of \a q isn't the opposite rotation. This would be the conjugate. */ -template -[[nodiscard]] inline detail::Quaternion invert(const detail::Quaternion &q); +template [[nodiscard]] inline QuaternionBase invert(const QuaternionBase &q); /** * Return invert of \a q assuming it is a unit quaternion. @@ -62,26 +59,25 @@ template * but this function shows the intent better, and asserts if \a q ever becomes non-unit-length. */ template -[[nodiscard]] inline detail::Quaternion invert_normalized(const detail::Quaternion &q); +[[nodiscard]] inline QuaternionBase invert_normalized(const QuaternionBase &q); /** * Return a unit quaternion representing the same rotation as \a q or * the identity quaternion if \a q is ill-formed. */ +template [[nodiscard]] inline QuaternionBase normalize(const QuaternionBase &q); template -[[nodiscard]] inline detail::Quaternion normalize(const detail::Quaternion &q); -template -[[nodiscard]] inline detail::Quaternion normalize_and_get_length(const detail::Quaternion &q, - T &out_length); +[[nodiscard]] inline QuaternionBase normalize_and_get_length(const QuaternionBase &q, + T &out_length); /** * Use spherical interpolation between two quaternions. * Always interpolate along the shortest angle. */ template -[[nodiscard]] inline detail::Quaternion interpolate(const detail::Quaternion &a, - const detail::Quaternion &b, - T t); +[[nodiscard]] inline QuaternionBase interpolate(const QuaternionBase &a, + const QuaternionBase &b, + T t); /** \} */ @@ -93,7 +89,7 @@ template * Transform \a v by rotation using the quaternion \a q . */ template -[[nodiscard]] inline VecBase transform_point(const detail::Quaternion &q, +[[nodiscard]] inline VecBase transform_point(const QuaternionBase &q, const VecBase &v); /** \} */ @@ -105,7 +101,7 @@ template /** * Returns true if all components are exactly equal to 0. */ -template [[nodiscard]] inline bool is_zero(const detail::Quaternion &q) +template [[nodiscard]] inline bool is_zero(const QuaternionBase &q) { return q.w == T(0) && q.x == T(0) && q.y == T(0) && q.z == T(0); } @@ -114,22 +110,22 @@ template [[nodiscard]] inline bool is_zero(const detail::Quaternion< * Returns true if the quaternions are equal within the given epsilon. Return false otherwise. */ template -[[nodiscard]] inline bool is_equal(const detail::Quaternion &a, - const detail::Quaternion &b, +[[nodiscard]] inline bool is_equal(const QuaternionBase &a, + const QuaternionBase &b, const T epsilon = T(0)) { return math::abs(a.w - b.w) <= epsilon && math::abs(a.y - b.y) <= epsilon && math::abs(a.x - b.x) <= epsilon && math::abs(a.z - b.z) <= epsilon; } -template [[nodiscard]] inline bool is_unit_scale(const detail::Quaternion &q) +template [[nodiscard]] inline bool is_unit_scale(const QuaternionBase &q) { /* Checks are flipped so NAN doesn't assert because we're making sure the value was * normalized and in the case we don't want NAN to be raising asserts since there * is nothing to be done in that case. */ const T test_unit = q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w; - return (!(math::abs(test_unit - T(1)) >= AssertUnitEpsilon>::value) || - !(math::abs(test_unit) >= AssertUnitEpsilon>::value)); + return (!(math::abs(test_unit - T(1)) >= AssertUnitEpsilon>::value) || + !(math::abs(test_unit) >= AssertUnitEpsilon>::value)); } /** \} */ @@ -138,73 +134,69 @@ template [[nodiscard]] inline bool is_unit_scale(const detail::Quate /** \name Quaternion * \{ */ -namespace detail { - /* -------------- Conversions -------------- */ -template AngleRadian Quaternion::twist_angle(const Axis axis) const +template AngleRadianBase QuaternionBase::twist_angle(const Axis axis) const { /* The calculation requires a canonical quaternion. */ const VecBase input_vec(canonicalize(*this)); - return T(2) * AngleRadian(input_vec[0], input_vec.yzw()[axis.as_int()]); + return T(2) * AngleRadianBase(input_vec[0], input_vec.yzw()[axis.as_int()]); } -template Quaternion Quaternion::swing(const Axis axis) const +template QuaternionBase QuaternionBase::swing(const Axis axis) const { /* The calculation requires a canonical quaternion. */ - const Quaternion input = canonicalize(*this); + const QuaternionBase input = canonicalize(*this); /* Compute swing by multiplying the original quaternion by inverted twist. */ - Quaternion swing = input * invert_normalized(input.twist(axis)); + QuaternionBase swing = input * invert_normalized(input.twist(axis)); BLI_assert(math::abs(VecBase(swing)[axis.as_int() + 1]) < BLI_ASSERT_UNIT_EPSILON); return swing; } -template Quaternion Quaternion::twist(const Axis axis) const +template QuaternionBase QuaternionBase::twist(const Axis axis) const { /* The calculation requires a canonical quaternion. */ const VecBase input_vec(canonicalize(*this)); - AngleCartesian half_angle = AngleCartesian::from_point(input_vec[0], - input_vec.yzw()[axis.as_int()]); + AngleCartesianBase half_angle = AngleCartesianBase::from_point( + input_vec[0], input_vec.yzw()[axis.as_int()]); VecBase twist(half_angle.cos(), T(0), T(0), T(0)); twist[axis.as_int() + 1] = half_angle.sin(); - return Quaternion(twist); + return QuaternionBase(twist); } /* -------------- Methods -------------- */ -template Quaternion Quaternion::wrapped_around(const Quaternion &reference) const +template +QuaternionBase QuaternionBase::wrapped_around(const QuaternionBase &reference) const { BLI_assert(is_unit_scale(*this)); - const Quaternion &input = *this; + const QuaternionBase &input = *this; T len; - Quaternion reference_normalized = normalize_and_get_length(reference, len); + QuaternionBase reference_normalized = normalize_and_get_length(reference, len); /* Skips degenerate case. */ if (len < 1e-4f) { return input; } - Quaternion result = reference * invert_normalized(reference_normalized) * input; + QuaternionBase result = reference * invert_normalized(reference_normalized) * input; return (distance_squared(VecBase(-result), VecBase(reference)) < distance_squared(VecBase(result), VecBase(reference))) ? -result : result; } -} // namespace detail - /* -------------- Functions -------------- */ template -[[nodiscard]] inline T dot(const detail::Quaternion &a, const detail::Quaternion &b) +[[nodiscard]] inline T dot(const QuaternionBase &a, const QuaternionBase &b) { return a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z; } -template -[[nodiscard]] detail::Quaternion pow(const detail::Quaternion &q, const T &y) +template [[nodiscard]] QuaternionBase pow(const QuaternionBase &q, const T &y) { BLI_assert(is_unit_scale(q)); /* Reference material: @@ -223,45 +215,42 @@ template return {math::cos(half_angle), math::sin(half_angle) * normalize(q.imaginary_part())}; } -template -[[nodiscard]] inline detail::Quaternion conjugate(const detail::Quaternion &a) +template [[nodiscard]] inline QuaternionBase conjugate(const QuaternionBase &a) { return {a.w, -a.x, -a.y, -a.z}; } template -[[nodiscard]] inline detail::Quaternion canonicalize(const detail::Quaternion &q) +[[nodiscard]] inline QuaternionBase canonicalize(const QuaternionBase &q) { return (q.w < T(0)) ? -q : q; } -template -[[nodiscard]] inline detail::Quaternion invert(const detail::Quaternion &q) +template [[nodiscard]] inline QuaternionBase invert(const QuaternionBase &q) { const T length_squared = dot(q, q); if (length_squared == T(0)) { - return detail::Quaternion::identity(); + return QuaternionBase::identity(); } return conjugate(q) * (T(1) / length_squared); } template -[[nodiscard]] inline detail::Quaternion invert_normalized(const detail::Quaternion &q) +[[nodiscard]] inline QuaternionBase invert_normalized(const QuaternionBase &q) { BLI_assert(is_unit_scale(q)); return conjugate(q); } template -[[nodiscard]] inline detail::Quaternion normalize_and_get_length(const detail::Quaternion &q, - T &out_length) +[[nodiscard]] inline QuaternionBase normalize_and_get_length(const QuaternionBase &q, + T &out_length) { out_length = math::sqrt(dot(q, q)); - return (out_length != T(0)) ? (q * (T(1) / out_length)) : detail::Quaternion::identity(); + return (out_length != T(0)) ? (q * (T(1) / out_length)) : QuaternionBase::identity(); } -template -[[nodiscard]] inline detail::Quaternion normalize(const detail::Quaternion &q) +template [[nodiscard]] inline QuaternionBase normalize(const QuaternionBase &q) { T len; return normalize_and_get_length(q, len); @@ -306,28 +295,28 @@ template } template -[[nodiscard]] inline detail::Quaternion interpolate(const detail::Quaternion &a, - const detail::Quaternion &b, - T t) +[[nodiscard]] inline QuaternionBase interpolate(const QuaternionBase &a, + const QuaternionBase &b, + T t) { using Vec4T = VecBase; BLI_assert(is_unit_scale(a)); BLI_assert(is_unit_scale(b)); VecBase w = interpolate_dot_slerp(t, dot(a, b)); - return detail::Quaternion(w[0] * Vec4T(a) + w[1] * Vec4T(b)); + return QuaternionBase(w[0] * Vec4T(a) + w[1] * Vec4T(b)); } template -[[nodiscard]] inline VecBase transform_point(const detail::Quaternion &q, +[[nodiscard]] inline VecBase transform_point(const QuaternionBase &q, const VecBase &v) { #if 0 /* Reference. */ - detail::Quaternion V(T(0), UNPACK3(v)); - detail::Quaternion R = q * V * conjugate(q); + QuaternionBase V(T(0), UNPACK3(v)); + QuaternionBase R = q * V * conjugate(q); return {R.x, R.y, R.z}; #else /* `S = q * V` */ - detail::Quaternion S; + QuaternionBase S; S.w = /* q.w * 0.0 */ -q.x * v.x - q.y * v.y - q.z * v.z; S.x = q.w * v.x /* + q.x * 0.0 */ + q.y * v.z - q.z * v.y; S.y = q.w * v.y /* + q.y * 0.0 */ + q.z * v.x - q.x * v.z; @@ -348,21 +337,20 @@ template /** \name Dual-Quaternion * \{ */ -namespace detail { - /* -------------- Constructors -------------- */ template -DualQuaternion::DualQuaternion(const Quaternion &non_dual, const Quaternion &dual) +DualQuaternionBase::DualQuaternionBase(const QuaternionBase &non_dual, + const QuaternionBase &dual) : quat(non_dual), trans(dual), scale_weight(0), quat_weight(1) { BLI_assert(is_unit_scale(non_dual)); } template -DualQuaternion::DualQuaternion(const Quaternion &non_dual, - const Quaternion &dual, - const MatBase &scale_mat) +DualQuaternionBase::DualQuaternionBase(const QuaternionBase &non_dual, + const QuaternionBase &dual, + const MatBase &scale_mat) : quat(non_dual), trans(dual), scale(scale_mat), scale_weight(1), quat_weight(1) { BLI_assert(is_unit_scale(non_dual)); @@ -370,9 +358,10 @@ DualQuaternion::DualQuaternion(const Quaternion &non_dual, /* -------------- Operators -------------- */ -template DualQuaternion &DualQuaternion::operator+=(const DualQuaternion &b) +template +DualQuaternionBase &DualQuaternionBase::operator+=(const DualQuaternionBase &b) { - DualQuaternion &a = *this; + DualQuaternionBase &a = *this; /* Sum rotation and translation. */ /* Make sure we interpolate quaternions in the right direction. */ @@ -416,10 +405,10 @@ template DualQuaternion &DualQuaternion::operator+=(const Dual return *this; } -template DualQuaternion &DualQuaternion::operator*=(const T &t) +template DualQuaternionBase &DualQuaternionBase::operator*=(const T &t) { BLI_assert(t >= 0); - DualQuaternion &q = *this; + DualQuaternionBase &q = *this; q.quat.w *= t; q.quat.x *= t; @@ -440,8 +429,6 @@ template DualQuaternion &DualQuaternion::operator*=(const T &t return *this; } -} // namespace detail - /* -------------- Functions -------------- */ /** @@ -452,18 +439,18 @@ template DualQuaternion &DualQuaternion::operator*=(const T &t * \note Returns identity #DualQuaternion if degenerate. */ template -[[nodiscard]] detail::DualQuaternion normalize(const detail::DualQuaternion &dual_quat) +[[nodiscard]] DualQuaternionBase normalize(const DualQuaternionBase &dual_quat) { const T norm_weighted = math::sqrt(dot(dual_quat.quat, dual_quat.quat)); /* NOTE(fclem): Should this be an epsilon? */ if (norm_weighted == T(0)) { /* The dual-quaternion was zero initialized or is degenerate. Return identity. */ - return detail::DualQuaternion::identity(); + return DualQuaternionBase::identity(); } const T inv_norm_weighted = T(1) / norm_weighted; - detail::DualQuaternion dq = dual_quat; + DualQuaternionBase dq = dual_quat; dq.quat = dq.quat * inv_norm_weighted; dq.trans = dq.trans * inv_norm_weighted; @@ -493,7 +480,7 @@ template * first. Optionally outputs crazy space matrix. */ template -[[nodiscard]] VecBase transform_point(const detail::DualQuaternion &dq, +[[nodiscard]] VecBase transform_point(const DualQuaternionBase &dq, const VecBase &point, MatBase *r_crazy_space_mat = nullptr) { @@ -555,8 +542,8 @@ template * This allows volume preserving deformation for skinning. */ template -[[nodiscard]] detail::DualQuaternion to_dual_quaternion(const MatBase &mat, - const MatBase &basemat) +[[nodiscard]] DualQuaternionBase to_dual_quaternion(const MatBase &mat, + const MatBase &basemat) { /** * Conversion routines between (regular quaternion, translation) and dual quaternion. @@ -586,7 +573,7 @@ template const Mat4T baseinv = invert(basemat); /* Extra orthogonalize, to avoid flipping with stretched bones. */ - detail::Quaternion basequat = to_quaternion(normalize(orthogonalize(baseRS, Axis::Y))); + QuaternionBase basequat = to_quaternion(normalize(orthogonalize(baseRS, Axis::Y))); Mat4T baseR = from_rotation(basequat); baseR.location() = baseRS.location(); @@ -603,21 +590,21 @@ template } /* Non-dual part. */ - const detail::Quaternion q = to_quaternion(normalize(R)); + const QuaternionBase q = to_quaternion(normalize(R)); /* Dual part. */ const Vec3T &t = R.location().xyz(); - detail::Quaternion d; + QuaternionBase d; d.w = T(-0.5) * (+t.x * q.x + t.y * q.y + t.z * q.z); d.x = T(+0.5) * (+t.x * q.w + t.y * q.z - t.z * q.y); d.y = T(+0.5) * (-t.x * q.z + t.y * q.w + t.z * q.x); d.z = T(+0.5) * (+t.x * q.y - t.y * q.x + t.z * q.w); if (has_scale) { - return detail::DualQuaternion(q, d, scale); + return DualQuaternionBase(q, d, scale); } - return detail::DualQuaternion(q, d); + return DualQuaternionBase(q, d); } /** \} */ @@ -631,7 +618,7 @@ namespace blender::math { * \{ */ template -detail::AxisAngle to_axis_angle(const detail::Quaternion &quat) +AxisAngleBase to_axis_angle(const QuaternionBase &quat) { BLI_assert(is_unit_scale(quat)); @@ -649,7 +636,7 @@ detail::AxisAngle to_axis_angle(const detail::Quaternion &quat) /* Leverage AngleT implementation of double angle. */ AngleT angle = AngleT(cos_half_angle, sin_half_angle) * 2; - return detail::AxisAngle(axis, angle); + return AxisAngleBase(axis, angle); } /** \} */ @@ -658,7 +645,7 @@ detail::AxisAngle to_axis_angle(const detail::Quaternion &quat) /** \name Conversion to Euler * \{ */ -template detail::EulerXYZ to_euler(const detail::Quaternion &quat) +template EulerXYZBase to_euler(const QuaternionBase &quat) { using Mat3T = MatBase; BLI_assert(is_unit_scale(quat)); @@ -666,8 +653,7 @@ template detail::EulerXYZ to_euler(const detail::Quaternion &q return to_euler(unit_mat); } -template -detail::Euler3 to_euler(const detail::Quaternion &quat, EulerOrder order) +template Euler3Base to_euler(const QuaternionBase &quat, EulerOrder order) { using Mat3T = MatBase; BLI_assert(is_unit_scale(quat)); @@ -683,24 +669,23 @@ detail::Euler3 to_euler(const detail::Quaternion &quat, EulerOrder order) /* Prototype needed to avoid interdependencies of headers. */ template -detail::Quaternion to_quaternion(const detail::AxisAngle &axis_angle); +QuaternionBase to_quaternion(const AxisAngleBase &axis_angle); -template -detail::Quaternion detail::Quaternion::expmap(const VecBase &expmap) +template QuaternionBase QuaternionBase::expmap(const VecBase &expmap) { - using AxisAngleT = detail::AxisAngle>; + using AxisAngleT = AxisAngleBase>; /* Obtain axis/angle representation. */ T angle; const VecBase axis = normalize_and_get_length(expmap, angle); if (LIKELY(angle != T(0))) { return to_quaternion(AxisAngleT(axis, angle_wrap_rad(angle))); } - return detail::Quaternion::identity(); + return QuaternionBase::identity(); } -template VecBase detail::Quaternion::expmap() const +template VecBase QuaternionBase::expmap() const { - using AxisAngleT = detail::AxisAngle>; + using AxisAngleT = AxisAngleBase>; BLI_assert(is_unit_scale(*this)); const AxisAngleT axis_angle = to_axis_angle(*this); return axis_angle.axis() * axis_angle.angle().radian(); diff --git a/source/blender/blenlib/BLI_math_quaternion_types.hh b/source/blender/blenlib/BLI_math_quaternion_types.hh index ea1817df0b8..d06d7cf8e11 100644 --- a/source/blender/blenlib/BLI_math_quaternion_types.hh +++ b/source/blender/blenlib/BLI_math_quaternion_types.hh @@ -18,48 +18,46 @@ namespace blender::math { /** \name Quaternion * \{ */ -namespace detail { - /** - * A `blender::math::Quaternion` represents either an orientation or a rotation. + * A `blender::math::QuaternionBase` represents either an orientation or a rotation. * * Mainly used for rigging and armature deformations as they have nice mathematical properties - * (eg: smooth shortest path interpolation). A `blender::math::Quaternion` is cheaper to combine - * than `MatBase`. However, transforming points is slower. Consider converting to a - * rotation matrix if you are rotating many points. + * (eg: smooth shortest path interpolation). A `blender::math::QuaternionBase` is cheaper to + * combine than `MatBase`. However, transforming points is slower. Consider converting to + * a rotation matrix if you are rotating many points. * * See this for more information: * https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation#Performance_comparisons */ -template struct Quaternion { +template struct QuaternionBase { T w, x, y, z; - Quaternion() = default; + QuaternionBase() = default; - Quaternion(const T &new_w, const T &new_x, const T &new_y, const T &new_z) + QuaternionBase(const T &new_w, const T &new_x, const T &new_y, const T &new_z) : w(new_w), x(new_x), y(new_y), z(new_z){}; /** * Creates a quaternion from an vector without reordering the components. * \note Component order must follow the scalar constructor (w, x, y, z). */ - explicit Quaternion(const VecBase &vec) : Quaternion(UNPACK4(vec)){}; + explicit QuaternionBase(const VecBase &vec) : QuaternionBase(UNPACK4(vec)){}; /** * Creates a quaternion from real (w) and imaginary parts (x, y, z). */ - Quaternion(const T &real, const VecBase &imaginary) - : Quaternion(real, UNPACK3(imaginary)){}; + QuaternionBase(const T &real, const VecBase &imaginary) + : QuaternionBase(real, UNPACK3(imaginary)){}; /** Static functions. */ - static Quaternion identity() + static QuaternionBase identity() { return {1, 0, 0, 0}; } /** This is just for convenience. Does not represent a rotation as it is degenerate. */ - static Quaternion zero() + static QuaternionBase zero() { return {0, 0, 0, 0}; } @@ -68,7 +66,7 @@ template struct Quaternion { * Create a quaternion from an exponential map representation. * An exponential map is basically the rotation axis multiplied by the rotation angle. */ - static Quaternion expmap(const VecBase &expmap); + static QuaternionBase expmap(const VecBase &expmap); /** Conversions. */ @@ -87,20 +85,20 @@ template struct Quaternion { * Returns the full twist angle for a given \a axis direction. * The twist is the isolated rotation in the plane whose \a axis is normal to. */ - AngleRadian twist_angle(const Axis axis) const; + AngleRadianBase twist_angle(const Axis axis) const; /** * Returns the twist part of this quaternion for the \a axis direction. * The twist is the isolated rotation in the plane whose \a axis is normal to. */ - Quaternion twist(const Axis axis) const; + QuaternionBase twist(const Axis axis) const; /** * Returns the swing part of this quaternion for the basis \a axis direction. * The swing is the original quaternion minus the twist around \a axis. * So we have the following identity : `q = q.swing(axis) * q.twist(axis)` */ - Quaternion swing(const Axis axis) const; + QuaternionBase swing(const Axis axis) const; /** * Returns the imaginary part of this quaternion (x, y, z). @@ -125,11 +123,11 @@ template struct Quaternion { * \note This quaternion is expected to be a unit quaternion. * \note Works even if \a reference is *not* a unit quaternion. */ - Quaternion wrapped_around(const Quaternion &reference) const; + QuaternionBase wrapped_around(const QuaternionBase &reference) const; /** Operators. */ - friend Quaternion operator*(const Quaternion &a, const Quaternion &b) + friend QuaternionBase operator*(const QuaternionBase &a, const QuaternionBase &b) { return {a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z, a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y, @@ -137,58 +135,54 @@ template struct Quaternion { a.w * b.z + a.z * b.w + a.x * b.y - a.y * b.x}; } - Quaternion &operator*=(const Quaternion &b) + QuaternionBase &operator*=(const QuaternionBase &b) { *this = *this * b; return *this; } /* Scalar product. */ - friend Quaternion operator*(const Quaternion &a, const T &b) + friend QuaternionBase operator*(const QuaternionBase &a, const T &b) { return {a.w * b, a.x * b, a.y * b, a.z * b}; } /* Negate the quaternion. */ - friend Quaternion operator-(const Quaternion &a) + friend QuaternionBase operator-(const QuaternionBase &a) { return {-a.w, -a.x, -a.y, -a.z}; } - friend bool operator==(const Quaternion &a, const Quaternion &b) + friend bool operator==(const QuaternionBase &a, const QuaternionBase &b) { return (a.w == b.w) && (a.x == b.x) && (a.y == b.y) && (a.z == b.z); } - friend std::ostream &operator<<(std::ostream &stream, const Quaternion &rot) + friend std::ostream &operator<<(std::ostream &stream, const QuaternionBase &rot) { return stream << "Quaternion" << static_cast>(rot); } }; -} // namespace detail - /** \} */ /* -------------------------------------------------------------------- */ /** \name Dual-Quaternion * \{ */ -namespace detail { - /** - * A `blender::math::DualQuaternion` implements dual-quaternion skinning with scale aware + * A `blender::math::DualQuaternionBase` implements dual-quaternion skinning with scale aware * transformation. It allows volume preserving deformation for skinning. * - * The type is implemented so that multiple weighted `blender::math::DualQuaternion` + * The type is implemented so that multiple weighted `blender::math::DualQuaternionBase` * can be aggregated into a final rotation. Calling `normalize(dual_quat)` is mandatory before * trying to transform points with it. */ -template struct DualQuaternion { +template struct DualQuaternionBase { /** Non-dual part. */ - Quaternion quat; + QuaternionBase quat; /** Dual part. */ - Quaternion trans; + QuaternionBase trans; /** * Scaling is saved separately to handle cases of non orthonormal axes, non uniform scale and @@ -198,7 +192,7 @@ template struct DualQuaternion { * It currently holds some translation in some cases. Is this wanted? * This would save some flops all along the way. */ MatBase scale; - /** The weight of #DualQuaternion.scale. Set to 0 if uniformly scaled to skip `scale` sum. */ + /** The weight of #DualQuaternionBase.scale. Set to 0 if uniformly scaled to skip `scale` sum. */ T scale_weight; /** * The weight of this dual-quaternion. Used for and summation & normalizing. @@ -206,25 +200,25 @@ template struct DualQuaternion { */ T quat_weight; - DualQuaternion() = delete; + DualQuaternionBase() = delete; /** * Dual quaternion without scaling. */ - DualQuaternion(const Quaternion &non_dual, const Quaternion &dual); + DualQuaternionBase(const QuaternionBase &non_dual, const QuaternionBase &dual); /** * Dual quaternion with scaling. */ - DualQuaternion(const Quaternion &non_dual, - const Quaternion &dual, - const MatBase &scale_mat); + DualQuaternionBase(const QuaternionBase &non_dual, + const QuaternionBase &dual, + const MatBase &scale_mat); /** Static functions. */ - static DualQuaternion identity() + static DualQuaternionBase identity() { - return DualQuaternion(Quaternion::identity(), Quaternion::zero()); + return DualQuaternionBase(QuaternionBase::identity(), QuaternionBase::zero()); } /** Methods. */ @@ -232,42 +226,42 @@ template struct DualQuaternion { /** Operators. */ /** Apply a scalar weight to a dual quaternion. */ - DualQuaternion &operator*=(const T &t); + DualQuaternionBase &operator*=(const T &t); /** Add two weighted dual-quaternions rotations. */ - DualQuaternion &operator+=(const DualQuaternion &b); + DualQuaternionBase &operator+=(const DualQuaternionBase &b); /** Apply a scalar weight to a dual quaternion. */ - friend DualQuaternion operator*(const DualQuaternion &a, const T &t) + friend DualQuaternionBase operator*(const DualQuaternionBase &a, const T &t) { - DualQuaternion dq = a; + DualQuaternionBase dq = a; dq *= t; return dq; } /** Apply a scalar weight to a dual quaternion. */ - friend DualQuaternion operator*(const T &t, const DualQuaternion &a) + friend DualQuaternionBase operator*(const T &t, const DualQuaternionBase &a) { - DualQuaternion dq = a; + DualQuaternionBase dq = a; dq *= t; return dq; } /** Add two weighted dual-quaternions rotations. */ - friend DualQuaternion operator+(const DualQuaternion &a, const DualQuaternion &b) + friend DualQuaternionBase operator+(const DualQuaternionBase &a, const DualQuaternionBase &b) { - DualQuaternion dq = a; + DualQuaternionBase dq = a; dq += b; return dq; } - friend bool operator==(const DualQuaternion &a, const DualQuaternion &b) + friend bool operator==(const DualQuaternionBase &a, const DualQuaternionBase &b) { return (a.quat == b.quat) && (a.trans == b.trans) && (a.quat_weight == b.quat_weight) && (a.scale_weight == b.scale_weight) && (a.scale == b.scale); } - friend std::ostream &operator<<(std::ostream &stream, const DualQuaternion &rot) + friend std::ostream &operator<<(std::ostream &stream, const DualQuaternionBase &rot) { stream << "DualQuaternion(\n"; stream << " .quat = " << rot.quat << "\n"; @@ -281,20 +275,18 @@ template struct DualQuaternion { } }; -} // namespace detail - /** * Returns true if the #DualQuaternion has not been mixed with other #DualQuaternion and needs no * normalization. */ -template [[nodiscard]] inline bool is_normalized(const detail::DualQuaternion &dq) +template [[nodiscard]] inline bool is_normalized(const DualQuaternionBase &dq) { return dq.quat_weight == T(1); } /** \} */ -template struct AssertUnitEpsilon> { +template struct AssertUnitEpsilon> { static constexpr U value = AssertUnitEpsilon::value * 10; }; @@ -310,8 +302,8 @@ template<> struct TypeTraits { using DoublePrecision = double; }; -using Quaternion = math::detail::Quaternion; -using DualQuaternion = math::detail::DualQuaternion; +using Quaternion = QuaternionBase; +using DualQuaternion = DualQuaternionBase; } // namespace blender::math diff --git a/source/blender/blenlib/BLI_math_rotation.hh b/source/blender/blenlib/BLI_math_rotation.hh index ef09aeafd76..9276e2713d6 100644 --- a/source/blender/blenlib/BLI_math_rotation.hh +++ b/source/blender/blenlib/BLI_math_rotation.hh @@ -27,7 +27,7 @@ namespace blender::math { * This might introduce some precision loss and have performance implication. */ template -[[nodiscard]] detail::Quaternion rotate(const detail::Quaternion &a, const RotT &b); +[[nodiscard]] QuaternionBase rotate(const QuaternionBase &a, const RotT &b); /** * Rotate \a a by \a b. In other word, insert the \a b rotation before \a a. @@ -36,8 +36,7 @@ template * This might introduce some precision loss and have performance implication. */ template -[[nodiscard]] detail::AxisAngle rotate(const detail::AxisAngle &a, - const RotT &b); +[[nodiscard]] AxisAngleBase rotate(const AxisAngleBase &a, const RotT &b); /** * Rotate \a a by \a b. In other word, insert the \a b rotation before \a a. @@ -46,7 +45,7 @@ template * This might introduce some precision loss and have performance implication. */ template -[[nodiscard]] detail::EulerXYZ rotate(const detail::EulerXYZ &a, const RotT &b); +[[nodiscard]] EulerXYZBase rotate(const EulerXYZBase &a, const RotT &b); /** * Rotate \a a by \a b. In other word, insert the \a b rotation before \a a. @@ -55,14 +54,14 @@ template * This might introduce some precision loss and have performance implication. */ template -[[nodiscard]] detail::Euler3 rotate(const detail::Euler3 &a, const RotT &b); +[[nodiscard]] Euler3Base rotate(const Euler3Base &a, const RotT &b); /** * Return rotation from orientation \a a to orientation \a b into another quaternion. */ template -[[nodiscard]] detail::Quaternion rotation_between(const detail::Quaternion &a, - const detail::Quaternion &b); +[[nodiscard]] QuaternionBase rotation_between(const QuaternionBase &a, + const QuaternionBase &b); /** * Create a orientation from a triangle plane and the axis formed by the segment(v1, v2). @@ -70,18 +69,18 @@ template * Used for Ngons when their normal is known. */ template -[[nodiscard]] detail::Quaternion from_triangle(const VecBase &v1, - const VecBase &v2, - const VecBase &v3, - const VecBase &normal); +[[nodiscard]] QuaternionBase from_triangle(const VecBase &v1, + const VecBase &v2, + const VecBase &v3, + const VecBase &normal); /** * Create a orientation from a triangle plane and the axis formed by the segment(v1, v2). */ template -[[nodiscard]] detail::Quaternion from_triangle(const VecBase &v1, - const VecBase &v2, - const VecBase &v3); +[[nodiscard]] QuaternionBase from_triangle(const VecBase &v1, + const VecBase &v2, + const VecBase &v3); /** * Create a rotation from a vector and a basis rotation. @@ -90,22 +89,21 @@ template * \a up_flag is supposed to be #Object.upflag */ template -[[nodiscard]] detail::Quaternion from_vector(const VecBase &vector, - const AxisSigned track_flag, - const Axis up_flag); +[[nodiscard]] QuaternionBase from_vector(const VecBase &vector, + const AxisSigned track_flag, + const Axis up_flag); /** * Returns a quaternion for converting local space to tracking space. * This is slightly different than from_axis_conversion for legacy reasons. */ template -[[nodiscard]] detail::Quaternion from_tracking(AxisSigned forward_axis, Axis up_axis); +[[nodiscard]] QuaternionBase from_tracking(AxisSigned forward_axis, Axis up_axis); /** * Convert euler rotation to gimbal rotation matrix. */ -template -[[nodiscard]] MatBase to_gimbal_axis(const detail::Euler3 &rotation); +template [[nodiscard]] MatBase to_gimbal_axis(const Euler3Base &rotation); /** \} */ @@ -120,7 +118,7 @@ template * Unlike the angle between vectors, this does *NOT* return the shortest angle. * See `angle_of_signed` below for this. */ -template [[nodiscard]] detail::AngleRadian angle_of(const detail::Quaternion &q) +template [[nodiscard]] AngleRadianBase angle_of(const QuaternionBase &q) { BLI_assert(is_unit_scale(q)); return T(2) * math::safe_acos(q.w); @@ -134,8 +132,7 @@ template [[nodiscard]] detail::AngleRadian angle_of(const detail: * allows to use 'abs(angle_of_signed(...))' to get the shortest angle between quaternions with * higher precision than subtracting 2pi afterwards. */ -template -[[nodiscard]] detail::AngleRadian angle_of_signed(const detail::Quaternion &q) +template [[nodiscard]] AngleRadianBase angle_of_signed(const QuaternionBase &q) { BLI_assert(is_unit_scale(q)); return T(2) * ((q.w >= T(0)) ? math::safe_acos(q.w) : -math::safe_acos(-q.w)); @@ -148,13 +145,13 @@ template * See `angle_of` for more detail. */ template -[[nodiscard]] detail::AngleRadian angle_between(const detail::Quaternion &a, - const detail::Quaternion &b) +[[nodiscard]] AngleRadianBase angle_between(const QuaternionBase &a, + const QuaternionBase &b) { return angle_of(rotation_between(a, b)); } template -[[nodiscard]] detail::AngleRadian angle_between(const VecBase &a, const VecBase &b) +[[nodiscard]] AngleRadianBase angle_between(const VecBase &a, const VecBase &b) { BLI_assert(is_unit_scale(a)); BLI_assert(is_unit_scale(b)); @@ -178,8 +175,8 @@ template * See `angle_of_signed` for more detail. */ template -[[nodiscard]] detail::AngleRadian angle_between_signed(const detail::Quaternion &a, - const detail::Quaternion &b) +[[nodiscard]] AngleRadianBase angle_between_signed(const QuaternionBase &a, + const QuaternionBase &b) { return angle_of_signed(rotation_between(a, b)); } @@ -191,27 +188,26 @@ template * \{ */ template -[[nodiscard]] detail::Quaternion rotate(const detail::Quaternion &a, const RotT &b) +[[nodiscard]] QuaternionBase rotate(const QuaternionBase &a, const RotT &b) { - return a * detail::Quaternion(b); + return a * QuaternionBase(b); } template -[[nodiscard]] detail::AxisAngle rotate(const detail::AxisAngle &a, - const RotT &b) +[[nodiscard]] AxisAngleBase rotate(const AxisAngleBase &a, const RotT &b) { - return detail::AxisAngle(detail::Quaternion(a) * detail::Quaternion(b)); + return AxisAngleBase(QuaternionBase(a) * QuaternionBase(b)); } template -[[nodiscard]] detail::EulerXYZ rotate(const detail::EulerXYZ &a, const RotT &b) +[[nodiscard]] EulerXYZBase rotate(const EulerXYZBase &a, const RotT &b) { MatBase tmp = from_rotation>(a) * from_rotation>(b); return to_euler(tmp); } template -[[nodiscard]] detail::Euler3 rotate(const detail::Euler3 &a, const RotT &b) +[[nodiscard]] Euler3Base rotate(const Euler3Base &a, const RotT &b) { const MatBase tmp = from_rotation>(a) * from_rotation>(b); @@ -219,17 +215,17 @@ template } template -[[nodiscard]] detail::Quaternion rotation_between(const detail::Quaternion &a, - const detail::Quaternion &b) +[[nodiscard]] QuaternionBase rotation_between(const QuaternionBase &a, + const QuaternionBase &b) { return invert(a) * b; } template -[[nodiscard]] detail::Quaternion from_triangle(const VecBase &v1, - const VecBase &v2, - const VecBase &v3, - const VecBase &normal) +[[nodiscard]] QuaternionBase from_triangle(const VecBase &v1, + const VecBase &v2, + const VecBase &v3, + const VecBase &normal) { /* Force to used an unused var to avoid the same function signature as the version without * `normal` argument. */ @@ -246,7 +242,7 @@ template T angle = T(-0.5) * math::safe_acos(z_axis.z); T si = math::sin(angle); - detail::Quaternion q1(math::cos(angle), nor.x * si, nor.y * si, T(0)); + QuaternionBase q1(math::cos(angle), nor.x * si, nor.y * si, T(0)); /* Rotate back line v1-v2. */ Vec3T line = transform_point(conjugate(q1), (v2 - v1)); @@ -254,23 +250,23 @@ template line = normalize(Vec3T(line.x, line.y, T(0))); angle = T(0.5) * math::atan2(line.y, line.x); - detail::Quaternion q2(math::cos(angle), 0.0, 0.0, math::sin(angle)); + QuaternionBase q2(math::cos(angle), 0.0, 0.0, math::sin(angle)); return q1 * q2; } template -[[nodiscard]] detail::Quaternion from_triangle(const VecBase &v1, - const VecBase &v2, - const VecBase &v3) +[[nodiscard]] QuaternionBase from_triangle(const VecBase &v1, + const VecBase &v2, + const VecBase &v3) { return from_triangle(v1, v2, v3, normal_tri(v1, v2, v3)); } template -[[nodiscard]] detail::Quaternion from_vector(const VecBase &vector, - const AxisSigned track_flag, - const Axis up_flag) +[[nodiscard]] QuaternionBase from_vector(const VecBase &vector, + const AxisSigned track_flag, + const Axis up_flag) { using Vec2T = VecBase; using Vec3T = VecBase; @@ -279,7 +275,7 @@ template const T vec_len = length(vector); if (UNLIKELY(vec_len == 0.0f)) { - return detail::Quaternion::identity(); + return QuaternionBase::identity(); } const Axis axis = track_flag.axis(); @@ -313,8 +309,8 @@ template * Avoiding the need for safe_acos and deriving sin from cos. */ const T rotation_angle = math::safe_acos(vec[axis.as_int()] / vec_len); - const detail::Quaternion q1 = to_quaternion( - detail::AxisAngle>(rotation_axis, rotation_angle)); + const QuaternionBase q1 = to_quaternion( + AxisAngleBase>(rotation_axis, rotation_angle)); if (axis == up_flag) { /* Nothing else to do. */ @@ -341,27 +337,26 @@ template projected = -projected; } - const detail::AngleCartesian angle(projected.x, projected.y); - const detail::AngleCartesian half_angle = angle / T(2); + const AngleCartesianBase angle(projected.x, projected.y); + const AngleCartesianBase half_angle = angle / T(2); - const detail::Quaternion q2(Vec4T(half_angle.cos(), vec * (half_angle.sin() / vec_len))); + const QuaternionBase q2(Vec4T(half_angle.cos(), vec * (half_angle.sin() / vec_len))); return q2 * q1; } template -[[nodiscard]] detail::Quaternion from_tracking(AxisSigned forward_axis, Axis up_axis) +[[nodiscard]] QuaternionBase from_tracking(AxisSigned forward_axis, Axis up_axis) { BLI_assert(forward_axis.axis() != up_axis); /* Curve have Z forward, Y up, X left. */ - return detail::Quaternion( + return QuaternionBase( rotation_between(from_orthonormal_axes(AxisSigned::Z_POS, AxisSigned::Y_POS), from_orthonormal_axes(forward_axis, AxisSigned(up_axis)))); } -template -[[nodiscard]] MatBase to_gimbal_axis(const detail::Euler3 &rotation) +template [[nodiscard]] MatBase to_gimbal_axis(const Euler3Base &rotation) { using Mat3T = MatBase; using Vec3T = VecBase; @@ -373,7 +368,7 @@ template /* First axis is local. */ result[i_index] = from_rotation(rotation)[i_index]; /* Second axis is local minus first rotation. */ - detail::Euler3 tmp_rot = rotation; + Euler3Base tmp_rot = rotation; tmp_rot.i() = T(0); result[j_index] = from_rotation(tmp_rot)[j_index]; /* Last axis is global. */ @@ -393,7 +388,7 @@ template * Creates a quaternion from an axis triple. * This is faster and more precise than converting from another representation. */ -template detail::Quaternion to_quaternion(const CartesianBasis &rotation) +template QuaternionBase to_quaternion(const CartesianBasis &rotation) { /** * There are only 6 * 4 = 24 possible valid orthonormal orientations. @@ -406,53 +401,53 @@ template detail::Quaternion to_quaternion(const CartesianBasis &r switch (map(rotation.axes.x, rotation.axes.y, rotation.axes.z)) { default: - return detail::Quaternion::identity(); + return QuaternionBase::identity(); case map(AxisSigned::Z_POS, AxisSigned::X_POS, AxisSigned::Y_POS): - return detail::Quaternion{T(0.5), T(-0.5), T(-0.5), T(-0.5)}; + return QuaternionBase{T(0.5), T(-0.5), T(-0.5), T(-0.5)}; case map(AxisSigned::Y_NEG, AxisSigned::X_POS, AxisSigned::Z_POS): - return detail::Quaternion{T(M_SQRT1_2), T(0), T(0), T(-M_SQRT1_2)}; + return QuaternionBase{T(M_SQRT1_2), T(0), T(0), T(-M_SQRT1_2)}; case map(AxisSigned::Z_NEG, AxisSigned::X_POS, AxisSigned::Y_NEG): - return detail::Quaternion{T(0.5), T(0.5), T(0.5), T(-0.5)}; + return QuaternionBase{T(0.5), T(0.5), T(0.5), T(-0.5)}; case map(AxisSigned::Y_POS, AxisSigned::X_POS, AxisSigned::Z_NEG): - return detail::Quaternion{T(0), T(M_SQRT1_2), T(M_SQRT1_2), T(0)}; + return QuaternionBase{T(0), T(M_SQRT1_2), T(M_SQRT1_2), T(0)}; case map(AxisSigned::Z_NEG, AxisSigned::Y_POS, AxisSigned::X_POS): - return detail::Quaternion{T(M_SQRT1_2), T(0), T(M_SQRT1_2), T(0)}; + return QuaternionBase{T(M_SQRT1_2), T(0), T(M_SQRT1_2), T(0)}; case map(AxisSigned::Z_POS, AxisSigned::Y_POS, AxisSigned::X_NEG): - return detail::Quaternion{T(M_SQRT1_2), T(0), T(-M_SQRT1_2), T(0)}; + return QuaternionBase{T(M_SQRT1_2), T(0), T(-M_SQRT1_2), T(0)}; case map(AxisSigned::X_NEG, AxisSigned::Y_POS, AxisSigned::Z_NEG): - return detail::Quaternion{T(0), T(0), T(1), T(0)}; + return QuaternionBase{T(0), T(0), T(1), T(0)}; case map(AxisSigned::Y_POS, AxisSigned::Z_POS, AxisSigned::X_POS): - return detail::Quaternion{T(0.5), T(0.5), T(0.5), T(0.5)}; + return QuaternionBase{T(0.5), T(0.5), T(0.5), T(0.5)}; case map(AxisSigned::X_NEG, AxisSigned::Z_POS, AxisSigned::Y_POS): - return detail::Quaternion{T(0), T(0), T(M_SQRT1_2), T(M_SQRT1_2)}; + return QuaternionBase{T(0), T(0), T(M_SQRT1_2), T(M_SQRT1_2)}; case map(AxisSigned::Y_NEG, AxisSigned::Z_POS, AxisSigned::X_NEG): - return detail::Quaternion{T(0.5), T(0.5), T(-0.5), T(-0.5)}; + return QuaternionBase{T(0.5), T(0.5), T(-0.5), T(-0.5)}; case map(AxisSigned::X_POS, AxisSigned::Z_POS, AxisSigned::Y_NEG): - return detail::Quaternion{T(M_SQRT1_2), T(M_SQRT1_2), T(0), T(0)}; + return QuaternionBase{T(M_SQRT1_2), T(M_SQRT1_2), T(0), T(0)}; case map(AxisSigned::Z_NEG, AxisSigned::X_NEG, AxisSigned::Y_POS): - return detail::Quaternion{T(0.5), T(-0.5), T(0.5), T(0.5)}; + return QuaternionBase{T(0.5), T(-0.5), T(0.5), T(0.5)}; case map(AxisSigned::Y_POS, AxisSigned::X_NEG, AxisSigned::Z_POS): - return detail::Quaternion{T(M_SQRT1_2), T(0), T(0), T(M_SQRT1_2)}; + return QuaternionBase{T(M_SQRT1_2), T(0), T(0), T(M_SQRT1_2)}; case map(AxisSigned::Z_POS, AxisSigned::X_NEG, AxisSigned::Y_NEG): - return detail::Quaternion{T(0.5), T(0.5), T(-0.5), T(0.5)}; + return QuaternionBase{T(0.5), T(0.5), T(-0.5), T(0.5)}; case map(AxisSigned::Y_NEG, AxisSigned::X_NEG, AxisSigned::Z_NEG): - return detail::Quaternion{T(0), T(-M_SQRT1_2), T(M_SQRT1_2), T(0)}; + return QuaternionBase{T(0), T(-M_SQRT1_2), T(M_SQRT1_2), T(0)}; case map(AxisSigned::Z_POS, AxisSigned::Y_NEG, AxisSigned::X_POS): - return detail::Quaternion{T(0), T(M_SQRT1_2), T(0), T(M_SQRT1_2)}; + return QuaternionBase{T(0), T(M_SQRT1_2), T(0), T(M_SQRT1_2)}; case map(AxisSigned::X_NEG, AxisSigned::Y_NEG, AxisSigned::Z_POS): - return detail::Quaternion{T(0), T(0), T(0), T(1)}; + return QuaternionBase{T(0), T(0), T(0), T(1)}; case map(AxisSigned::Z_NEG, AxisSigned::Y_NEG, AxisSigned::X_NEG): - return detail::Quaternion{T(0), T(-M_SQRT1_2), T(0), T(M_SQRT1_2)}; + return QuaternionBase{T(0), T(-M_SQRT1_2), T(0), T(M_SQRT1_2)}; case map(AxisSigned::X_POS, AxisSigned::Y_NEG, AxisSigned::Z_NEG): - return detail::Quaternion{T(0), T(1), T(0), T(0)}; + return QuaternionBase{T(0), T(1), T(0), T(0)}; case map(AxisSigned::Y_NEG, AxisSigned::Z_NEG, AxisSigned::X_POS): - return detail::Quaternion{T(0.5), T(-0.5), T(0.5), T(-0.5)}; + return QuaternionBase{T(0.5), T(-0.5), T(0.5), T(-0.5)}; case map(AxisSigned::X_POS, AxisSigned::Z_NEG, AxisSigned::Y_POS): - return detail::Quaternion{T(M_SQRT1_2), T(-M_SQRT1_2), T(0), T(0)}; + return QuaternionBase{T(M_SQRT1_2), T(-M_SQRT1_2), T(0), T(0)}; case map(AxisSigned::Y_POS, AxisSigned::Z_NEG, AxisSigned::X_NEG): - return detail::Quaternion{T(0.5), T(-0.5), T(-0.5), T(0.5)}; + return QuaternionBase{T(0.5), T(-0.5), T(-0.5), T(0.5)}; case map(AxisSigned::X_NEG, AxisSigned::Z_NEG, AxisSigned::Y_NEG): - return detail::Quaternion{T(0), T(0), T(-M_SQRT1_2), T(M_SQRT1_2)}; + return QuaternionBase{T(0), T(0), T(-M_SQRT1_2), T(M_SQRT1_2)}; } } diff --git a/source/blender/blenlib/intern/math_matrix.cc b/source/blender/blenlib/intern/math_matrix.cc index aad6498b62b..a266313d506 100644 --- a/source/blender/blenlib/intern/math_matrix.cc +++ b/source/blender/blenlib/intern/math_matrix.cc @@ -339,9 +339,9 @@ MatBase interpolate(const MatBase &A, const MatBase & P_B = -P_B; } - detail::Quaternion quat_A = math::to_quaternion(normalize(U_A)); - detail::Quaternion quat_B = math::to_quaternion(normalize(U_B)); - detail::Quaternion quat = math::interpolate(quat_A, quat_B, t); + QuaternionBase quat_A = math::to_quaternion(normalize(U_A)); + QuaternionBase quat_B = math::to_quaternion(normalize(U_B)); + QuaternionBase quat = math::interpolate(quat_A, quat_B, t); Mat3T U = from_rotation(quat); Mat3T P = interpolate_linear(P_A, P_B, t); @@ -372,7 +372,7 @@ template double4x4 interpolate(const double4x4 &a, const double4x4 &b, double t) template MatBase interpolate_fast(const MatBase &a, const MatBase &b, T t) { - using QuaternionT = detail::Quaternion; + using QuaternionT = QuaternionBase; using Vec3T = typename MatBase::vec3_type; Vec3T a_scale, b_scale; @@ -391,7 +391,7 @@ template double3x3 interpolate_fast(const double3x3 &a, const double3x3 &b, doub template MatBase interpolate_fast(const MatBase &a, const MatBase &b, T t) { - using QuaternionT = detail::Quaternion; + using QuaternionT = QuaternionBase; using Vec3T = typename MatBase::vec3_type; Vec3T a_loc, b_loc; @@ -447,30 +447,30 @@ Quaternion to_quaternion_legacy(const float3x3 &mat) namespace detail { template void normalized_to_eul2(const float3x3 &mat, - detail::Euler3 &eul1, - detail::Euler3 &eul2); + Euler3Base &eul1, + Euler3Base &eul2); template void normalized_to_eul2(const float3x3 &mat, - detail::EulerXYZ &eul1, - detail::EulerXYZ &eul2); + EulerXYZBase &eul1, + EulerXYZBase &eul2); template void normalized_to_eul2(const double3x3 &mat, - detail::EulerXYZ &eul1, - detail::EulerXYZ &eul2); + EulerXYZBase &eul1, + EulerXYZBase &eul2); -template detail::Quaternion normalized_to_quat_with_checks(const float3x3 &mat); -template detail::Quaternion normalized_to_quat_with_checks(const double3x3 &mat); +template QuaternionBase normalized_to_quat_with_checks(const float3x3 &mat); +template QuaternionBase normalized_to_quat_with_checks(const double3x3 &mat); -template MatBase from_rotation(const detail::AngleRadian &rotation); -template MatBase from_rotation(const detail::AngleRadian &rotation); -template MatBase from_rotation(const detail::EulerXYZ &rotation); -template MatBase from_rotation(const detail::EulerXYZ &rotation); -template MatBase from_rotation(const detail::Euler3 &rotation); -template MatBase from_rotation(const detail::Euler3 &rotation); -template MatBase from_rotation(const detail::Quaternion &rotation); -template MatBase from_rotation(const detail::Quaternion &rotation); -template MatBase from_rotation(const math::AxisAngle &rotation); -template MatBase from_rotation(const math::AxisAngle &rotation); -template MatBase from_rotation(const math::AxisAngleCartesian &rotation); -template MatBase from_rotation(const math::AxisAngleCartesian &rotation); +template MatBase from_rotation(const AngleRadian &rotation); +template MatBase from_rotation(const AngleRadian &rotation); +template MatBase from_rotation(const EulerXYZ &rotation); +template MatBase from_rotation(const EulerXYZ &rotation); +template MatBase from_rotation(const Euler3 &rotation); +template MatBase from_rotation(const Euler3 &rotation); +template MatBase from_rotation(const Quaternion &rotation); +template MatBase from_rotation(const Quaternion &rotation); +template MatBase from_rotation(const AxisAngle &rotation); +template MatBase from_rotation(const AxisAngle &rotation); +template MatBase from_rotation(const AxisAngleCartesian &rotation); +template MatBase from_rotation(const AxisAngleCartesian &rotation); } // namespace detail