Move Vectormath main
C++20 game and graphics mathematics
Loading...
Searching...
No Matches
TrsTransform3.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <cmath>
5#include <cstdint>
6#include <optional>
7#include <type_traits>
8
11
12namespace mv::math
13{
14 template <typename T>
15 requires std::is_floating_point_v<T>
17 {
18 public:
19 using Component = T;
20
22
26 Translation_(translation), Rotation_(rotation), Scale_(scale)
27 {
28 }
29
31 {
32 return TrsTransform3();
33 }
34
36 {
37 return Translation_;
38 }
39
41 {
42 return Rotation_;
43 }
44
46 {
47 return Scale_;
48 }
49
51 {
52 // A TRS value applies scale, then rotation, then translation.
53 // This is the row-vector transpose of the standard Graphics Gems
54 // affine construction and is cross-checked against GLM's MIT
55 // scale/rotation/translation composition.
56 const Mat3<T> rotation = Mat3<T>::FromRotation(Rotation_);
58 rotation.Row(0U) * Scale_.X(), rotation.Row(1U) * Scale_.Y(),
59 rotation.Row(2U) * Scale_.Z(), Translation_);
60 }
61
62 [[nodiscard]] friend bool operator==(
63 const TrsTransform3& left, const TrsTransform3& right) noexcept
64 {
65 return left.Translation_ == right.Translation_ &&
66 left.Rotation_ == right.Rotation_ &&
67 left.Scale_ == right.Scale_;
68 }
69
70 private:
71 Vec3<T> Translation_{};
72 Rotation3<T> Rotation_{};
73 Vec3<T> Scale_{T(1), T(1), T(1)};
74 };
75
78
79 enum class TrsDecompositionStatus : std::uint8_t
80 {
81 Success,
83 Sheared,
85 };
86
87 template <typename T>
88 requires std::is_floating_point_v<T>
90 {
92 std::optional<TrsTransform3<T>> Transform;
94
95 [[nodiscard]] explicit operator bool() const noexcept
96 {
98 }
99 };
100
103
104 template <typename T>
107 T orthogonalityTolerance = static_cast<T>(1.0e-5)) noexcept
108 {
109 const Vec3<T>& axisX = transform.AxisX();
110 const Vec3<T>& axisY = transform.AxisY();
111 const Vec3<T>& axisZ = transform.AxisZ();
112 T scaleX = Length(axisX);
113 T scaleY = Length(axisY);
114 T scaleZ = Length(axisZ);
115 if (!(scaleX > T(0)) || !(scaleY > T(0)) || !(scaleZ > T(0)))
116 {
117 return {TrsDecompositionStatus::Singular, std::nullopt,
118 Vec3<T>::Zero()};
119 }
120 if (!std::isfinite(scaleX) || !std::isfinite(scaleY) ||
121 !std::isfinite(scaleZ))
122 {
123 return {TrsDecompositionStatus::NumericalFailure, std::nullopt,
124 Vec3<T>::Zero()};
125 }
126
133 const T tolerance = std::abs(orthogonalityTolerance);
134 if (std::abs(shear.X()) > tolerance ||
135 std::abs(shear.Y()) > tolerance || std::abs(shear.Z()) > tolerance)
136 {
137 return {TrsDecompositionStatus::Sheared, std::nullopt, shear};
138 }
139
140 // A unit quaternion represents only proper rotations. Preserve an
141 // affine reflection by assigning its sign to the X scale before
142 // extracting the proper orthonormal basis. This is the deterministic
143 // Move policy; equivalent decompositions with another negative axis
144 // are intentionally not produced.
146 {
148 scaleX = -scaleX;
149 }
150
154 if (!directionX || !directionY || !directionZ)
155 {
156 return {TrsDecompositionStatus::NumericalFailure, std::nullopt,
157 shear};
158 }
161 if (!rotation)
162 {
163 return {TrsDecompositionStatus::NumericalFailure, std::nullopt,
164 shear};
165 }
166
168 TrsTransform3<T>(transform.Translation(), *rotation,
170 shear};
171 }
172
173 template <typename T>
174 [[nodiscard]] inline std::optional<TrsTransform3<T>> TryToTrs(
176 T orthogonalityTolerance = static_cast<T>(1.0e-5)) noexcept
177 {
179 }
180} // namespace mv::math
181
182static_assert(std::is_trivially_copyable_v<mv::math::TrsTransform3f>);
183static_assert(std::is_standard_layout_v<mv::math::TrsTransform3f>);
184static_assert(std::is_trivially_copyable_v<mv::math::TrsTransform3d>);
185static_assert(std::is_standard_layout_v<mv::math::TrsTransform3d>);
static std::optional< Direction3 > TryFrom(const Vec3< T > &value) noexcept
static Mat3 FromRotation(const Rotation3< T > &rotation) noexcept
Definition Mat3.hpp:65
static std::optional< Rotation3 > TryFromOrthonormalAxes(const Direction3< T > &axisX, const Direction3< T > &axisY, const Direction3< T > &axisZ, T orthogonalityTolerance=static_cast< T >(1.0e-5)) noexcept
TrsTransform3() noexcept=default
friend bool operator==(const TrsTransform3 &left, const TrsTransform3 &right) noexcept
const Vec3< T > & Translation() const noexcept
static TrsTransform3 Identity() noexcept
const Rotation3< T > & Rotation() const noexcept
const Vec3< T > & Scale() const noexcept
AffineTransform3< T > ToAffine() const noexcept
static Vec3 Zero() noexcept
Definition Vec3.hpp:78
constexpr T Dot(const Quat< T > &left, const Quat< T > &right) noexcept
Definition Quat.hpp:102
Vec3< T > Cross(const Vec3< T > &left, const Vec3< T > &right) noexcept
Definition Vec3.hpp:367
TrsDecomposition3< T > DecomposeTrs(const AffineTransform3< T > &transform, T orthogonalityTolerance=static_cast< T >(1.0e-5)) noexcept
std::optional< TrsTransform3< T > > TryToTrs(const AffineTransform3< T > &transform, T orthogonalityTolerance=static_cast< T >(1.0e-5)) noexcept
T Length(const Quat< T > &value) noexcept
Definition Quat.hpp:116
TrsDecompositionStatus Status
std::optional< TrsTransform3< T > > Transform