forked from blender/blender
main sync #3
@ -19,33 +19,31 @@
|
||||
|
||||
namespace blender::math {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* A `blender::math::AngleRadian<T>` is a typical radian angle.
|
||||
* A `blender::math::AngleRadianBase<T>` is a typical radian angle.
|
||||
* - Storage : `1 * sizeof(T)`
|
||||
* - Range : [-inf..inf]
|
||||
* - Fast : Everything not slow.
|
||||
* - Slow : `cos()`, `sin()`, `tan()`, `AngleRadian(cos, sin)`
|
||||
*/
|
||||
template<typename T> struct AngleRadian {
|
||||
template<typename T> 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<typename T> 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<typename T> 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<T>` stores the angle as cosine + sine tuple.
|
||||
* A `blender::math::AngleCartesianBase<T>` 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<typename T> 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<typename T> struct AngleCartesian {
|
||||
template<typename T> 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<typename T> 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<T> &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<T> &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<typename T> 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<typename T> 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<T> for "
|
||||
"performance reason. Use AngleRadian<T> instead.");
|
||||
"Arbitrary angle product isn't supported with AngleCartesianBase<T> for "
|
||||
"performance reason. Use AngleRadianBase<T> 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)),
|
||||
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<typename T> struct AngleCartesian {
|
||||
return result;
|
||||
}
|
||||
BLI_assert_msg(0,
|
||||
"Arbitrary angle quotient isn't supported with AngleCartesian<T> for "
|
||||
"performance reason. Use AngleRadian<T> instead.");
|
||||
"Arbitrary angle quotient isn't supported with AngleCartesianBase<T> for "
|
||||
"performance reason. Use AngleRadianBase<T> 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<T>` stores a radian angle as quotient.
|
||||
* - Storage : `2 * sizeof(int64_t)`
|
||||
@ -385,7 +381,7 @@ template<typename T> 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<T>` if both `cos()` and `sin()`
|
||||
* NOTE: Prefer converting to `blender::math::AngleCartesianBase<T>` 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<typename T = float> struct AngleFraction {
|
||||
<< ")";
|
||||
}
|
||||
|
||||
operator detail::AngleCartesian<T>() const
|
||||
operator AngleCartesianBase<T>() const
|
||||
{
|
||||
AngleFraction a = this->wrapped();
|
||||
BLI_assert(abs(a.numerator_) <= a.denominator_);
|
||||
@ -698,51 +694,51 @@ template<typename T = float> struct AngleFraction {
|
||||
if (is_negative) {
|
||||
y = -y;
|
||||
}
|
||||
return detail::AngleCartesian<T>(x, y);
|
||||
return AngleCartesianBase<T>(x, y);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> T cos(const detail::AngleRadian<T> &a)
|
||||
template<typename T> T cos(const AngleRadianBase<T> &a)
|
||||
{
|
||||
return cos(a.radian());
|
||||
}
|
||||
template<typename T> T sin(const detail::AngleRadian<T> &a)
|
||||
template<typename T> T sin(const AngleRadianBase<T> &a)
|
||||
{
|
||||
return sin(a.radian());
|
||||
}
|
||||
template<typename T> T tan(const detail::AngleRadian<T> &a)
|
||||
template<typename T> T tan(const AngleRadianBase<T> &a)
|
||||
{
|
||||
return tan(a.radian());
|
||||
}
|
||||
|
||||
template<typename T> T cos(const detail::AngleCartesian<T> &a)
|
||||
template<typename T> T cos(const AngleCartesianBase<T> &a)
|
||||
{
|
||||
return a.cos();
|
||||
}
|
||||
template<typename T> T sin(const detail::AngleCartesian<T> &a)
|
||||
template<typename T> T sin(const AngleCartesianBase<T> &a)
|
||||
{
|
||||
return a.sin();
|
||||
}
|
||||
template<typename T> T tan(const detail::AngleCartesian<T> &a)
|
||||
template<typename T> T tan(const AngleCartesianBase<T> &a)
|
||||
{
|
||||
return a.tan();
|
||||
}
|
||||
|
||||
template<typename T> T cos(const AngleFraction<T> &a)
|
||||
{
|
||||
return cos(detail::AngleCartesian<T>(a));
|
||||
return cos(AngleCartesianBase<T>(a));
|
||||
}
|
||||
template<typename T> T sin(const AngleFraction<T> &a)
|
||||
{
|
||||
return sin(detail::AngleCartesian<T>(a));
|
||||
return sin(AngleCartesianBase<T>(a));
|
||||
}
|
||||
template<typename T> T tan(const AngleFraction<T> &a)
|
||||
{
|
||||
return tan(detail::AngleCartesian<T>(a));
|
||||
return tan(AngleCartesianBase<T>(a));
|
||||
}
|
||||
|
||||
using AngleRadian = math::detail::AngleRadian<float>;
|
||||
using AngleCartesian = math::detail::AngleCartesian<float>;
|
||||
using AngleRadian = AngleRadianBase<float>;
|
||||
using AngleCartesian = AngleCartesianBase<float>;
|
||||
|
||||
} // namespace blender::math
|
||||
|
||||
|
@ -13,14 +13,14 @@
|
||||
#include "BLI_math_matrix.hh"
|
||||
#include "BLI_math_quaternion.hh"
|
||||
|
||||
namespace blender::math::detail {
|
||||
namespace blender::math {
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Constructors
|
||||
* \{ */
|
||||
|
||||
template<typename T, typename AngleT>
|
||||
AxisAngle<T, AngleT>::AxisAngle(const VecBase<T, 3> &axis, const AngleT &angle)
|
||||
AxisAngleBase<T, AngleT>::AxisAngleBase(const VecBase<T, 3> &axis, const AngleT &angle)
|
||||
{
|
||||
BLI_assert(is_unit_scale(axis));
|
||||
axis_ = axis;
|
||||
@ -28,14 +28,14 @@ AxisAngle<T, AngleT>::AxisAngle(const VecBase<T, 3> &axis, const AngleT &angle)
|
||||
}
|
||||
|
||||
template<typename T, typename AngleT>
|
||||
AxisAngle<T, AngleT>::AxisAngle(const AxisSigned axis, const AngleT &angle)
|
||||
AxisAngleBase<T, AngleT>::AxisAngleBase(const AxisSigned axis, const AngleT &angle)
|
||||
{
|
||||
axis_ = to_vector<VecBase<T, 3>>(axis);
|
||||
angle_ = angle;
|
||||
}
|
||||
|
||||
template<typename T, typename AngleT>
|
||||
AxisAngle<T, AngleT>::AxisAngle(const VecBase<T, 3> &from, const VecBase<T, 3> &to)
|
||||
AxisAngleBase<T, AngleT>::AxisAngleBase(const VecBase<T, 3> &from, const VecBase<T, 3> &to)
|
||||
{
|
||||
BLI_assert(is_unit_scale(from));
|
||||
BLI_assert(is_unit_scale(to));
|
||||
@ -61,16 +61,12 @@ AxisAngle<T, AngleT>::AxisAngle(const VecBase<T, 3> &from, const VecBase<T, 3> &
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::math::detail
|
||||
|
||||
namespace blender::math {
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Conversion to Quaternions
|
||||
* \{ */
|
||||
|
||||
template<typename T, typename AngleT>
|
||||
detail::Quaternion<T> to_quaternion(const detail::AxisAngle<T, AngleT> &axis_angle)
|
||||
QuaternionBase<T> to_quaternion(const AxisAngleBase<T, AngleT> &axis_angle)
|
||||
{
|
||||
BLI_assert(math::is_unit_scale(axis_angle.axis()));
|
||||
|
||||
@ -79,7 +75,7 @@ detail::Quaternion<T> to_quaternion(const detail::AxisAngle<T, AngleT> &axis_ang
|
||||
T hc = math::cos(half_angle);
|
||||
|
||||
VecBase<T, 3> xyz = axis_angle.axis() * hs;
|
||||
return detail::Quaternion<T>(hc, xyz.x, xyz.y, xyz.z);
|
||||
return QuaternionBase<T>(hc, xyz.x, xyz.y, xyz.z);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@ -89,25 +85,25 @@ detail::Quaternion<T> to_quaternion(const detail::AxisAngle<T, AngleT> &axis_ang
|
||||
* \{ */
|
||||
|
||||
template<typename T, typename AngleT>
|
||||
detail::Euler3<T> to_euler(const detail::AxisAngle<T, AngleT> &axis_angle, EulerOrder order)
|
||||
Euler3Base<T> to_euler(const AxisAngleBase<T, AngleT> &axis_angle, EulerOrder order)
|
||||
{
|
||||
/* Use quaternions as intermediate representation for now... */
|
||||
return to_euler(to_quaternion(axis_angle), order);
|
||||
}
|
||||
|
||||
template<typename T, typename AngleT>
|
||||
detail::EulerXYZ<T> to_euler(const detail::AxisAngle<T, AngleT> &axis_angle)
|
||||
EulerXYZBase<T> to_euler(const AxisAngleBase<T, AngleT> &axis_angle)
|
||||
{
|
||||
/* Check easy and exact conversions first. */
|
||||
const VecBase<T, 3> axis = axis_angle.axis();
|
||||
if (axis.x == T(1)) {
|
||||
return detail::EulerXYZ<T>(T(axis_angle.angle()), T(0), T(0));
|
||||
return EulerXYZBase<T>(T(axis_angle.angle()), T(0), T(0));
|
||||
}
|
||||
else if (axis.y == T(1)) {
|
||||
return detail::EulerXYZ<T>(T(0), T(axis_angle.angle()), T(0));
|
||||
return EulerXYZBase<T>(T(0), T(axis_angle.angle()), T(0));
|
||||
}
|
||||
else if (axis.z == T(1)) {
|
||||
return detail::EulerXYZ<T>(T(0), T(0), T(axis_angle.angle()));
|
||||
return EulerXYZBase<T>(T(0), T(0), T(axis_angle.angle()));
|
||||
}
|
||||
/* Use quaternions as intermediate representation for now... */
|
||||
return to_euler(to_quaternion(axis_angle));
|
||||
|
@ -14,8 +14,8 @@
|
||||
* 2D operations and are thus faster.
|
||||
*
|
||||
* Interpolation isn't possible between two `blender::math::AxisAngle<T>`; they must be
|
||||
* converted to other rotation types for that. Converting to `blender::math::Quaternion<T>` is the
|
||||
* fastest and more correct option.
|
||||
* converted to other rotation types for that. Converting to `blender::math::QuaternionBase<T>` is
|
||||
* the fastest and more correct option.
|
||||
*/
|
||||
|
||||
#include "BLI_math_angle_types.hh"
|
||||
@ -25,9 +25,7 @@
|
||||
|
||||
namespace blender::math {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T, typename AngleT> struct AxisAngle {
|
||||
template<typename T, typename AngleT> struct AxisAngleBase {
|
||||
using vec3_type = VecBase<T, 3>;
|
||||
|
||||
private:
|
||||
@ -36,29 +34,29 @@ template<typename T, typename AngleT> 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<typename T, typename AngleT> 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<float, detail::AngleRadian<float>>;
|
||||
using AxisAngleCartesian = math::detail::AxisAngle<float, detail::AngleCartesian<float>>;
|
||||
using AxisAngle = AxisAngleBase<float, AngleRadianBase<float>>;
|
||||
using AxisAngleCartesian = AxisAngleBase<float, AngleCartesianBase<float>>;
|
||||
|
||||
} // namespace blender::math
|
||||
|
||||
|
@ -14,43 +14,40 @@
|
||||
#include "BLI_math_matrix.hh"
|
||||
#include "BLI_math_quaternion.hh"
|
||||
|
||||
namespace blender::math::detail {
|
||||
namespace blender::math {
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name EulerXYZ
|
||||
* \{ */
|
||||
|
||||
template<typename T> EulerXYZ<T> EulerXYZ<T>::wrapped() const
|
||||
template<typename T> EulerXYZBase<T> EulerXYZBase<T>::wrapped() const
|
||||
{
|
||||
EulerXYZ<T> result(*this);
|
||||
result.x() = AngleRadian<T>(result.x()).wrapped().radian();
|
||||
result.y() = AngleRadian<T>(result.y()).wrapped().radian();
|
||||
result.z() = AngleRadian<T>(result.z()).wrapped().radian();
|
||||
EulerXYZBase<T> result(*this);
|
||||
result.x() = AngleRadianBase<T>(result.x()).wrapped().radian();
|
||||
result.y() = AngleRadianBase<T>(result.y()).wrapped().radian();
|
||||
result.z() = AngleRadianBase<T>(result.z()).wrapped().radian();
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T> EulerXYZ<T> EulerXYZ<T>::wrapped_around(const EulerXYZ &reference) const
|
||||
template<typename T>
|
||||
EulerXYZBase<T> EulerXYZBase<T>::wrapped_around(const EulerXYZBase &reference) const
|
||||
{
|
||||
EulerXYZ<T> result(*this);
|
||||
result.x() = AngleRadian<T>(result.x()).wrapped_around(reference.x()).radian();
|
||||
result.y() = AngleRadian<T>(result.y()).wrapped_around(reference.y()).radian();
|
||||
result.z() = AngleRadian<T>(result.z()).wrapped_around(reference.z()).radian();
|
||||
EulerXYZBase<T> result(*this);
|
||||
result.x() = AngleRadianBase<T>(result.x()).wrapped_around(reference.x()).radian();
|
||||
result.y() = AngleRadianBase<T>(result.y()).wrapped_around(reference.y()).radian();
|
||||
result.z() = AngleRadianBase<T>(result.z()).wrapped_around(reference.z()).radian();
|
||||
return result;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::math::detail
|
||||
|
||||
namespace blender::math {
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Conversion to Quaternions
|
||||
* \{ */
|
||||
|
||||
template<typename T> detail::Quaternion<T> to_quaternion(const detail::EulerXYZ<T> &eul)
|
||||
template<typename T> QuaternionBase<T> to_quaternion(const EulerXYZBase<T> &eul)
|
||||
{
|
||||
using AngleT = typename detail::EulerXYZ<T>::AngleT;
|
||||
using AngleT = typename EulerXYZBase<T>::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<typename T> detail::Quaternion<T> to_quaternion(const detail::EulerXYZ<
|
||||
const T sin_cos = sin_i * cos_k;
|
||||
const T sin_sin = sin_i * sin_k;
|
||||
|
||||
detail::Quaternion<T> quat;
|
||||
QuaternionBase<T> 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<typename T> detail::Quaternion<T> to_quaternion(const detail::EulerXYZ<
|
||||
return quat;
|
||||
}
|
||||
|
||||
template<typename T> detail::Quaternion<T> to_quaternion(const detail::Euler3<T> &eulO)
|
||||
template<typename T> QuaternionBase<T> to_quaternion(const Euler3Base<T> &eulO)
|
||||
{
|
||||
/* Swizzle to XYZ. */
|
||||
detail::EulerXYZ<T> eul_xyz{eulO.ijk()};
|
||||
EulerXYZBase<T> eul_xyz{eulO.ijk()};
|
||||
/* Flip with parity. */
|
||||
eul_xyz.y() = eulO.parity() ? -eul_xyz.y() : eul_xyz.y();
|
||||
/* Quaternion conversion. */
|
||||
detail::Quaternion<T> quat = to_quaternion(eul_xyz);
|
||||
QuaternionBase<T> quat = to_quaternion(eul_xyz);
|
||||
/* Swizzle back from XYZ. */
|
||||
VecBase<T, 3> quat_xyz;
|
||||
quat_xyz[eulO.i_index()] = quat.x;
|
||||
@ -97,14 +94,14 @@ template<typename T> detail::Quaternion<T> to_quaternion(const detail::Euler3<T>
|
||||
* \{ */
|
||||
|
||||
template<typename T, typename AngleT = AngleRadian>
|
||||
detail::AxisAngle<T, AngleT> to_axis_angle(const detail::EulerXYZ<T> &euler)
|
||||
AxisAngleBase<T, AngleT> to_axis_angle(const EulerXYZBase<T> &euler)
|
||||
{
|
||||
/* Use quaternions as intermediate representation for now... */
|
||||
return to_axis_angle<T, AngleT>(to_quaternion(euler));
|
||||
}
|
||||
|
||||
template<typename T, typename AngleT = AngleRadian>
|
||||
detail::AxisAngle<T, AngleT> to_axis_angle(const detail::Euler3<T> &euler)
|
||||
AxisAngleBase<T, AngleT> to_axis_angle(const Euler3Base<T> &euler)
|
||||
{
|
||||
/* Use quaternions as intermediate representation for now... */
|
||||
return to_axis_angle<T, AngleT>(to_quaternion(euler));
|
||||
|
@ -43,14 +43,12 @@ enum EulerOrder {
|
||||
|
||||
std::ostream &operator<<(std::ostream &stream, EulerOrder order);
|
||||
|
||||
namespace detail {
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name EulerBase
|
||||
* \{ */
|
||||
|
||||
template<typename T> struct EulerBase {
|
||||
using AngleT = AngleRadian<T>;
|
||||
using AngleT = AngleRadianBase<T>;
|
||||
|
||||
protected:
|
||||
/**
|
||||
@ -130,24 +128,24 @@ template<typename T> struct EulerBase {
|
||||
/** \name EulerXYZ
|
||||
* \{ */
|
||||
|
||||
template<typename T> struct EulerXYZ : public EulerBase<T> {
|
||||
using AngleT = AngleRadian<T>;
|
||||
template<typename T> struct EulerXYZBase : public EulerBase<T> {
|
||||
using AngleT = AngleRadianBase<T>;
|
||||
|
||||
public:
|
||||
EulerXYZ() = default;
|
||||
EulerXYZBase() = default;
|
||||
|
||||
/**
|
||||
* Create an euler x,y,z rotation from a triple of radian angle.
|
||||
*/
|
||||
template<typename AngleU> EulerXYZ(const VecBase<AngleU, 3> &vec) : EulerBase<T>(vec){};
|
||||
template<typename AngleU> EulerXYZBase(const VecBase<AngleU, 3> &vec) : EulerBase<T>(vec){};
|
||||
|
||||
EulerXYZ(const AngleT &x, const AngleT &y, const AngleT &z) : EulerBase<T>(x, y, z){};
|
||||
EulerXYZBase(const AngleT &x, const AngleT &y, const AngleT &z) : EulerBase<T>(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<typename T> struct EulerXYZ : public EulerBase<T> {
|
||||
|
||||
/** Static functions. */
|
||||
|
||||
static EulerXYZ identity()
|
||||
static EulerXYZBase identity()
|
||||
{
|
||||
return {AngleRadian<T>::identity(), AngleRadian<T>::identity(), AngleRadian<T>::identity()};
|
||||
return {AngleRadianBase<T>::identity(),
|
||||
AngleRadianBase<T>::identity(),
|
||||
AngleRadianBase<T>::identity()};
|
||||
}
|
||||
|
||||
/** Methods. */
|
||||
@ -165,7 +165,7 @@ template<typename T> struct EulerXYZ : public EulerBase<T> {
|
||||
/**
|
||||
* 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<typename T> struct EulerXYZ : public EulerBase<T> {
|
||||
* 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<VecBase<T, 3>>(rot);
|
||||
}
|
||||
@ -199,8 +199,8 @@ template<typename T> struct EulerXYZ : public EulerBase<T> {
|
||||
/** \name Euler3
|
||||
* \{ */
|
||||
|
||||
template<typename T> struct Euler3 : public EulerBase<T> {
|
||||
using AngleT = AngleRadian<T>;
|
||||
template<typename T> struct Euler3Base : public EulerBase<T> {
|
||||
using AngleT = AngleRadianBase<T>;
|
||||
|
||||
private:
|
||||
/** Axes order from applying the rotation. */
|
||||
@ -211,12 +211,12 @@ template<typename T> struct Euler3 : public EulerBase<T> {
|
||||
*/
|
||||
class Swizzle {
|
||||
private:
|
||||
Euler3 &eul_;
|
||||
Euler3Base &eul_;
|
||||
|
||||
public:
|
||||
explicit Swizzle(Euler3 &eul) : eul_(eul){};
|
||||
explicit Swizzle(Euler3Base &eul) : eul_(eul){};
|
||||
|
||||
Euler3 &operator=(const VecBase<AngleT, 3> &angles)
|
||||
Euler3Base &operator=(const VecBase<AngleT, 3> &angles)
|
||||
{
|
||||
eul_.xyz_.x = angles[eul_.i_index()];
|
||||
eul_.xyz_.y = angles[eul_.j_index()];
|
||||
@ -236,7 +236,7 @@ template<typename T> struct Euler3 : public EulerBase<T> {
|
||||
};
|
||||
|
||||
public:
|
||||
Euler3() = delete;
|
||||
Euler3Base() = delete;
|
||||
|
||||
/**
|
||||
* Create an euler rotation with \a order rotation ordering
|
||||
@ -244,16 +244,16 @@ template<typename T> struct Euler3 : public EulerBase<T> {
|
||||
* eg: If \a order is `EulerOrder::ZXY` then `angles.z` will be the angle of the first rotation.
|
||||
*/
|
||||
template<typename AngleU>
|
||||
Euler3(const VecBase<AngleU, 3> &angles_xyz, EulerOrder order)
|
||||
Euler3Base(const VecBase<AngleU, 3> &angles_xyz, EulerOrder order)
|
||||
: EulerBase<T>(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<T>(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<T>(), order_(order)
|
||||
Euler3Base(const Axis axis, AngleT angle, EulerOrder order) : EulerBase<T>(), order_(order)
|
||||
{
|
||||
this->xyz_[axis] = angle;
|
||||
}
|
||||
@ -262,7 +262,7 @@ template<typename T> struct Euler3 : public EulerBase<T> {
|
||||
* 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<typename T> struct Euler3 : public EulerBase<T> {
|
||||
* 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<AngleT, 3>(EulerXYZ<T>(this->xyz_).wrapped_around(reference.xyz_)), order_};
|
||||
return {VecBase<AngleT, 3>(EulerXYZBase<T>(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<typename T> struct Euler3 : public EulerBase<T> {
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace detail
|
||||
|
||||
using EulerXYZ = math::detail::EulerXYZ<float>;
|
||||
using Euler3 = math::detail::Euler3<float>;
|
||||
using EulerXYZ = EulerXYZBase<float>;
|
||||
using Euler3 = Euler3Base<float>;
|
||||
|
||||
} // namespace blender::math
|
||||
|
||||
|
@ -256,14 +256,12 @@ template<typename MatT, typename VectorT>
|
||||
* Extract euler rotation from transform matrix.
|
||||
* \return the rotation with the smallest values from the potential candidates.
|
||||
*/
|
||||
template<typename T> [[nodiscard]] inline EulerXYZBase<T> to_euler(const MatBase<T, 3, 3> &mat);
|
||||
template<typename T> [[nodiscard]] inline EulerXYZBase<T> to_euler(const MatBase<T, 4, 4> &mat);
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::EulerXYZ<T> to_euler(const MatBase<T, 3, 3> &mat);
|
||||
[[nodiscard]] inline Euler3Base<T> to_euler(const MatBase<T, 3, 3> &mat, EulerOrder order);
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::EulerXYZ<T> to_euler(const MatBase<T, 4, 4> &mat);
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::Euler3<T> to_euler(const MatBase<T, 3, 3> &mat, EulerOrder order);
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::Euler3<T> to_euler(const MatBase<T, 4, 4> &mat, EulerOrder order);
|
||||
[[nodiscard]] inline Euler3Base<T> to_euler(const MatBase<T, 4, 4> &mat, EulerOrder order);
|
||||
|
||||
/**
|
||||
* Extract euler rotation from transform matrix.
|
||||
@ -273,25 +271,25 @@ template<typename T>
|
||||
* \note this correspond to the C API "to_compatible" functions.
|
||||
*/
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::EulerXYZ<T> to_nearest_euler(const MatBase<T, 3, 3> &mat,
|
||||
const detail::EulerXYZ<T> &reference);
|
||||
[[nodiscard]] inline EulerXYZBase<T> to_nearest_euler(const MatBase<T, 3, 3> &mat,
|
||||
const EulerXYZBase<T> &reference);
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::EulerXYZ<T> to_nearest_euler(const MatBase<T, 4, 4> &mat,
|
||||
const detail::EulerXYZ<T> &reference);
|
||||
[[nodiscard]] inline EulerXYZBase<T> to_nearest_euler(const MatBase<T, 4, 4> &mat,
|
||||
const EulerXYZBase<T> &reference);
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::Euler3<T> to_nearest_euler(const MatBase<T, 3, 3> &mat,
|
||||
const detail::Euler3<T> &reference);
|
||||
[[nodiscard]] inline Euler3Base<T> to_nearest_euler(const MatBase<T, 3, 3> &mat,
|
||||
const Euler3Base<T> &reference);
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::Euler3<T> to_nearest_euler(const MatBase<T, 4, 4> &mat,
|
||||
const detail::Euler3<T> &reference);
|
||||
[[nodiscard]] inline Euler3Base<T> to_nearest_euler(const MatBase<T, 4, 4> &mat,
|
||||
const Euler3Base<T> &reference);
|
||||
|
||||
/**
|
||||
* Extract quaternion rotation from transform matrix.
|
||||
*/
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::Quaternion<T> to_quaternion(const MatBase<T, 3, 3> &mat);
|
||||
[[nodiscard]] inline QuaternionBase<T> to_quaternion(const MatBase<T, 3, 3> &mat);
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::Quaternion<T> to_quaternion(const MatBase<T, 4, 4> &mat);
|
||||
[[nodiscard]] inline QuaternionBase<T> to_quaternion(const MatBase<T, 4, 4> &mat);
|
||||
|
||||
/**
|
||||
* Extract quaternion rotation from transform matrix.
|
||||
@ -516,25 +514,25 @@ inline bool is_zero(const MatBase<T, NumCol, NumRow> &mat)
|
||||
namespace detail {
|
||||
|
||||
template<typename T, int NumCol, int NumRow>
|
||||
[[nodiscard]] MatBase<T, NumCol, NumRow> from_rotation(const AngleRadian<T> &rotation);
|
||||
[[nodiscard]] MatBase<T, NumCol, NumRow> from_rotation(const AngleRadianBase<T> &rotation);
|
||||
|
||||
template<typename T, int NumCol, int NumRow>
|
||||
[[nodiscard]] MatBase<T, NumCol, NumRow> from_rotation(const EulerXYZ<T> &rotation);
|
||||
[[nodiscard]] MatBase<T, NumCol, NumRow> from_rotation(const EulerXYZBase<T> &rotation);
|
||||
|
||||
template<typename T, int NumCol, int NumRow>
|
||||
[[nodiscard]] MatBase<T, NumCol, NumRow> from_rotation(const Euler3<T> &rotation);
|
||||
[[nodiscard]] MatBase<T, NumCol, NumRow> from_rotation(const Euler3Base<T> &rotation);
|
||||
|
||||
template<typename T, int NumCol, int NumRow>
|
||||
[[nodiscard]] MatBase<T, NumCol, NumRow> from_rotation(const Quaternion<T> &rotation);
|
||||
[[nodiscard]] MatBase<T, NumCol, NumRow> from_rotation(const QuaternionBase<T> &rotation);
|
||||
|
||||
template<typename T, int NumCol, int NumRow>
|
||||
[[nodiscard]] MatBase<T, NumCol, NumRow> from_rotation(const DualQuaternion<T> &rotation);
|
||||
[[nodiscard]] MatBase<T, NumCol, NumRow> from_rotation(const DualQuaternionBase<T> &rotation);
|
||||
|
||||
template<typename T, int NumCol, int NumRow>
|
||||
[[nodiscard]] MatBase<T, NumCol, NumRow> from_rotation(const CartesianBasis &rotation);
|
||||
|
||||
template<typename T, int NumCol, int NumRow, typename AngleT>
|
||||
[[nodiscard]] MatBase<T, NumCol, NumRow> from_rotation(const AxisAngle<T, AngleT> &rotation);
|
||||
[[nodiscard]] MatBase<T, NumCol, NumRow> from_rotation(const AxisAngleBase<T, AngleT> &rotation);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@ -591,7 +589,7 @@ template<typename T, int NumCol, int NumRow, typename VectorT>
|
||||
|
||||
template<typename T, int NumCol, int NumRow, typename AngleT>
|
||||
[[nodiscard]] MatBase<T, NumCol, NumRow> rotate(const MatBase<T, NumCol, NumRow> &mat,
|
||||
const detail::AxisAngle<T, AngleT> &rotation)
|
||||
const AxisAngleBase<T, AngleT> &rotation)
|
||||
{
|
||||
using MatT = MatBase<T, NumCol, NumRow>;
|
||||
using Vec3T = typename MatT::vec3_type;
|
||||
@ -707,9 +705,7 @@ template<typename T, int NumCol, int NumRow, typename VectorT>
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
void normalized_to_eul2(const MatBase<T, 3, 3> &mat,
|
||||
detail::EulerXYZ<T> &eul1,
|
||||
detail::EulerXYZ<T> &eul2)
|
||||
void normalized_to_eul2(const MatBase<T, 3, 3> &mat, EulerXYZBase<T> &eul1, EulerXYZBase<T> &eul2)
|
||||
{
|
||||
BLI_assert(math::is_unit_scale(mat));
|
||||
|
||||
@ -732,9 +728,7 @@ void normalized_to_eul2(const MatBase<T, 3, 3> &mat,
|
||||
}
|
||||
}
|
||||
template<typename T>
|
||||
void normalized_to_eul2(const MatBase<T, 3, 3> &mat,
|
||||
detail::Euler3<T> &eul1,
|
||||
detail::Euler3<T> &eul2)
|
||||
void normalized_to_eul2(const MatBase<T, 3, 3> &mat, Euler3Base<T> &eul1, Euler3Base<T> &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<T, 3, 3> &mat,
|
||||
|
||||
/* Using explicit template instantiations in order to reduce compilation time. */
|
||||
extern template void normalized_to_eul2(const float3x3 &mat,
|
||||
detail::Euler3<float> &eul1,
|
||||
detail::Euler3<float> &eul2);
|
||||
Euler3Base<float> &eul1,
|
||||
Euler3Base<float> &eul2);
|
||||
extern template void normalized_to_eul2(const float3x3 &mat,
|
||||
detail::EulerXYZ<float> &eul1,
|
||||
detail::EulerXYZ<float> &eul2);
|
||||
EulerXYZBase<float> &eul1,
|
||||
EulerXYZBase<float> &eul2);
|
||||
extern template void normalized_to_eul2(const double3x3 &mat,
|
||||
detail::EulerXYZ<double> &eul1,
|
||||
detail::EulerXYZ<double> &eul2);
|
||||
EulerXYZBase<double> &eul1,
|
||||
EulerXYZBase<double> &eul2);
|
||||
|
||||
template<typename T> detail::Quaternion<T> normalized_to_quat_fast(const MatBase<T, 3, 3> &mat)
|
||||
template<typename T> QuaternionBase<T> normalized_to_quat_fast(const MatBase<T, 3, 3> &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<T> q;
|
||||
QuaternionBase<T> 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<typename T> detail::Quaternion<T> normalized_to_quat_fast(const MatBase
|
||||
return q;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
detail::Quaternion<T> normalized_to_quat_with_checks(const MatBase<T, 3, 3> &mat)
|
||||
template<typename T> QuaternionBase<T> normalized_to_quat_with_checks(const MatBase<T, 3, 3> &mat)
|
||||
{
|
||||
const T det = math::determinant(mat);
|
||||
if (UNLIKELY(!isfinite(det))) {
|
||||
return detail::Quaternion<T>::identity();
|
||||
return QuaternionBase<T>::identity();
|
||||
}
|
||||
else if (UNLIKELY(det < T(0))) {
|
||||
return normalized_to_quat_fast(-mat);
|
||||
@ -879,11 +872,11 @@ detail::Quaternion<T> normalized_to_quat_with_checks(const MatBase<T, 3, 3> &mat
|
||||
}
|
||||
|
||||
/* Using explicit template instantiations in order to reduce compilation time. */
|
||||
extern template Quaternion<float> normalized_to_quat_with_checks(const float3x3 &mat);
|
||||
extern template Quaternion<double> normalized_to_quat_with_checks(const double3x3 &mat);
|
||||
extern template QuaternionBase<float> normalized_to_quat_with_checks(const float3x3 &mat);
|
||||
extern template QuaternionBase<double> normalized_to_quat_with_checks(const double3x3 &mat);
|
||||
|
||||
template<typename T, int NumCol, int NumRow>
|
||||
MatBase<T, NumCol, NumRow> from_rotation(const EulerXYZ<T> &rotation)
|
||||
MatBase<T, NumCol, NumRow> from_rotation(const EulerXYZBase<T> &rotation)
|
||||
{
|
||||
using MatT = MatBase<T, NumCol, NumRow>;
|
||||
using DoublePrecision = typename TypeTraits<T>::DoublePrecision;
|
||||
@ -914,14 +907,14 @@ MatBase<T, NumCol, NumRow> from_rotation(const EulerXYZ<T> &rotation)
|
||||
}
|
||||
|
||||
template<typename T, int NumCol, int NumRow>
|
||||
MatBase<T, NumCol, NumRow> from_rotation(const Euler3<T> &rotation)
|
||||
MatBase<T, NumCol, NumRow> from_rotation(const Euler3Base<T> &rotation)
|
||||
{
|
||||
using MatT = MatBase<T, NumCol, NumRow>;
|
||||
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<T> euler_xyz(rotation.ijk());
|
||||
EulerXYZBase<T> euler_xyz(rotation.ijk());
|
||||
const MatT mat = from_rotation<T, NumCol, NumRow>(rotation.parity() ? -euler_xyz : euler_xyz);
|
||||
MatT result = MatT::identity();
|
||||
result[i_index][i_index] = mat[0][0];
|
||||
@ -940,7 +933,7 @@ MatBase<T, NumCol, NumRow> from_rotation(const Euler3<T> &rotation)
|
||||
}
|
||||
|
||||
template<typename T, int NumCol, int NumRow>
|
||||
MatBase<T, NumCol, NumRow> from_rotation(const Quaternion<T> &rotation)
|
||||
MatBase<T, NumCol, NumRow> from_rotation(const QuaternionBase<T> &rotation)
|
||||
{
|
||||
using MatT = MatBase<T, NumCol, NumRow>;
|
||||
using DoublePrecision = typename TypeTraits<T>::DoublePrecision;
|
||||
@ -976,7 +969,7 @@ MatBase<T, NumCol, NumRow> from_rotation(const Quaternion<T> &rotation)
|
||||
|
||||
/* Not technically speaking a simple rotation, but a whole transform. */
|
||||
template<typename T, int NumCol, int NumRow>
|
||||
[[nodiscard]] MatBase<T, NumCol, NumRow> from_rotation(const DualQuaternion<T> &rotation)
|
||||
[[nodiscard]] MatBase<T, NumCol, NumRow> from_rotation(const DualQuaternionBase<T> &rotation)
|
||||
{
|
||||
using MatT = MatBase<T, NumCol, NumRow>;
|
||||
BLI_assert(is_normalized(rotation));
|
||||
@ -987,8 +980,8 @@ template<typename T, int NumCol, int NumRow>
|
||||
* Trinity College Dublin, Czech Technical University in Prague
|
||||
*/
|
||||
/* Follow the paper notation. */
|
||||
const Quaternion<T> &c0 = rotation.quat;
|
||||
const Quaternion<T> &ce = rotation.trans;
|
||||
const QuaternionBase<T> &c0 = rotation.quat;
|
||||
const QuaternionBase<T> &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<T, NumCol, NumRow> from_rotation(const CartesianBasis &rotation)
|
||||
}
|
||||
|
||||
template<typename T, int NumCol, int NumRow, typename AngleT>
|
||||
MatBase<T, NumCol, NumRow> from_rotation(const AxisAngle<T, AngleT> &rotation)
|
||||
MatBase<T, NumCol, NumRow> from_rotation(const AxisAngleBase<T, AngleT> &rotation)
|
||||
{
|
||||
using MatT = MatBase<T, NumCol, NumRow>;
|
||||
using Vec3T = typename MatT::vec3_type;
|
||||
@ -1045,7 +1038,7 @@ MatBase<T, NumCol, NumRow> from_rotation(const AxisAngle<T, AngleT> &rotation)
|
||||
}
|
||||
|
||||
template<typename T, int NumCol, int NumRow>
|
||||
MatBase<T, NumCol, NumRow> from_rotation(const AngleRadian<T> &rotation)
|
||||
MatBase<T, NumCol, NumRow> from_rotation(const AngleRadianBase<T> &rotation)
|
||||
{
|
||||
using MatT = MatBase<T, NumCol, NumRow>;
|
||||
const T cos_i = cos(rotation);
|
||||
@ -1061,34 +1054,34 @@ MatBase<T, NumCol, NumRow> from_rotation(const AngleRadian<T> &rotation)
|
||||
}
|
||||
|
||||
/* Using explicit template instantiations in order to reduce compilation time. */
|
||||
extern template MatBase<float, 2, 2> from_rotation(const AngleRadian<float> &rotation);
|
||||
extern template MatBase<float, 3, 3> from_rotation(const AngleRadian<float> &rotation);
|
||||
extern template MatBase<float, 3, 3> from_rotation(const EulerXYZ<float> &rotation);
|
||||
extern template MatBase<float, 4, 4> from_rotation(const EulerXYZ<float> &rotation);
|
||||
extern template MatBase<float, 3, 3> from_rotation(const Euler3<float> &rotation);
|
||||
extern template MatBase<float, 4, 4> from_rotation(const Euler3<float> &rotation);
|
||||
extern template MatBase<float, 3, 3> from_rotation(const Quaternion<float> &rotation);
|
||||
extern template MatBase<float, 4, 4> from_rotation(const Quaternion<float> &rotation);
|
||||
extern template MatBase<float, 3, 3> from_rotation(const math::AxisAngle &rotation);
|
||||
extern template MatBase<float, 4, 4> from_rotation(const math::AxisAngle &rotation);
|
||||
extern template MatBase<float, 3, 3> from_rotation(const math::AxisAngleCartesian &rotation);
|
||||
extern template MatBase<float, 4, 4> from_rotation(const math::AxisAngleCartesian &rotation);
|
||||
extern template MatBase<float, 2, 2> from_rotation(const AngleRadian &rotation);
|
||||
extern template MatBase<float, 3, 3> from_rotation(const AngleRadian &rotation);
|
||||
extern template MatBase<float, 3, 3> from_rotation(const EulerXYZ &rotation);
|
||||
extern template MatBase<float, 4, 4> from_rotation(const EulerXYZ &rotation);
|
||||
extern template MatBase<float, 3, 3> from_rotation(const Euler3 &rotation);
|
||||
extern template MatBase<float, 4, 4> from_rotation(const Euler3 &rotation);
|
||||
extern template MatBase<float, 3, 3> from_rotation(const Quaternion &rotation);
|
||||
extern template MatBase<float, 4, 4> from_rotation(const Quaternion &rotation);
|
||||
extern template MatBase<float, 3, 3> from_rotation(const AxisAngle &rotation);
|
||||
extern template MatBase<float, 4, 4> from_rotation(const AxisAngle &rotation);
|
||||
extern template MatBase<float, 3, 3> from_rotation(const AxisAngleCartesian &rotation);
|
||||
extern template MatBase<float, 4, 4> from_rotation(const AxisAngleCartesian &rotation);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::Euler3<T> to_euler(const MatBase<T, 3, 3> &mat, EulerOrder order)
|
||||
[[nodiscard]] inline Euler3Base<T> to_euler(const MatBase<T, 3, 3> &mat, EulerOrder order)
|
||||
{
|
||||
detail::Euler3<T> eul1(order), eul2(order);
|
||||
Euler3Base<T> 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<T, 3>(eul1)) > length_manhattan(VecBase<T, 3>(eul2))) ? eul2 :
|
||||
eul1;
|
||||
}
|
||||
|
||||
template<typename T> [[nodiscard]] inline detail::EulerXYZ<T> to_euler(const MatBase<T, 3, 3> &mat)
|
||||
template<typename T> [[nodiscard]] inline EulerXYZBase<T> to_euler(const MatBase<T, 3, 3> &mat)
|
||||
{
|
||||
detail::EulerXYZ<T> eul1, eul2;
|
||||
EulerXYZBase<T> 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<T, 3>(eul1)) > length_manhattan(VecBase<T, 3>(eul2))) ? eul2 :
|
||||
@ -1096,23 +1089,23 @@ template<typename T> [[nodiscard]] inline detail::EulerXYZ<T> to_euler(const Mat
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::Euler3<T> to_euler(const MatBase<T, 4, 4> &mat, EulerOrder order)
|
||||
[[nodiscard]] inline Euler3Base<T> to_euler(const MatBase<T, 4, 4> &mat, EulerOrder order)
|
||||
{
|
||||
/* TODO(fclem): Avoid the copy with 3x3 ref. */
|
||||
return to_euler<T>(MatBase<T, 3, 3>(mat), order);
|
||||
}
|
||||
|
||||
template<typename T> [[nodiscard]] inline detail::EulerXYZ<T> to_euler(const MatBase<T, 4, 4> &mat)
|
||||
template<typename T> [[nodiscard]] inline EulerXYZBase<T> to_euler(const MatBase<T, 4, 4> &mat)
|
||||
{
|
||||
/* TODO(fclem): Avoid the copy with 3x3 ref. */
|
||||
return to_euler<T>(MatBase<T, 3, 3>(mat));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::Euler3<T> to_nearest_euler(const MatBase<T, 3, 3> &mat,
|
||||
const detail::Euler3<T> &reference)
|
||||
[[nodiscard]] inline Euler3Base<T> to_nearest_euler(const MatBase<T, 3, 3> &mat,
|
||||
const Euler3Base<T> &reference)
|
||||
{
|
||||
detail::Euler3<T> eul1(reference.order()), eul2(reference.order());
|
||||
Euler3Base<T> 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<typename T>
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::EulerXYZ<T> to_nearest_euler(const MatBase<T, 3, 3> &mat,
|
||||
const detail::EulerXYZ<T> &reference)
|
||||
[[nodiscard]] inline EulerXYZBase<T> to_nearest_euler(const MatBase<T, 3, 3> &mat,
|
||||
const EulerXYZBase<T> &reference)
|
||||
{
|
||||
detail::EulerXYZ<T> eul1, eul2;
|
||||
EulerXYZBase<T> eul1, eul2;
|
||||
detail::normalized_to_eul2(mat, eul1, eul2);
|
||||
eul1 = eul1.wrapped_around(reference);
|
||||
eul2 = eul2.wrapped_around(reference);
|
||||
@ -1139,29 +1132,29 @@ template<typename T>
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::Euler3<T> to_nearest_euler(const MatBase<T, 4, 4> &mat,
|
||||
const detail::Euler3<T> &reference)
|
||||
[[nodiscard]] inline Euler3Base<T> to_nearest_euler(const MatBase<T, 4, 4> &mat,
|
||||
const Euler3Base<T> &reference)
|
||||
{
|
||||
/* TODO(fclem): Avoid the copy with 3x3 ref. */
|
||||
return to_euler<T>(MatBase<T, 3, 3>(mat), reference);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::EulerXYZ<T> to_nearest_euler(const MatBase<T, 4, 4> &mat,
|
||||
const detail::EulerXYZ<T> &reference)
|
||||
[[nodiscard]] inline EulerXYZBase<T> to_nearest_euler(const MatBase<T, 4, 4> &mat,
|
||||
const EulerXYZBase<T> &reference)
|
||||
{
|
||||
/* TODO(fclem): Avoid the copy with 3x3 ref. */
|
||||
return to_euler<T>(MatBase<T, 3, 3>(mat), reference);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::Quaternion<T> to_quaternion(const MatBase<T, 3, 3> &mat)
|
||||
[[nodiscard]] inline QuaternionBase<T> to_quaternion(const MatBase<T, 3, 3> &mat)
|
||||
{
|
||||
return detail::normalized_to_quat_with_checks(mat);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::Quaternion<T> to_quaternion(const MatBase<T, 4, 4> &mat)
|
||||
[[nodiscard]] inline QuaternionBase<T> to_quaternion(const MatBase<T, 4, 4> &mat)
|
||||
{
|
||||
/* TODO(fclem): Avoid the copy with 3x3 ref. */
|
||||
return to_quaternion<T>(MatBase<T, 3, 3>(mat));
|
||||
@ -1195,19 +1188,19 @@ template<bool AllowNegativeScale, typename T>
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
inline void to_rotation(const MatBase<T, 3, 3> &mat, detail::Quaternion<T> &r_rotation)
|
||||
inline void to_rotation(const MatBase<T, 3, 3> &mat, QuaternionBase<T> &r_rotation)
|
||||
{
|
||||
r_rotation = to_quaternion<T>(mat);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void to_rotation(const MatBase<T, 3, 3> &mat, detail::EulerXYZ<T> &r_rotation)
|
||||
inline void to_rotation(const MatBase<T, 3, 3> &mat, EulerXYZBase<T> &r_rotation)
|
||||
{
|
||||
r_rotation = to_euler<T>(mat);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void to_rotation(const MatBase<T, 3, 3> &mat, detail::Euler3<T> &r_rotation)
|
||||
inline void to_rotation(const MatBase<T, 3, 3> &mat, Euler3Base<T> &r_rotation)
|
||||
{
|
||||
r_rotation = to_euler<T>(mat, r_rotation.order());
|
||||
}
|
||||
|
@ -24,37 +24,34 @@ namespace blender::math {
|
||||
* Equivalent to component wise multiplication followed by summation of the result.
|
||||
*/
|
||||
template<typename T>
|
||||
[[nodiscard]] inline T dot(const detail::Quaternion<T> &a, const detail::Quaternion<T> &b);
|
||||
[[nodiscard]] inline T dot(const QuaternionBase<T> &a, const QuaternionBase<T> &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<typename T>
|
||||
[[nodiscard]] detail::Quaternion<T> pow(const detail::Quaternion<T> &q, const T &y);
|
||||
template<typename T> [[nodiscard]] QuaternionBase<T> pow(const QuaternionBase<T> &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<typename T>
|
||||
[[nodiscard]] inline detail::Quaternion<T> conjugate(const detail::Quaternion<T> &a);
|
||||
template<typename T> [[nodiscard]] inline QuaternionBase<T> conjugate(const QuaternionBase<T> &a);
|
||||
|
||||
/**
|
||||
* Negate the quaternion if real component (w) is negative.
|
||||
*/
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::Quaternion<T> canonicalize(const detail::Quaternion<T> &q);
|
||||
[[nodiscard]] inline QuaternionBase<T> canonicalize(const QuaternionBase<T> &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<typename T>
|
||||
[[nodiscard]] inline detail::Quaternion<T> invert(const detail::Quaternion<T> &q);
|
||||
template<typename T> [[nodiscard]] inline QuaternionBase<T> invert(const QuaternionBase<T> &q);
|
||||
|
||||
/**
|
||||
* Return invert of \a q assuming it is a unit quaternion.
|
||||
@ -62,16 +59,15 @@ template<typename T>
|
||||
* but this function shows the intent better, and asserts if \a q ever becomes non-unit-length.
|
||||
*/
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::Quaternion<T> invert_normalized(const detail::Quaternion<T> &q);
|
||||
[[nodiscard]] inline QuaternionBase<T> invert_normalized(const QuaternionBase<T> &q);
|
||||
|
||||
/**
|
||||
* Return a unit quaternion representing the same rotation as \a q or
|
||||
* the identity quaternion if \a q is ill-formed.
|
||||
*/
|
||||
template<typename T> [[nodiscard]] inline QuaternionBase<T> normalize(const QuaternionBase<T> &q);
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::Quaternion<T> normalize(const detail::Quaternion<T> &q);
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::Quaternion<T> normalize_and_get_length(const detail::Quaternion<T> &q,
|
||||
[[nodiscard]] inline QuaternionBase<T> normalize_and_get_length(const QuaternionBase<T> &q,
|
||||
T &out_length);
|
||||
|
||||
/**
|
||||
@ -79,8 +75,8 @@ template<typename T>
|
||||
* Always interpolate along the shortest angle.
|
||||
*/
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::Quaternion<T> interpolate(const detail::Quaternion<T> &a,
|
||||
const detail::Quaternion<T> &b,
|
||||
[[nodiscard]] inline QuaternionBase<T> interpolate(const QuaternionBase<T> &a,
|
||||
const QuaternionBase<T> &b,
|
||||
T t);
|
||||
|
||||
/** \} */
|
||||
@ -93,7 +89,7 @@ template<typename T>
|
||||
* Transform \a v by rotation using the quaternion \a q .
|
||||
*/
|
||||
template<typename T>
|
||||
[[nodiscard]] inline VecBase<T, 3> transform_point(const detail::Quaternion<T> &q,
|
||||
[[nodiscard]] inline VecBase<T, 3> transform_point(const QuaternionBase<T> &q,
|
||||
const VecBase<T, 3> &v);
|
||||
|
||||
/** \} */
|
||||
@ -105,7 +101,7 @@ template<typename T>
|
||||
/**
|
||||
* Returns true if all components are exactly equal to 0.
|
||||
*/
|
||||
template<typename T> [[nodiscard]] inline bool is_zero(const detail::Quaternion<T> &q)
|
||||
template<typename T> [[nodiscard]] inline bool is_zero(const QuaternionBase<T> &q)
|
||||
{
|
||||
return q.w == T(0) && q.x == T(0) && q.y == T(0) && q.z == T(0);
|
||||
}
|
||||
@ -114,22 +110,22 @@ template<typename T> [[nodiscard]] inline bool is_zero(const detail::Quaternion<
|
||||
* Returns true if the quaternions are equal within the given epsilon. Return false otherwise.
|
||||
*/
|
||||
template<typename T>
|
||||
[[nodiscard]] inline bool is_equal(const detail::Quaternion<T> &a,
|
||||
const detail::Quaternion<T> &b,
|
||||
[[nodiscard]] inline bool is_equal(const QuaternionBase<T> &a,
|
||||
const QuaternionBase<T> &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<typename T> [[nodiscard]] inline bool is_unit_scale(const detail::Quaternion<T> &q)
|
||||
template<typename T> [[nodiscard]] inline bool is_unit_scale(const QuaternionBase<T> &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<detail::Quaternion<T>>::value) ||
|
||||
!(math::abs(test_unit) >= AssertUnitEpsilon<detail::Quaternion<T>>::value));
|
||||
return (!(math::abs(test_unit - T(1)) >= AssertUnitEpsilon<QuaternionBase<T>>::value) ||
|
||||
!(math::abs(test_unit) >= AssertUnitEpsilon<QuaternionBase<T>>::value));
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@ -138,73 +134,69 @@ template<typename T> [[nodiscard]] inline bool is_unit_scale(const detail::Quate
|
||||
/** \name Quaternion
|
||||
* \{ */
|
||||
|
||||
namespace detail {
|
||||
|
||||
/* -------------- Conversions -------------- */
|
||||
|
||||
template<typename T> AngleRadian<T> Quaternion<T>::twist_angle(const Axis axis) const
|
||||
template<typename T> AngleRadianBase<T> QuaternionBase<T>::twist_angle(const Axis axis) const
|
||||
{
|
||||
/* The calculation requires a canonical quaternion. */
|
||||
const VecBase<T, 4> input_vec(canonicalize(*this));
|
||||
|
||||
return T(2) * AngleRadian<T>(input_vec[0], input_vec.yzw()[axis.as_int()]);
|
||||
return T(2) * AngleRadianBase<T>(input_vec[0], input_vec.yzw()[axis.as_int()]);
|
||||
}
|
||||
|
||||
template<typename T> Quaternion<T> Quaternion<T>::swing(const Axis axis) const
|
||||
template<typename T> QuaternionBase<T> QuaternionBase<T>::swing(const Axis axis) const
|
||||
{
|
||||
/* The calculation requires a canonical quaternion. */
|
||||
const Quaternion<T> input = canonicalize(*this);
|
||||
const QuaternionBase<T> input = canonicalize(*this);
|
||||
/* Compute swing by multiplying the original quaternion by inverted twist. */
|
||||
Quaternion<T> swing = input * invert_normalized(input.twist(axis));
|
||||
QuaternionBase<T> swing = input * invert_normalized(input.twist(axis));
|
||||
|
||||
BLI_assert(math::abs(VecBase<T, 4>(swing)[axis.as_int() + 1]) < BLI_ASSERT_UNIT_EPSILON);
|
||||
return swing;
|
||||
}
|
||||
|
||||
template<typename T> Quaternion<T> Quaternion<T>::twist(const Axis axis) const
|
||||
template<typename T> QuaternionBase<T> QuaternionBase<T>::twist(const Axis axis) const
|
||||
{
|
||||
/* The calculation requires a canonical quaternion. */
|
||||
const VecBase<T, 4> input_vec(canonicalize(*this));
|
||||
|
||||
AngleCartesian<T> half_angle = AngleCartesian<T>::from_point(input_vec[0],
|
||||
input_vec.yzw()[axis.as_int()]);
|
||||
AngleCartesianBase<T> half_angle = AngleCartesianBase<T>::from_point(
|
||||
input_vec[0], input_vec.yzw()[axis.as_int()]);
|
||||
|
||||
VecBase<T, 4> twist(half_angle.cos(), T(0), T(0), T(0));
|
||||
twist[axis.as_int() + 1] = half_angle.sin();
|
||||
return Quaternion<T>(twist);
|
||||
return QuaternionBase<T>(twist);
|
||||
}
|
||||
|
||||
/* -------------- Methods -------------- */
|
||||
|
||||
template<typename T> Quaternion<T> Quaternion<T>::wrapped_around(const Quaternion &reference) const
|
||||
template<typename T>
|
||||
QuaternionBase<T> QuaternionBase<T>::wrapped_around(const QuaternionBase<T> &reference) const
|
||||
{
|
||||
BLI_assert(is_unit_scale(*this));
|
||||
const Quaternion<T> &input = *this;
|
||||
const QuaternionBase<T> &input = *this;
|
||||
T len;
|
||||
Quaternion<T> reference_normalized = normalize_and_get_length(reference, len);
|
||||
QuaternionBase<T> reference_normalized = normalize_and_get_length(reference, len);
|
||||
/* Skips degenerate case. */
|
||||
if (len < 1e-4f) {
|
||||
return input;
|
||||
}
|
||||
Quaternion<T> result = reference * invert_normalized(reference_normalized) * input;
|
||||
QuaternionBase<T> result = reference * invert_normalized(reference_normalized) * input;
|
||||
return (distance_squared(VecBase<T, 4>(-result), VecBase<T, 4>(reference)) <
|
||||
distance_squared(VecBase<T, 4>(result), VecBase<T, 4>(reference))) ?
|
||||
-result :
|
||||
result;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/* -------------- Functions -------------- */
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline T dot(const detail::Quaternion<T> &a, const detail::Quaternion<T> &b)
|
||||
[[nodiscard]] inline T dot(const QuaternionBase<T> &a, const QuaternionBase<T> &b)
|
||||
{
|
||||
return a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] detail::Quaternion<T> pow(const detail::Quaternion<T> &q, const T &y)
|
||||
template<typename T> [[nodiscard]] QuaternionBase<T> pow(const QuaternionBase<T> &q, const T &y)
|
||||
{
|
||||
BLI_assert(is_unit_scale(q));
|
||||
/* Reference material:
|
||||
@ -223,45 +215,42 @@ template<typename T>
|
||||
return {math::cos(half_angle), math::sin(half_angle) * normalize(q.imaginary_part())};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::Quaternion<T> conjugate(const detail::Quaternion<T> &a)
|
||||
template<typename T> [[nodiscard]] inline QuaternionBase<T> conjugate(const QuaternionBase<T> &a)
|
||||
{
|
||||
return {a.w, -a.x, -a.y, -a.z};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::Quaternion<T> canonicalize(const detail::Quaternion<T> &q)
|
||||
[[nodiscard]] inline QuaternionBase<T> canonicalize(const QuaternionBase<T> &q)
|
||||
{
|
||||
return (q.w < T(0)) ? -q : q;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::Quaternion<T> invert(const detail::Quaternion<T> &q)
|
||||
template<typename T> [[nodiscard]] inline QuaternionBase<T> invert(const QuaternionBase<T> &q)
|
||||
{
|
||||
const T length_squared = dot(q, q);
|
||||
if (length_squared == T(0)) {
|
||||
return detail::Quaternion<T>::identity();
|
||||
return QuaternionBase<T>::identity();
|
||||
}
|
||||
return conjugate(q) * (T(1) / length_squared);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::Quaternion<T> invert_normalized(const detail::Quaternion<T> &q)
|
||||
[[nodiscard]] inline QuaternionBase<T> invert_normalized(const QuaternionBase<T> &q)
|
||||
{
|
||||
BLI_assert(is_unit_scale(q));
|
||||
return conjugate(q);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::Quaternion<T> normalize_and_get_length(const detail::Quaternion<T> &q,
|
||||
[[nodiscard]] inline QuaternionBase<T> normalize_and_get_length(const QuaternionBase<T> &q,
|
||||
T &out_length)
|
||||
{
|
||||
out_length = math::sqrt(dot(q, q));
|
||||
return (out_length != T(0)) ? (q * (T(1) / out_length)) : detail::Quaternion<T>::identity();
|
||||
return (out_length != T(0)) ? (q * (T(1) / out_length)) : QuaternionBase<T>::identity();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::Quaternion<T> normalize(const detail::Quaternion<T> &q)
|
||||
template<typename T> [[nodiscard]] inline QuaternionBase<T> normalize(const QuaternionBase<T> &q)
|
||||
{
|
||||
T len;
|
||||
return normalize_and_get_length(q, len);
|
||||
@ -306,28 +295,28 @@ template<typename T>
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline detail::Quaternion<T> interpolate(const detail::Quaternion<T> &a,
|
||||
const detail::Quaternion<T> &b,
|
||||
[[nodiscard]] inline QuaternionBase<T> interpolate(const QuaternionBase<T> &a,
|
||||
const QuaternionBase<T> &b,
|
||||
T t)
|
||||
{
|
||||
using Vec4T = VecBase<T, 4>;
|
||||
BLI_assert(is_unit_scale(a));
|
||||
BLI_assert(is_unit_scale(b));
|
||||
VecBase<T, 2> w = interpolate_dot_slerp(t, dot(a, b));
|
||||
return detail::Quaternion<T>(w[0] * Vec4T(a) + w[1] * Vec4T(b));
|
||||
return QuaternionBase<T>(w[0] * Vec4T(a) + w[1] * Vec4T(b));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline VecBase<T, 3> transform_point(const detail::Quaternion<T> &q,
|
||||
[[nodiscard]] inline VecBase<T, 3> transform_point(const QuaternionBase<T> &q,
|
||||
const VecBase<T, 3> &v)
|
||||
{
|
||||
#if 0 /* Reference. */
|
||||
detail::Quaternion<T> V(T(0), UNPACK3(v));
|
||||
detail::Quaternion<T> R = q * V * conjugate(q);
|
||||
QuaternionBase<T> V(T(0), UNPACK3(v));
|
||||
QuaternionBase<T> R = q * V * conjugate(q);
|
||||
return {R.x, R.y, R.z};
|
||||
#else
|
||||
/* `S = q * V` */
|
||||
detail::Quaternion<T> S;
|
||||
QuaternionBase<T> 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,20 +337,19 @@ template<typename T>
|
||||
/** \name Dual-Quaternion
|
||||
* \{ */
|
||||
|
||||
namespace detail {
|
||||
|
||||
/* -------------- Constructors -------------- */
|
||||
|
||||
template<typename T>
|
||||
DualQuaternion<T>::DualQuaternion(const Quaternion<T> &non_dual, const Quaternion<T> &dual)
|
||||
DualQuaternionBase<T>::DualQuaternionBase(const QuaternionBase<T> &non_dual,
|
||||
const QuaternionBase<T> &dual)
|
||||
: quat(non_dual), trans(dual), scale_weight(0), quat_weight(1)
|
||||
{
|
||||
BLI_assert(is_unit_scale(non_dual));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
DualQuaternion<T>::DualQuaternion(const Quaternion<T> &non_dual,
|
||||
const Quaternion<T> &dual,
|
||||
DualQuaternionBase<T>::DualQuaternionBase(const QuaternionBase<T> &non_dual,
|
||||
const QuaternionBase<T> &dual,
|
||||
const MatBase<T, 4, 4> &scale_mat)
|
||||
: quat(non_dual), trans(dual), scale(scale_mat), scale_weight(1), quat_weight(1)
|
||||
{
|
||||
@ -370,9 +358,10 @@ DualQuaternion<T>::DualQuaternion(const Quaternion<T> &non_dual,
|
||||
|
||||
/* -------------- Operators -------------- */
|
||||
|
||||
template<typename T> DualQuaternion<T> &DualQuaternion<T>::operator+=(const DualQuaternion<T> &b)
|
||||
template<typename T>
|
||||
DualQuaternionBase<T> &DualQuaternionBase<T>::operator+=(const DualQuaternionBase<T> &b)
|
||||
{
|
||||
DualQuaternion<T> &a = *this;
|
||||
DualQuaternionBase<T> &a = *this;
|
||||
/* Sum rotation and translation. */
|
||||
|
||||
/* Make sure we interpolate quaternions in the right direction. */
|
||||
@ -416,10 +405,10 @@ template<typename T> DualQuaternion<T> &DualQuaternion<T>::operator+=(const Dual
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T> DualQuaternion<T> &DualQuaternion<T>::operator*=(const T &t)
|
||||
template<typename T> DualQuaternionBase<T> &DualQuaternionBase<T>::operator*=(const T &t)
|
||||
{
|
||||
BLI_assert(t >= 0);
|
||||
DualQuaternion<T> &q = *this;
|
||||
DualQuaternionBase<T> &q = *this;
|
||||
|
||||
q.quat.w *= t;
|
||||
q.quat.x *= t;
|
||||
@ -440,8 +429,6 @@ template<typename T> DualQuaternion<T> &DualQuaternion<T>::operator*=(const T &t
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/* -------------- Functions -------------- */
|
||||
|
||||
/**
|
||||
@ -452,18 +439,18 @@ template<typename T> DualQuaternion<T> &DualQuaternion<T>::operator*=(const T &t
|
||||
* \note Returns identity #DualQuaternion if degenerate.
|
||||
*/
|
||||
template<typename T>
|
||||
[[nodiscard]] detail::DualQuaternion<T> normalize(const detail::DualQuaternion<T> &dual_quat)
|
||||
[[nodiscard]] DualQuaternionBase<T> normalize(const DualQuaternionBase<T> &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<T>::identity();
|
||||
return DualQuaternionBase<T>::identity();
|
||||
}
|
||||
|
||||
const T inv_norm_weighted = T(1) / norm_weighted;
|
||||
|
||||
detail::DualQuaternion<T> dq = dual_quat;
|
||||
DualQuaternionBase<T> dq = dual_quat;
|
||||
dq.quat = dq.quat * inv_norm_weighted;
|
||||
dq.trans = dq.trans * inv_norm_weighted;
|
||||
|
||||
@ -493,7 +480,7 @@ template<typename T>
|
||||
* first. Optionally outputs crazy space matrix.
|
||||
*/
|
||||
template<typename T>
|
||||
[[nodiscard]] VecBase<T, 3> transform_point(const detail::DualQuaternion<T> &dq,
|
||||
[[nodiscard]] VecBase<T, 3> transform_point(const DualQuaternionBase<T> &dq,
|
||||
const VecBase<T, 3> &point,
|
||||
MatBase<T, 3, 3> *r_crazy_space_mat = nullptr)
|
||||
{
|
||||
@ -555,7 +542,7 @@ template<typename T>
|
||||
* This allows volume preserving deformation for skinning.
|
||||
*/
|
||||
template<typename T>
|
||||
[[nodiscard]] detail::DualQuaternion<T> to_dual_quaternion(const MatBase<T, 4, 4> &mat,
|
||||
[[nodiscard]] DualQuaternionBase<T> to_dual_quaternion(const MatBase<T, 4, 4> &mat,
|
||||
const MatBase<T, 4, 4> &basemat)
|
||||
{
|
||||
/**
|
||||
@ -586,7 +573,7 @@ template<typename T>
|
||||
const Mat4T baseinv = invert(basemat);
|
||||
|
||||
/* Extra orthogonalize, to avoid flipping with stretched bones. */
|
||||
detail::Quaternion<T> basequat = to_quaternion(normalize(orthogonalize(baseRS, Axis::Y)));
|
||||
QuaternionBase<T> basequat = to_quaternion(normalize(orthogonalize(baseRS, Axis::Y)));
|
||||
|
||||
Mat4T baseR = from_rotation<Mat4T>(basequat);
|
||||
baseR.location() = baseRS.location();
|
||||
@ -603,21 +590,21 @@ template<typename T>
|
||||
}
|
||||
|
||||
/* Non-dual part. */
|
||||
const detail::Quaternion<T> q = to_quaternion(normalize(R));
|
||||
const QuaternionBase<T> q = to_quaternion(normalize(R));
|
||||
|
||||
/* Dual part. */
|
||||
const Vec3T &t = R.location().xyz();
|
||||
detail::Quaternion<T> d;
|
||||
QuaternionBase<T> 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<T>(q, d, scale);
|
||||
return DualQuaternionBase<T>(q, d, scale);
|
||||
}
|
||||
|
||||
return detail::DualQuaternion<T>(q, d);
|
||||
return DualQuaternionBase<T>(q, d);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@ -631,7 +618,7 @@ namespace blender::math {
|
||||
* \{ */
|
||||
|
||||
template<typename T, typename AngleT = AngleRadian>
|
||||
detail::AxisAngle<T, AngleT> to_axis_angle(const detail::Quaternion<T> &quat)
|
||||
AxisAngleBase<T, AngleT> to_axis_angle(const QuaternionBase<T> &quat)
|
||||
{
|
||||
BLI_assert(is_unit_scale(quat));
|
||||
|
||||
@ -649,7 +636,7 @@ detail::AxisAngle<T, AngleT> to_axis_angle(const detail::Quaternion<T> &quat)
|
||||
/* Leverage AngleT implementation of double angle. */
|
||||
AngleT angle = AngleT(cos_half_angle, sin_half_angle) * 2;
|
||||
|
||||
return detail::AxisAngle<T, AngleT>(axis, angle);
|
||||
return AxisAngleBase<T, AngleT>(axis, angle);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@ -658,7 +645,7 @@ detail::AxisAngle<T, AngleT> to_axis_angle(const detail::Quaternion<T> &quat)
|
||||
/** \name Conversion to Euler
|
||||
* \{ */
|
||||
|
||||
template<typename T> detail::EulerXYZ<T> to_euler(const detail::Quaternion<T> &quat)
|
||||
template<typename T> EulerXYZBase<T> to_euler(const QuaternionBase<T> &quat)
|
||||
{
|
||||
using Mat3T = MatBase<T, 3, 3>;
|
||||
BLI_assert(is_unit_scale(quat));
|
||||
@ -666,8 +653,7 @@ template<typename T> detail::EulerXYZ<T> to_euler(const detail::Quaternion<T> &q
|
||||
return to_euler<T>(unit_mat);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
detail::Euler3<T> to_euler(const detail::Quaternion<T> &quat, EulerOrder order)
|
||||
template<typename T> Euler3Base<T> to_euler(const QuaternionBase<T> &quat, EulerOrder order)
|
||||
{
|
||||
using Mat3T = MatBase<T, 3, 3>;
|
||||
BLI_assert(is_unit_scale(quat));
|
||||
@ -683,24 +669,23 @@ detail::Euler3<T> to_euler(const detail::Quaternion<T> &quat, EulerOrder order)
|
||||
|
||||
/* Prototype needed to avoid interdependencies of headers. */
|
||||
template<typename T, typename AngleT>
|
||||
detail::Quaternion<T> to_quaternion(const detail::AxisAngle<T, AngleT> &axis_angle);
|
||||
QuaternionBase<T> to_quaternion(const AxisAngleBase<T, AngleT> &axis_angle);
|
||||
|
||||
template<typename T>
|
||||
detail::Quaternion<T> detail::Quaternion<T>::expmap(const VecBase<T, 3> &expmap)
|
||||
template<typename T> QuaternionBase<T> QuaternionBase<T>::expmap(const VecBase<T, 3> &expmap)
|
||||
{
|
||||
using AxisAngleT = detail::AxisAngle<T, detail::AngleRadian<T>>;
|
||||
using AxisAngleT = AxisAngleBase<T, AngleRadianBase<T>>;
|
||||
/* Obtain axis/angle representation. */
|
||||
T angle;
|
||||
const VecBase<T, 3> axis = normalize_and_get_length(expmap, angle);
|
||||
if (LIKELY(angle != T(0))) {
|
||||
return to_quaternion(AxisAngleT(axis, angle_wrap_rad(angle)));
|
||||
}
|
||||
return detail::Quaternion<T>::identity();
|
||||
return QuaternionBase<T>::identity();
|
||||
}
|
||||
|
||||
template<typename T> VecBase<T, 3> detail::Quaternion<T>::expmap() const
|
||||
template<typename T> VecBase<T, 3> QuaternionBase<T>::expmap() const
|
||||
{
|
||||
using AxisAngleT = detail::AxisAngle<T, detail::AngleRadian<T>>;
|
||||
using AxisAngleT = AxisAngleBase<T, AngleRadianBase<T>>;
|
||||
BLI_assert(is_unit_scale(*this));
|
||||
const AxisAngleT axis_angle = to_axis_angle(*this);
|
||||
return axis_angle.axis() * axis_angle.angle().radian();
|
||||
|
@ -18,48 +18,46 @@ namespace blender::math {
|
||||
/** \name Quaternion
|
||||
* \{ */
|
||||
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* A `blender::math::Quaternion<T>` represents either an orientation or a rotation.
|
||||
* A `blender::math::QuaternionBase<T>` 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<T>` is cheaper to combine
|
||||
* than `MatBase<T, 3, 3>`. 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<T>` is cheaper to
|
||||
* combine than `MatBase<T, 3, 3>`. 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<typename T = float> struct Quaternion {
|
||||
template<typename T> 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<T, 4> &vec) : Quaternion(UNPACK4(vec)){};
|
||||
explicit QuaternionBase(const VecBase<T, 4> &vec) : QuaternionBase(UNPACK4(vec)){};
|
||||
|
||||
/**
|
||||
* Creates a quaternion from real (w) and imaginary parts (x, y, z).
|
||||
*/
|
||||
Quaternion(const T &real, const VecBase<T, 3> &imaginary)
|
||||
: Quaternion(real, UNPACK3(imaginary)){};
|
||||
QuaternionBase(const T &real, const VecBase<T, 3> &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<typename T = float> 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<T, 3> &expmap);
|
||||
static QuaternionBase expmap(const VecBase<T, 3> &expmap);
|
||||
|
||||
/** Conversions. */
|
||||
|
||||
@ -87,20 +85,20 @@ template<typename T = float> 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<T> twist_angle(const Axis axis) const;
|
||||
AngleRadianBase<T> 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<typename T = float> 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<typename T = float> 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<VecBase<T, 4>>(rot);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Dual-Quaternion
|
||||
* \{ */
|
||||
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* A `blender::math::DualQuaternion<T>` implements dual-quaternion skinning with scale aware
|
||||
* A `blender::math::DualQuaternionBase<T>` 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<T>`
|
||||
* The type is implemented so that multiple weighted `blender::math::DualQuaternionBase<T>`
|
||||
* can be aggregated into a final rotation. Calling `normalize(dual_quat)` is mandatory before
|
||||
* trying to transform points with it.
|
||||
*/
|
||||
template<typename T = float> struct DualQuaternion {
|
||||
template<typename T> struct DualQuaternionBase {
|
||||
/** Non-dual part. */
|
||||
Quaternion<T> quat;
|
||||
QuaternionBase<T> quat;
|
||||
/** Dual part. */
|
||||
Quaternion<T> trans;
|
||||
QuaternionBase<T> trans;
|
||||
|
||||
/**
|
||||
* Scaling is saved separately to handle cases of non orthonormal axes, non uniform scale and
|
||||
@ -198,7 +192,7 @@ template<typename T = float> struct DualQuaternion {
|
||||
* It currently holds some translation in some cases. Is this wanted?
|
||||
* This would save some flops all along the way. */
|
||||
MatBase<T, 4, 4> 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<typename T = float> struct DualQuaternion {
|
||||
*/
|
||||
T quat_weight;
|
||||
|
||||
DualQuaternion() = delete;
|
||||
DualQuaternionBase() = delete;
|
||||
|
||||
/**
|
||||
* Dual quaternion without scaling.
|
||||
*/
|
||||
DualQuaternion(const Quaternion<T> &non_dual, const Quaternion<T> &dual);
|
||||
DualQuaternionBase(const QuaternionBase<T> &non_dual, const QuaternionBase<T> &dual);
|
||||
|
||||
/**
|
||||
* Dual quaternion with scaling.
|
||||
*/
|
||||
DualQuaternion(const Quaternion<T> &non_dual,
|
||||
const Quaternion<T> &dual,
|
||||
DualQuaternionBase(const QuaternionBase<T> &non_dual,
|
||||
const QuaternionBase<T> &dual,
|
||||
const MatBase<T, 4, 4> &scale_mat);
|
||||
|
||||
/** Static functions. */
|
||||
|
||||
static DualQuaternion identity()
|
||||
static DualQuaternionBase identity()
|
||||
{
|
||||
return DualQuaternion(Quaternion<T>::identity(), Quaternion<T>::zero());
|
||||
return DualQuaternionBase(QuaternionBase<T>::identity(), QuaternionBase<T>::zero());
|
||||
}
|
||||
|
||||
/** Methods. */
|
||||
@ -232,42 +226,42 @@ template<typename T = float> 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<typename T = float> struct DualQuaternion {
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* Returns true if the #DualQuaternion has not been mixed with other #DualQuaternion and needs no
|
||||
* normalization.
|
||||
*/
|
||||
template<typename T> [[nodiscard]] inline bool is_normalized(const detail::DualQuaternion<T> &dq)
|
||||
template<typename T> [[nodiscard]] inline bool is_normalized(const DualQuaternionBase<T> &dq)
|
||||
{
|
||||
return dq.quat_weight == T(1);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
template<typename U> struct AssertUnitEpsilon<detail::Quaternion<U>> {
|
||||
template<typename U> struct AssertUnitEpsilon<QuaternionBase<U>> {
|
||||
static constexpr U value = AssertUnitEpsilon<U>::value * 10;
|
||||
};
|
||||
|
||||
@ -310,8 +302,8 @@ template<> struct TypeTraits<float> {
|
||||
using DoublePrecision = double;
|
||||
};
|
||||
|
||||
using Quaternion = math::detail::Quaternion<float>;
|
||||
using DualQuaternion = math::detail::DualQuaternion<float>;
|
||||
using Quaternion = QuaternionBase<float>;
|
||||
using DualQuaternion = DualQuaternionBase<float>;
|
||||
|
||||
} // namespace blender::math
|
||||
|
||||
|
@ -27,7 +27,7 @@ namespace blender::math {
|
||||
* This might introduce some precision loss and have performance implication.
|
||||
*/
|
||||
template<typename T, typename RotT>
|
||||
[[nodiscard]] detail::Quaternion<T> rotate(const detail::Quaternion<T> &a, const RotT &b);
|
||||
[[nodiscard]] QuaternionBase<T> rotate(const QuaternionBase<T> &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<typename T, typename RotT>
|
||||
* This might introduce some precision loss and have performance implication.
|
||||
*/
|
||||
template<typename T, typename RotT, typename AngleT>
|
||||
[[nodiscard]] detail::AxisAngle<T, AngleT> rotate(const detail::AxisAngle<T, AngleT> &a,
|
||||
const RotT &b);
|
||||
[[nodiscard]] AxisAngleBase<T, AngleT> rotate(const AxisAngleBase<T, AngleT> &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<typename T, typename RotT, typename AngleT>
|
||||
* This might introduce some precision loss and have performance implication.
|
||||
*/
|
||||
template<typename T, typename RotT>
|
||||
[[nodiscard]] detail::EulerXYZ<T> rotate(const detail::EulerXYZ<T> &a, const RotT &b);
|
||||
[[nodiscard]] EulerXYZBase<T> rotate(const EulerXYZBase<T> &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<typename T, typename RotT>
|
||||
* This might introduce some precision loss and have performance implication.
|
||||
*/
|
||||
template<typename T, typename RotT>
|
||||
[[nodiscard]] detail::Euler3<T> rotate(const detail::Euler3<T> &a, const RotT &b);
|
||||
[[nodiscard]] Euler3Base<T> rotate(const Euler3Base<T> &a, const RotT &b);
|
||||
|
||||
/**
|
||||
* Return rotation from orientation \a a to orientation \a b into another quaternion.
|
||||
*/
|
||||
template<typename T>
|
||||
[[nodiscard]] detail::Quaternion<T> rotation_between(const detail::Quaternion<T> &a,
|
||||
const detail::Quaternion<T> &b);
|
||||
[[nodiscard]] QuaternionBase<T> rotation_between(const QuaternionBase<T> &a,
|
||||
const QuaternionBase<T> &b);
|
||||
|
||||
/**
|
||||
* Create a orientation from a triangle plane and the axis formed by the segment(v1, v2).
|
||||
@ -70,7 +69,7 @@ template<typename T>
|
||||
* Used for Ngons when their normal is known.
|
||||
*/
|
||||
template<typename T>
|
||||
[[nodiscard]] detail::Quaternion<T> from_triangle(const VecBase<T, 3> &v1,
|
||||
[[nodiscard]] QuaternionBase<T> from_triangle(const VecBase<T, 3> &v1,
|
||||
const VecBase<T, 3> &v2,
|
||||
const VecBase<T, 3> &v3,
|
||||
const VecBase<T, 3> &normal);
|
||||
@ -79,7 +78,7 @@ template<typename T>
|
||||
* Create a orientation from a triangle plane and the axis formed by the segment(v1, v2).
|
||||
*/
|
||||
template<typename T>
|
||||
[[nodiscard]] detail::Quaternion<T> from_triangle(const VecBase<T, 3> &v1,
|
||||
[[nodiscard]] QuaternionBase<T> from_triangle(const VecBase<T, 3> &v1,
|
||||
const VecBase<T, 3> &v2,
|
||||
const VecBase<T, 3> &v3);
|
||||
|
||||
@ -90,7 +89,7 @@ template<typename T>
|
||||
* \a up_flag is supposed to be #Object.upflag
|
||||
*/
|
||||
template<typename T>
|
||||
[[nodiscard]] detail::Quaternion<T> from_vector(const VecBase<T, 3> &vector,
|
||||
[[nodiscard]] QuaternionBase<T> from_vector(const VecBase<T, 3> &vector,
|
||||
const AxisSigned track_flag,
|
||||
const Axis up_flag);
|
||||
|
||||
@ -99,13 +98,12 @@ template<typename T>
|
||||
* This is slightly different than from_axis_conversion for legacy reasons.
|
||||
*/
|
||||
template<typename T>
|
||||
[[nodiscard]] detail::Quaternion<T> from_tracking(AxisSigned forward_axis, Axis up_axis);
|
||||
[[nodiscard]] QuaternionBase<T> from_tracking(AxisSigned forward_axis, Axis up_axis);
|
||||
|
||||
/**
|
||||
* Convert euler rotation to gimbal rotation matrix.
|
||||
*/
|
||||
template<typename T>
|
||||
[[nodiscard]] MatBase<T, 3, 3> to_gimbal_axis(const detail::Euler3<T> &rotation);
|
||||
template<typename T> [[nodiscard]] MatBase<T, 3, 3> to_gimbal_axis(const Euler3Base<T> &rotation);
|
||||
|
||||
/** \} */
|
||||
|
||||
@ -120,7 +118,7 @@ template<typename T>
|
||||
* Unlike the angle between vectors, this does *NOT* return the shortest angle.
|
||||
* See `angle_of_signed` below for this.
|
||||
*/
|
||||
template<typename T> [[nodiscard]] detail::AngleRadian<T> angle_of(const detail::Quaternion<T> &q)
|
||||
template<typename T> [[nodiscard]] AngleRadianBase<T> angle_of(const QuaternionBase<T> &q)
|
||||
{
|
||||
BLI_assert(is_unit_scale(q));
|
||||
return T(2) * math::safe_acos(q.w);
|
||||
@ -134,8 +132,7 @@ template<typename T> [[nodiscard]] detail::AngleRadian<T> 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<typename T>
|
||||
[[nodiscard]] detail::AngleRadian<T> angle_of_signed(const detail::Quaternion<T> &q)
|
||||
template<typename T> [[nodiscard]] AngleRadianBase<T> angle_of_signed(const QuaternionBase<T> &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<typename T>
|
||||
* See `angle_of` for more detail.
|
||||
*/
|
||||
template<typename T>
|
||||
[[nodiscard]] detail::AngleRadian<T> angle_between(const detail::Quaternion<T> &a,
|
||||
const detail::Quaternion<T> &b)
|
||||
[[nodiscard]] AngleRadianBase<T> angle_between(const QuaternionBase<T> &a,
|
||||
const QuaternionBase<T> &b)
|
||||
{
|
||||
return angle_of(rotation_between(a, b));
|
||||
}
|
||||
template<typename T>
|
||||
[[nodiscard]] detail::AngleRadian<T> angle_between(const VecBase<T, 3> &a, const VecBase<T, 3> &b)
|
||||
[[nodiscard]] AngleRadianBase<T> angle_between(const VecBase<T, 3> &a, const VecBase<T, 3> &b)
|
||||
{
|
||||
BLI_assert(is_unit_scale(a));
|
||||
BLI_assert(is_unit_scale(b));
|
||||
@ -178,8 +175,8 @@ template<typename T>
|
||||
* See `angle_of_signed` for more detail.
|
||||
*/
|
||||
template<typename T>
|
||||
[[nodiscard]] detail::AngleRadian<T> angle_between_signed(const detail::Quaternion<T> &a,
|
||||
const detail::Quaternion<T> &b)
|
||||
[[nodiscard]] AngleRadianBase<T> angle_between_signed(const QuaternionBase<T> &a,
|
||||
const QuaternionBase<T> &b)
|
||||
{
|
||||
return angle_of_signed(rotation_between(a, b));
|
||||
}
|
||||
@ -191,27 +188,26 @@ template<typename T>
|
||||
* \{ */
|
||||
|
||||
template<typename T, typename RotT>
|
||||
[[nodiscard]] detail::Quaternion<T> rotate(const detail::Quaternion<T> &a, const RotT &b)
|
||||
[[nodiscard]] QuaternionBase<T> rotate(const QuaternionBase<T> &a, const RotT &b)
|
||||
{
|
||||
return a * detail::Quaternion<T>(b);
|
||||
return a * QuaternionBase<T>(b);
|
||||
}
|
||||
|
||||
template<typename T, typename RotT, typename AngleT>
|
||||
[[nodiscard]] detail::AxisAngle<T, AngleT> rotate(const detail::AxisAngle<T, AngleT> &a,
|
||||
const RotT &b)
|
||||
[[nodiscard]] AxisAngleBase<T, AngleT> rotate(const AxisAngleBase<T, AngleT> &a, const RotT &b)
|
||||
{
|
||||
return detail::AxisAngle<T, AngleT>(detail::Quaternion<T>(a) * detail::Quaternion<T>(b));
|
||||
return AxisAngleBase<T, AngleT>(QuaternionBase<T>(a) * QuaternionBase<T>(b));
|
||||
}
|
||||
|
||||
template<typename T, typename RotT>
|
||||
[[nodiscard]] detail::EulerXYZ<T> rotate(const detail::EulerXYZ<T> &a, const RotT &b)
|
||||
[[nodiscard]] EulerXYZBase<T> rotate(const EulerXYZBase<T> &a, const RotT &b)
|
||||
{
|
||||
MatBase<T, 3, 3> tmp = from_rotation<MatBase<T, 3, 3>>(a) * from_rotation<MatBase<T, 3, 3>>(b);
|
||||
return to_euler(tmp);
|
||||
}
|
||||
|
||||
template<typename T, typename RotT>
|
||||
[[nodiscard]] detail::Euler3<T> rotate(const detail::Euler3<T> &a, const RotT &b)
|
||||
[[nodiscard]] Euler3Base<T> rotate(const Euler3Base<T> &a, const RotT &b)
|
||||
{
|
||||
const MatBase<T, 3, 3> tmp = from_rotation<MatBase<T, 3, 3>>(a) *
|
||||
from_rotation<MatBase<T, 3, 3>>(b);
|
||||
@ -219,14 +215,14 @@ template<typename T, typename RotT>
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] detail::Quaternion<T> rotation_between(const detail::Quaternion<T> &a,
|
||||
const detail::Quaternion<T> &b)
|
||||
[[nodiscard]] QuaternionBase<T> rotation_between(const QuaternionBase<T> &a,
|
||||
const QuaternionBase<T> &b)
|
||||
{
|
||||
return invert(a) * b;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] detail::Quaternion<T> from_triangle(const VecBase<T, 3> &v1,
|
||||
[[nodiscard]] QuaternionBase<T> from_triangle(const VecBase<T, 3> &v1,
|
||||
const VecBase<T, 3> &v2,
|
||||
const VecBase<T, 3> &v3,
|
||||
const VecBase<T, 3> &normal)
|
||||
@ -246,7 +242,7 @@ template<typename T>
|
||||
|
||||
T angle = T(-0.5) * math::safe_acos(z_axis.z);
|
||||
T si = math::sin(angle);
|
||||
detail::Quaternion<T> q1(math::cos(angle), nor.x * si, nor.y * si, T(0));
|
||||
QuaternionBase<T> 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,13 +250,13 @@ template<typename T>
|
||||
line = normalize(Vec3T(line.x, line.y, T(0)));
|
||||
|
||||
angle = T(0.5) * math::atan2(line.y, line.x);
|
||||
detail::Quaternion<T> q2(math::cos(angle), 0.0, 0.0, math::sin(angle));
|
||||
QuaternionBase<T> q2(math::cos(angle), 0.0, 0.0, math::sin(angle));
|
||||
|
||||
return q1 * q2;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] detail::Quaternion<T> from_triangle(const VecBase<T, 3> &v1,
|
||||
[[nodiscard]] QuaternionBase<T> from_triangle(const VecBase<T, 3> &v1,
|
||||
const VecBase<T, 3> &v2,
|
||||
const VecBase<T, 3> &v3)
|
||||
{
|
||||
@ -268,7 +264,7 @@ template<typename T>
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] detail::Quaternion<T> from_vector(const VecBase<T, 3> &vector,
|
||||
[[nodiscard]] QuaternionBase<T> from_vector(const VecBase<T, 3> &vector,
|
||||
const AxisSigned track_flag,
|
||||
const Axis up_flag)
|
||||
{
|
||||
@ -279,7 +275,7 @@ template<typename T>
|
||||
const T vec_len = length(vector);
|
||||
|
||||
if (UNLIKELY(vec_len == 0.0f)) {
|
||||
return detail::Quaternion<T>::identity();
|
||||
return QuaternionBase<T>::identity();
|
||||
}
|
||||
|
||||
const Axis axis = track_flag.axis();
|
||||
@ -313,8 +309,8 @@ template<typename T>
|
||||
* 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<T> q1 = to_quaternion(
|
||||
detail::AxisAngle<T, detail::AngleRadian<T>>(rotation_axis, rotation_angle));
|
||||
const QuaternionBase<T> q1 = to_quaternion(
|
||||
AxisAngleBase<T, AngleRadianBase<T>>(rotation_axis, rotation_angle));
|
||||
|
||||
if (axis == up_flag) {
|
||||
/* Nothing else to do. */
|
||||
@ -341,27 +337,26 @@ template<typename T>
|
||||
projected = -projected;
|
||||
}
|
||||
|
||||
const detail::AngleCartesian<T> angle(projected.x, projected.y);
|
||||
const detail::AngleCartesian<T> half_angle = angle / T(2);
|
||||
const AngleCartesianBase<T> angle(projected.x, projected.y);
|
||||
const AngleCartesianBase<T> half_angle = angle / T(2);
|
||||
|
||||
const detail::Quaternion<T> q2(Vec4T(half_angle.cos(), vec * (half_angle.sin() / vec_len)));
|
||||
const QuaternionBase<T> q2(Vec4T(half_angle.cos(), vec * (half_angle.sin() / vec_len)));
|
||||
|
||||
return q2 * q1;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] detail::Quaternion<T> from_tracking(AxisSigned forward_axis, Axis up_axis)
|
||||
[[nodiscard]] QuaternionBase<T> 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<T>(
|
||||
return QuaternionBase<T>(
|
||||
rotation_between(from_orthonormal_axes(AxisSigned::Z_POS, AxisSigned::Y_POS),
|
||||
from_orthonormal_axes(forward_axis, AxisSigned(up_axis))));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] MatBase<T, 3, 3> to_gimbal_axis(const detail::Euler3<T> &rotation)
|
||||
template<typename T> [[nodiscard]] MatBase<T, 3, 3> to_gimbal_axis(const Euler3Base<T> &rotation)
|
||||
{
|
||||
using Mat3T = MatBase<T, 3, 3>;
|
||||
using Vec3T = VecBase<T, 3>;
|
||||
@ -373,7 +368,7 @@ template<typename T>
|
||||
/* First axis is local. */
|
||||
result[i_index] = from_rotation<Mat3T>(rotation)[i_index];
|
||||
/* Second axis is local minus first rotation. */
|
||||
detail::Euler3<T> tmp_rot = rotation;
|
||||
Euler3Base<T> tmp_rot = rotation;
|
||||
tmp_rot.i() = T(0);
|
||||
result[j_index] = from_rotation<Mat3T>(tmp_rot)[j_index];
|
||||
/* Last axis is global. */
|
||||
@ -393,7 +388,7 @@ template<typename T>
|
||||
* Creates a quaternion from an axis triple.
|
||||
* This is faster and more precise than converting from another representation.
|
||||
*/
|
||||
template<typename T> detail::Quaternion<T> to_quaternion(const CartesianBasis &rotation)
|
||||
template<typename T> QuaternionBase<T> to_quaternion(const CartesianBasis &rotation)
|
||||
{
|
||||
/**
|
||||
* There are only 6 * 4 = 24 possible valid orthonormal orientations.
|
||||
@ -406,53 +401,53 @@ template<typename T> detail::Quaternion<T> to_quaternion(const CartesianBasis &r
|
||||
|
||||
switch (map(rotation.axes.x, rotation.axes.y, rotation.axes.z)) {
|
||||
default:
|
||||
return detail::Quaternion<T>::identity();
|
||||
return QuaternionBase<T>::identity();
|
||||
case map(AxisSigned::Z_POS, AxisSigned::X_POS, AxisSigned::Y_POS):
|
||||
return detail::Quaternion<T>{T(0.5), T(-0.5), T(-0.5), T(-0.5)};
|
||||
return QuaternionBase<T>{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>{T(M_SQRT1_2), T(0), T(0), T(-M_SQRT1_2)};
|
||||
return QuaternionBase<T>{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>{T(0.5), T(0.5), T(0.5), T(-0.5)};
|
||||
return QuaternionBase<T>{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>{T(0), T(M_SQRT1_2), T(M_SQRT1_2), T(0)};
|
||||
return QuaternionBase<T>{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>{T(M_SQRT1_2), T(0), T(M_SQRT1_2), T(0)};
|
||||
return QuaternionBase<T>{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>{T(M_SQRT1_2), T(0), T(-M_SQRT1_2), T(0)};
|
||||
return QuaternionBase<T>{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>{T(0), T(0), T(1), T(0)};
|
||||
return QuaternionBase<T>{T(0), T(0), T(1), T(0)};
|
||||
case map(AxisSigned::Y_POS, AxisSigned::Z_POS, AxisSigned::X_POS):
|
||||
return detail::Quaternion<T>{T(0.5), T(0.5), T(0.5), T(0.5)};
|
||||
return QuaternionBase<T>{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>{T(0), T(0), T(M_SQRT1_2), T(M_SQRT1_2)};
|
||||
return QuaternionBase<T>{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>{T(0.5), T(0.5), T(-0.5), T(-0.5)};
|
||||
return QuaternionBase<T>{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>{T(M_SQRT1_2), T(M_SQRT1_2), T(0), T(0)};
|
||||
return QuaternionBase<T>{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>{T(0.5), T(-0.5), T(0.5), T(0.5)};
|
||||
return QuaternionBase<T>{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>{T(M_SQRT1_2), T(0), T(0), T(M_SQRT1_2)};
|
||||
return QuaternionBase<T>{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>{T(0.5), T(0.5), T(-0.5), T(0.5)};
|
||||
return QuaternionBase<T>{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>{T(0), T(-M_SQRT1_2), T(M_SQRT1_2), T(0)};
|
||||
return QuaternionBase<T>{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>{T(0), T(M_SQRT1_2), T(0), T(M_SQRT1_2)};
|
||||
return QuaternionBase<T>{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>{T(0), T(0), T(0), T(1)};
|
||||
return QuaternionBase<T>{T(0), T(0), T(0), T(1)};
|
||||
case map(AxisSigned::Z_NEG, AxisSigned::Y_NEG, AxisSigned::X_NEG):
|
||||
return detail::Quaternion<T>{T(0), T(-M_SQRT1_2), T(0), T(M_SQRT1_2)};
|
||||
return QuaternionBase<T>{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>{T(0), T(1), T(0), T(0)};
|
||||
return QuaternionBase<T>{T(0), T(1), T(0), T(0)};
|
||||
case map(AxisSigned::Y_NEG, AxisSigned::Z_NEG, AxisSigned::X_POS):
|
||||
return detail::Quaternion<T>{T(0.5), T(-0.5), T(0.5), T(-0.5)};
|
||||
return QuaternionBase<T>{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>{T(M_SQRT1_2), T(-M_SQRT1_2), T(0), T(0)};
|
||||
return QuaternionBase<T>{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>{T(0.5), T(-0.5), T(-0.5), T(0.5)};
|
||||
return QuaternionBase<T>{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>{T(0), T(0), T(-M_SQRT1_2), T(M_SQRT1_2)};
|
||||
return QuaternionBase<T>{T(0), T(0), T(-M_SQRT1_2), T(M_SQRT1_2)};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -339,9 +339,9 @@ MatBase<T, 3, 3> interpolate(const MatBase<T, 3, 3> &A, const MatBase<T, 3, 3> &
|
||||
P_B = -P_B;
|
||||
}
|
||||
|
||||
detail::Quaternion<T> quat_A = math::to_quaternion(normalize(U_A));
|
||||
detail::Quaternion<T> quat_B = math::to_quaternion(normalize(U_B));
|
||||
detail::Quaternion<T> quat = math::interpolate(quat_A, quat_B, t);
|
||||
QuaternionBase<T> quat_A = math::to_quaternion(normalize(U_A));
|
||||
QuaternionBase<T> quat_B = math::to_quaternion(normalize(U_B));
|
||||
QuaternionBase<T> quat = math::interpolate(quat_A, quat_B, t);
|
||||
Mat3T U = from_rotation<Mat3T>(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<typename T>
|
||||
MatBase<T, 3, 3> interpolate_fast(const MatBase<T, 3, 3> &a, const MatBase<T, 3, 3> &b, T t)
|
||||
{
|
||||
using QuaternionT = detail::Quaternion<T>;
|
||||
using QuaternionT = QuaternionBase<T>;
|
||||
using Vec3T = typename MatBase<T, 3, 3>::vec3_type;
|
||||
|
||||
Vec3T a_scale, b_scale;
|
||||
@ -391,7 +391,7 @@ template double3x3 interpolate_fast(const double3x3 &a, const double3x3 &b, doub
|
||||
template<typename T>
|
||||
MatBase<T, 4, 4> interpolate_fast(const MatBase<T, 4, 4> &a, const MatBase<T, 4, 4> &b, T t)
|
||||
{
|
||||
using QuaternionT = detail::Quaternion<T>;
|
||||
using QuaternionT = QuaternionBase<T>;
|
||||
using Vec3T = typename MatBase<T, 3, 3>::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<float> &eul1,
|
||||
detail::Euler3<float> &eul2);
|
||||
Euler3Base<float> &eul1,
|
||||
Euler3Base<float> &eul2);
|
||||
template void normalized_to_eul2(const float3x3 &mat,
|
||||
detail::EulerXYZ<float> &eul1,
|
||||
detail::EulerXYZ<float> &eul2);
|
||||
EulerXYZBase<float> &eul1,
|
||||
EulerXYZBase<float> &eul2);
|
||||
template void normalized_to_eul2(const double3x3 &mat,
|
||||
detail::EulerXYZ<double> &eul1,
|
||||
detail::EulerXYZ<double> &eul2);
|
||||
EulerXYZBase<double> &eul1,
|
||||
EulerXYZBase<double> &eul2);
|
||||
|
||||
template detail::Quaternion<float> normalized_to_quat_with_checks(const float3x3 &mat);
|
||||
template detail::Quaternion<double> normalized_to_quat_with_checks(const double3x3 &mat);
|
||||
template QuaternionBase<float> normalized_to_quat_with_checks(const float3x3 &mat);
|
||||
template QuaternionBase<double> normalized_to_quat_with_checks(const double3x3 &mat);
|
||||
|
||||
template MatBase<float, 2, 2> from_rotation(const detail::AngleRadian<float> &rotation);
|
||||
template MatBase<float, 3, 3> from_rotation(const detail::AngleRadian<float> &rotation);
|
||||
template MatBase<float, 3, 3> from_rotation(const detail::EulerXYZ<float> &rotation);
|
||||
template MatBase<float, 4, 4> from_rotation(const detail::EulerXYZ<float> &rotation);
|
||||
template MatBase<float, 3, 3> from_rotation(const detail::Euler3<float> &rotation);
|
||||
template MatBase<float, 4, 4> from_rotation(const detail::Euler3<float> &rotation);
|
||||
template MatBase<float, 3, 3> from_rotation(const detail::Quaternion<float> &rotation);
|
||||
template MatBase<float, 4, 4> from_rotation(const detail::Quaternion<float> &rotation);
|
||||
template MatBase<float, 3, 3> from_rotation(const math::AxisAngle &rotation);
|
||||
template MatBase<float, 4, 4> from_rotation(const math::AxisAngle &rotation);
|
||||
template MatBase<float, 3, 3> from_rotation(const math::AxisAngleCartesian &rotation);
|
||||
template MatBase<float, 4, 4> from_rotation(const math::AxisAngleCartesian &rotation);
|
||||
template MatBase<float, 2, 2> from_rotation(const AngleRadian &rotation);
|
||||
template MatBase<float, 3, 3> from_rotation(const AngleRadian &rotation);
|
||||
template MatBase<float, 3, 3> from_rotation(const EulerXYZ &rotation);
|
||||
template MatBase<float, 4, 4> from_rotation(const EulerXYZ &rotation);
|
||||
template MatBase<float, 3, 3> from_rotation(const Euler3 &rotation);
|
||||
template MatBase<float, 4, 4> from_rotation(const Euler3 &rotation);
|
||||
template MatBase<float, 3, 3> from_rotation(const Quaternion &rotation);
|
||||
template MatBase<float, 4, 4> from_rotation(const Quaternion &rotation);
|
||||
template MatBase<float, 3, 3> from_rotation(const AxisAngle &rotation);
|
||||
template MatBase<float, 4, 4> from_rotation(const AxisAngle &rotation);
|
||||
template MatBase<float, 3, 3> from_rotation(const AxisAngleCartesian &rotation);
|
||||
template MatBase<float, 4, 4> from_rotation(const AxisAngleCartesian &rotation);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user