Changeset View
Standalone View
source/blender/blenlib/BLI_math_rotation_types.hh
- This file was added.
| /* SPDX-License-Identifier: GPL-2.0-or-later */ | ||||||||||
| #pragma once | ||||||||||
| /** \file | ||||||||||
| * \ingroup bli | ||||||||||
| */ | ||||||||||
| #include "BLI_math_base.hh" | ||||||||||
| #include "BLI_math_vec_types.hh" | ||||||||||
| namespace blender::math { | ||||||||||
| namespace detail { | ||||||||||
| /** | ||||||||||
| * Rotation Types | ||||||||||
| * | ||||||||||
| * It gives more semantic informations allowing overloaded functions based on the rotation | ||||||||||
| * type. It also prevent implicit cast from rotation to vector types. | ||||||||||
HooglyBoogly: >These are wrappers around the vector types.
Not quite true anymore as far as I can see | ||||||||||
| */ | ||||||||||
Done Inline Actions
HooglyBoogly: | ||||||||||
| /* Forward declaration. */ | ||||||||||
| template<typename T> struct AxisAngle; | ||||||||||
| template<typename T> struct Quaternion; | ||||||||||
| template<typename T> struct EulerXYZ { | ||||||||||
| T x, y, z; | ||||||||||
| EulerXYZ() = default; | ||||||||||
| EulerXYZ(const T &x, const T &y, const T &z) | ||||||||||
| { | ||||||||||
| this->x = x; | ||||||||||
| this->y = y; | ||||||||||
| this->z = z; | ||||||||||
| } | ||||||||||
| EulerXYZ(const vec_base<T, 3> &vec) : EulerXYZ(UNPACK3(vec)){}; | ||||||||||
| /** Static functions. */ | ||||||||||
| static EulerXYZ identity() | ||||||||||
| { | ||||||||||
| return {0, 0, 0}; | ||||||||||
| } | ||||||||||
| /** Conversions. */ | ||||||||||
| explicit operator vec_base<T, 3>() const | ||||||||||
| { | ||||||||||
| return {this->x, this->y, this->z}; | ||||||||||
| } | ||||||||||
| explicit operator AxisAngle<T>() const; | ||||||||||
| explicit operator Quaternion<T>() const; | ||||||||||
| /** Operators. */ | ||||||||||
| friend std::ostream &operator<<(std::ostream &stream, const EulerXYZ &rot) | ||||||||||
| { | ||||||||||
| return stream << "EulerXYZ" << static_cast<vec_base<T, 3>>(rot); | ||||||||||
| } | ||||||||||
| }; | ||||||||||
| template<typename T = float> struct Quaternion { | ||||||||||
| T x, y, z, w; | ||||||||||
| Quaternion() = default; | ||||||||||
| Quaternion(const T &x, const T &y, const T &z, const T &w) | ||||||||||
| { | ||||||||||
| this->x = x; | ||||||||||
| this->y = y; | ||||||||||
| this->z = z; | ||||||||||
| this->w = w; | ||||||||||
| } | ||||||||||
| Quaternion(const vec_base<T, 4> &vec) : Quaternion(UNPACK4(vec)){}; | ||||||||||
| /** Static functions. */ | ||||||||||
| static Quaternion identity() | ||||||||||
| { | ||||||||||
| return {1, 0, 0, 0}; | ||||||||||
| } | ||||||||||
| /** Conversions. */ | ||||||||||
| explicit operator vec_base<T, 4>() const | ||||||||||
| { | ||||||||||
| return {this->x, this->y, this->z, this->w}; | ||||||||||
| } | ||||||||||
| explicit operator EulerXYZ<T>() const; | ||||||||||
| explicit operator AxisAngle<T>() const; | ||||||||||
| /** Operators. */ | ||||||||||
| const T &operator[](int i) const | ||||||||||
| { | ||||||||||
| BLI_assert(i >= 0 && i < 4); | ||||||||||
| return (&this->x)[i]; | ||||||||||
| } | ||||||||||
| friend std::ostream &operator<<(std::ostream &stream, const Quaternion &rot) | ||||||||||
| { | ||||||||||
| return stream << "Quaternion" << static_cast<vec_base<T, 4>>(rot); | ||||||||||
| } | ||||||||||
| }; | ||||||||||
| template<typename T> struct AxisAngle { | ||||||||||
| using vec3_type = vec_base<T, 3>; | ||||||||||
| protected: | ||||||||||
| vec3_type axis_ = {0, 1, 0}; | ||||||||||
| /** Store cosine and sine so rotation is cheaper and doesn't require atan2. */ | ||||||||||
| T angle_cos_ = 1; | ||||||||||
| T angle_sin_ = 0; | ||||||||||
Done Inline ActionsI don't really like the fact that we store the cos and sin here as well. It can help sometimes and be worse in others (when it is computed even though it's not needed). I think this should be passed to functions separately or there should be something like struct AxisAngleWithSinCos that contains everything. JacquesLucke: I don't really like the fact that we store the cos and sin here as well. It can help sometimes… | ||||||||||
Done Inline ActionsI am not against changing it but I would like to express my opinion.
These being protected members, makes it implementation detail and allows for changes to be made later if the case arise that we really need these. fclem: I am not against changing it but I would like to express my opinion.
- I could not find a… | ||||||||||
| /** | ||||||||||
| * Source angle for interpolation. | ||||||||||
| * It might not be computed on creation, so the getter ensures it is updated. | ||||||||||
| */ | ||||||||||
| T angle_ = 0; | ||||||||||
Done Inline Actions
HooglyBoogly: | ||||||||||
| /** | ||||||||||
| * A defaulted constructor would cause zero initialization instead of default initialization, | ||||||||||
| * and not call the default member initializers. | ||||||||||
Done Inline ActionsI guess this is not defaulted to avoid 0 initalization (e.g. when constructing like T())? Worth adding a comment on, for example: "A defaulted constructor would cause zero initialization instead of default initialization, and not call the default member initializers." Severin: I guess this is not defaulted to avoid 0 initalization (e.g. when constructing like `T()`)? | ||||||||||
Done Inline ActionsAdded a comment. Note that this is only exposed for internal usage like for indentity(), and AxisAngleNormalized. fclem: Added a comment. Note that this is only exposed for internal usage like for `indentity()`, and… | ||||||||||
| */ | ||||||||||
| explicit AxisAngle(){}; | ||||||||||
| public: | ||||||||||
| /** | ||||||||||
| * Create a rotation from an axis and an angle. | ||||||||||
| * \note `axis` does not have to be normalized. | ||||||||||
| * Use `AxisAngleNormalized` instead to skip normalization cost. | ||||||||||
| */ | ||||||||||
| AxisAngle(const vec3_type &axis, T angle); | ||||||||||
| /** | ||||||||||
| * Create a rotation from 2 normalized vectors. | ||||||||||
| * \note `from` and `to` must be normalized. | ||||||||||
| */ | ||||||||||
| AxisAngle(const vec3_type &from, const vec3_type &to); | ||||||||||
| /** Static functions. */ | ||||||||||
| static AxisAngle<T> identity() | ||||||||||
| { | ||||||||||
| return AxisAngle<T>(); | ||||||||||
| } | ||||||||||
| /** Getters. */ | ||||||||||
| const vec3_type &axis() const | ||||||||||
| { | ||||||||||
| return axis_; | ||||||||||
| } | ||||||||||
| const T &angle() const | ||||||||||
| { | ||||||||||
| if (UNLIKELY(angle_ == T(0) && angle_cos_ != T(1))) { | ||||||||||
| /* Angle wasn't computed by constructor. */ | ||||||||||
| const_cast<AxisAngle *>(this)->angle_ = math::atan2(angle_sin_, angle_cos_); | ||||||||||
| } | ||||||||||
| return angle_; | ||||||||||
| } | ||||||||||
| const T &angle_cos() const | ||||||||||
| { | ||||||||||
| return angle_cos_; | ||||||||||
| } | ||||||||||
| const T &angle_sin() const | ||||||||||
| { | ||||||||||
| return angle_sin_; | ||||||||||
| } | ||||||||||
| /** Conversions. */ | ||||||||||
| explicit operator Quaternion<T>() const; | ||||||||||
| explicit operator EulerXYZ<T>() const; | ||||||||||
| /** Operators. */ | ||||||||||
| friend bool operator==(const AxisAngle &a, const AxisAngle &b) | ||||||||||
| { | ||||||||||
| return (a.axis == b.axis) && (a.angle == b.angle); | ||||||||||
| } | ||||||||||
| friend bool operator!=(const AxisAngle &a, const AxisAngle &b) | ||||||||||
| { | ||||||||||
| return (a != b); | ||||||||||
| } | ||||||||||
| friend std::ostream &operator<<(std::ostream &stream, const AxisAngle &rot) | ||||||||||
| { | ||||||||||
| return stream << "AxisAngle(axis=" << rot.axis << ", angle=" << rot.angle << ")"; | ||||||||||
| } | ||||||||||
| }; | ||||||||||
| /** | ||||||||||
| * A version of AxisAngle that expects axis to be already normalized. | ||||||||||
| * Implicitly cast back to AxisAngle. | ||||||||||
| */ | ||||||||||
| template<typename T> struct AxisAngleNormalized : public AxisAngle<T> { | ||||||||||
| AxisAngleNormalized(const vec_base<T, 3> &axis, T angle); | ||||||||||
| operator AxisAngle<T>() const | ||||||||||
| { | ||||||||||
| return *this; | ||||||||||
| } | ||||||||||
| }; | ||||||||||
| /** | ||||||||||
| * Intermediate Types. | ||||||||||
| * | ||||||||||
| * Some functions need to have higher precision than standard floats for some operations. | ||||||||||
| */ | ||||||||||
| template<typename T> struct TypeTraits { | ||||||||||
| using DoublePrecision = T; | ||||||||||
Done Inline ActionsIntermediateType is quite generic. Maybe call it DoublePrecision or so. JacquesLucke: `IntermediateType` is quite generic. Maybe call it `DoublePrecision` or so. | ||||||||||
| }; | ||||||||||
| template<> struct TypeTraits<float> { | ||||||||||
| using DoublePrecision = double; | ||||||||||
| }; | ||||||||||
| }; // namespace detail | ||||||||||
| template<typename U> struct AssertUnitEpsilon<detail::Quaternion<U>> { | ||||||||||
| static constexpr U value = AssertUnitEpsilon<U>::value * 10; | ||||||||||
| }; | ||||||||||
| /* Most common used types. */ | ||||||||||
| using EulerXYZ = math::detail::EulerXYZ<float>; | ||||||||||
| using Quaternion = math::detail::Quaternion<float>; | ||||||||||
| using AxisAngle = math::detail::AxisAngle<float>; | ||||||||||
| using AxisAngleNormalized = math::detail::AxisAngleNormalized<float>; | ||||||||||
| } // namespace blender::math | ||||||||||
| /** \} */ | ||||||||||
Not quite true anymore as far as I can see