MeshLib
 
Loading...
Searching...
No Matches
MRMesh/MRMatrix3.h
Go to the documentation of this file.
1#pragma once
2
3#include "MRVector3.h"
4#include "MRConstants.h"
5
6namespace MR
7{
8
11template <typename T>
12struct Matrix3
13{
14 using ValueType = T;
16
18 Vector3<T> x{ 1, 0, 0 };
19 Vector3<T> y{ 0, 1, 0 };
20 Vector3<T> z{ 0, 0, 1 };
21
22 constexpr Matrix3() noexcept = default;
24 constexpr Matrix3( const Vector3<T> & x, const Vector3<T> & y, const Vector3<T> & z ) : x( x ), y( y ), z( z ) { }
25 template <typename U>
26 constexpr explicit Matrix3( const Matrix3<U> & m ) : x( m.x ), y( m.y ), z( m.z ) { }
27 static constexpr Matrix3 zero() noexcept { return Matrix3( Vector3<T>(), Vector3<T>(), Vector3<T>() ); }
28 static constexpr Matrix3 identity() noexcept { return Matrix3(); }
30 static constexpr Matrix3 scale( T s ) noexcept { return Matrix3( { s, T(0), T(0) }, { T(0), s, T(0) }, { T(0), T(0), s } ); }
32 static constexpr Matrix3 scale( T sx, T sy, T sz ) noexcept { return Matrix3( { sx, T(0), T(0) }, { T(0), sy, T(0) }, { T(0), T(0), sz } ); }
33 static constexpr Matrix3 scale( const Vector3<T> & s ) noexcept { return Matrix3( { s.x, T(0), T(0) }, { T(0), s.y, T(0) }, { T(0), T(0), s.z } ); }
35 static constexpr Matrix3 rotation( const Vector3<T> & axis, T angle ) noexcept MR_REQUIRES_IF_SUPPORTED( std::floating_point<T> );
37 static constexpr Matrix3 rotation( const Vector3<T> & from, const Vector3<T> & to ) noexcept MR_REQUIRES_IF_SUPPORTED( std::floating_point<T> );
40 static constexpr Matrix3 rotationFromEuler( const Vector3<T> & eulerAngles ) noexcept MR_REQUIRES_IF_SUPPORTED( std::is_floating_point_v<T> );
42 static constexpr Matrix3 approximateLinearRotationMatrixFromEuler( const Vector3<T> & eulerAngles ) noexcept MR_REQUIRES_IF_SUPPORTED( std::is_floating_point_v<T> );
44 static constexpr Matrix3 fromRows( const Vector3<T> & x, const Vector3<T> & y, const Vector3<T> & z ) noexcept { return Matrix3( x, y, z ); }
47 static constexpr Matrix3 fromColumns( const Vector3<T> & x, const Vector3<T> & y, const Vector3<T> & z ) noexcept { return Matrix3( x, y, z ).transposed(); }
48
50 constexpr const Vector3<T> & operator []( int row ) const noexcept { return *( &x + row ); }
51 constexpr Vector3<T> & operator []( int row ) noexcept { return *( &x + row ); }
52
54 constexpr Vector3<T> col( int i ) const noexcept { return { x[i], y[i], z[i] }; }
55
57 constexpr T trace() const noexcept { return x.x + y.y + z.z; }
59 constexpr T normSq() const noexcept { return x.lengthSq() + y.lengthSq() + z.lengthSq(); }
60 constexpr auto norm() const noexcept
61 {
62 // Calling `sqrt` this way to hopefully support boost.multiprecision numbers.
63 // Returning `auto` to not break on integral types.
64 using std::sqrt;
65 return sqrt( normSq() );
66 }
68 constexpr T det() const noexcept;
70 constexpr Matrix3<T> inverse() const noexcept MR_REQUIRES_IF_SUPPORTED( !std::is_integral_v<T> );
72 constexpr Matrix3<T> transposed() const noexcept;
74 constexpr Vector3<T> toEulerAngles() const noexcept MR_REQUIRES_IF_SUPPORTED( std::is_floating_point_v<T> );
75
76 struct QR
77 {
79 };
81 QR qr() const noexcept MR_REQUIRES_IF_SUPPORTED( !std::is_integral_v<T> );
82
83 Matrix3 & operator +=( const Matrix3<T> & b ) { x += b.x; y += b.y; z += b.z; return * this; }
84 Matrix3 & operator -=( const Matrix3<T> & b ) { x -= b.x; y -= b.y; z -= b.z; return * this; }
85 Matrix3 & operator *=( T b ) { x *= b; y *= b; z *= b; return * this; }
87 {
88 if constexpr ( std::is_integral_v<T> )
89 { x /= b; y /= b; z /= b; return * this; }
90 else
91 return *this *= ( 1 / b );
92 }
93};
94
97
99template <typename T>
100inline Vector3<T> operator *( const Matrix3<T> & a, const Vector3<T> & b )
101{
102 return { dot( a.x, b ), dot( a.y, b ), dot( a.z, b ) };
103}
104
106template <typename T>
107inline T dot( const Matrix3<T> & a, const Matrix3<T> & b )
108{
109 return dot( a.x, b.x ) + dot( a.y, b.y ) + dot( a.z, b.z );
110}
111
113template <typename T>
114inline Matrix3<T> operator *( const Matrix3<T> & a, const Matrix3<T> & b )
115{
116 Matrix3<T> res;
117 for ( int i = 0; i < 3; ++i )
118 for ( int j = 0; j < 3; ++j )
119 res[i][j] = dot( a[i], b.col(j) );
120 return res;
121}
122
124template <typename T>
125inline Matrix3<T> outer( const Vector3<T> & a, const Vector3<T> & b )
126{
127 return { a.x * b, a.y * b, a.z * b };
128}
129
130template <typename T>
131inline bool operator ==( const Matrix3<T> & a, const Matrix3<T> & b )
132 { return a.x == b.x && a.y == b.y && a.z == b.z; }
133
134template <typename T>
135inline bool operator !=( const Matrix3<T> & a, const Matrix3<T> & b )
136 { return !( a == b ); }
137
138template <typename T>
139inline Matrix3<T> operator +( const Matrix3<T> & a, const Matrix3<T> & b )
140 { return { a.x + b.x, a.y + b.y, a.z + b.z }; }
141
142template <typename T>
143inline Matrix3<T> operator -( const Matrix3<T> & a, const Matrix3<T> & b )
144 { return { a.x - b.x, a.y - b.y, a.z - b.z }; }
145
146template <typename T>
147inline Matrix3<T> operator *( T a, const Matrix3<T> & b )
148 { return { a * b.x, a * b.y, a * b.z }; }
149
150template <typename T>
151inline Matrix3<T> operator *( const Matrix3<T> & b, T a )
152 { return { a * b.x, a * b.y, a * b.z }; }
153
154template <typename T>
155inline Matrix3<T> operator /( Matrix3<T> b, T a )
156 { b /= a; return b; }
157
158template <typename T>
159constexpr Matrix3<T> Matrix3<T>::rotation( const Vector3<T> & axis, T angle ) noexcept MR_REQUIRES_IF_SUPPORTED( std::floating_point<T> )
160{
161 // https://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle
162 auto u = axis.normalized();
163 T c = cos( angle );
164 T oc = 1 - c;
165 T s = sin( angle );
166 return {
167 { c + u.x * u.x * oc, u.x * u.y * oc - u.z * s, u.x * u.z * oc + u.y * s },
168 { u.y * u.x * oc + u.z * s, c + u.y * u.y * oc, u.y * u.z * oc - u.x * s },
169 { u.z * u.x * oc - u.y * s, u.z * u.y * oc + u.x * s, c + u.z * u.z * oc }
170 };
171}
172
173template <typename T>
174constexpr Matrix3<T> Matrix3<T>::rotation( const Vector3<T> & from, const Vector3<T> & to ) noexcept MR_REQUIRES_IF_SUPPORTED( std::floating_point<T> )
175{
176 auto axis = cross( from, to );
177 if ( axis.lengthSq() > 0 )
178 return rotation( axis, angle( from, to ) );
179 if ( dot( from, to ) >= 0 )
180 return {}; // identity matrix
181 return rotation( cross( from, from.furthestBasisVector() ), T( PI ) );
182}
183
184template <typename T>
185constexpr Matrix3<T> Matrix3<T>::rotationFromEuler( const Vector3<T> & eulerAngles ) noexcept MR_REQUIRES_IF_SUPPORTED( std::is_floating_point_v<T> )
186{
187 // https://www.geometrictools.com/Documentation/EulerAngles.pdf (36)
188 const auto cx = std::cos( eulerAngles.x );
189 const auto cy = std::cos( eulerAngles.y );
190 const auto cz = std::cos( eulerAngles.z );
191 const auto sx = std::sin( eulerAngles.x );
192 const auto sy = std::sin( eulerAngles.y );
193 const auto sz = std::sin( eulerAngles.z );
194 return {
195 { cy * cz, cz * sx * sy - cx * sz, cx * cz * sy + sx * sz },
196 { cy * sz, cx * cz + sx * sy * sz, -cz * sx + cx * sy * sz },
197 { -sy, cy * sx, cx * cy }
198 };
199}
200
201template <typename T>
202constexpr Matrix3<T> Matrix3<T>::approximateLinearRotationMatrixFromEuler( const Vector3<T> & eulerAngles ) noexcept MR_REQUIRES_IF_SUPPORTED( std::is_floating_point_v<T> )
203{
204 const auto alpha = eulerAngles.x;
205 const auto beta = eulerAngles.y;
206 const auto gamma = eulerAngles.z;
207 return {
208 { T(1), -gamma, beta },
209 { gamma, T(1), -alpha },
210 { -beta, alpha, T(1) }
211 };
212}
213
214template <typename T>
215constexpr T Matrix3<T>::det() const noexcept
216{
217 return
218 x.x * ( y.y * z.z - y.z * z.y )
219 - x.y * ( y.x * z.z - y.z * z.x )
220 + x.z * ( y.x * z.y - y.y * z.x );
221}
222
223template <typename T>
224constexpr Matrix3<T> Matrix3<T>::inverse() const noexcept MR_REQUIRES_IF_SUPPORTED( !std::is_integral_v<T> )
225{
226 auto det = this->det();
227 if ( det == 0 )
228 return {};
229 return Matrix3<T>
230 {
231 { y.y * z.z - y.z * z.y, x.z * z.y - x.y * z.z, x.y * y.z - x.z * y.y },
232 { y.z * z.x - y.x * z.z, x.x * z.z - x.z * z.x, x.z * y.x - x.x * y.z },
233 { y.x * z.y - y.y * z.x, x.y * z.x - x.x * z.y, x.x * y.y - x.y * y.x }
234 } / det;
235}
236
237template <typename T>
238constexpr Matrix3<T> Matrix3<T>::transposed() const noexcept
239{
240 return Matrix3<T>
241 {
242 { x.x, y.x, z.x },
243 { x.y, y.y, z.y },
244 { x.z, y.z, z.z }
245 };
246}
247
248template <typename T>
249constexpr Vector3<T> Matrix3<T>::toEulerAngles() const noexcept MR_REQUIRES_IF_SUPPORTED( std::is_floating_point_v<T> )
250{
251 // https://stackoverflow.com/questions/15022630/how-to-calculate-the-angle-from-rotation-matrix
252 return {
253 std::atan2( z.y, z.z ),
254 std::atan2( -z.x, std::sqrt( z.y * z.y + z.z * z.z ) ),
255 std::atan2( y.x, x.x )
256 };
257}
258
259template <typename T>
260auto Matrix3<T>::qr() const noexcept -> QR MR_REQUIRES_IF_SUPPORTED( !std::is_integral_v<T> )
261{
262 // https://en.wikipedia.org/wiki/QR_decomposition#Computing_the_QR_decomposition
263 const auto a0 = col( 0 );
264 auto a1 = col( 1 );
265 auto a2 = col( 2 );
266 const auto r00 = a0.length();
267 const auto e0 = r00 > 0 ? a0 / r00 : Vector3<T>{};
268 const auto r01 = dot( e0, a1 );
269 const auto r02 = dot( e0, a2 );
270 a1 -= r01 * e0;
271 const auto r11 = a1.length();
272 const auto e1 = r11 > 0 ? a1 / r11 : Vector3<T>{};
273 const auto r12 = dot( e1, a2 );
274 a2 -= r02 * e0 + r12 * e1;
275 const auto r22 = a2.length();
276 const auto e2 = r22 > 0 ? a2 / r22 : Vector3<T>{};
277 return QR
278 {
279 Matrix3::fromColumns( e0, e1, e2 ),
280 Matrix3::fromRows( { r00, r01, r02 }, { T(0), r11, r12 }, { T(0), T(0), r22 } )
281 };
282}
283
285
286} // namespace MR
#define MR_REQUIRES_IF_SUPPORTED(...)
Definition MRMacros.h:26
BitSet operator-(const BitSet &a, const BitSet &b)
Definition MRMesh/MRBitSet.h:325
MRMESH_API bool operator==(const BitSet &a, const BitSet &b)
compare that two bit sets have the same set bits (they can be equal even if sizes are distinct but la...
bool operator!=(const SetBitIteratorT< T > &a, const SetBitIteratorT< T > &b)
Definition MRMesh/MRBitSet.h:259
constexpr auto dot(A a, A b)
Definition MRImGuiVectorOperators.h:129
Definition MRCameraOrientationPlugin.h:7
Color operator/(const Color &b, float a)
Definition MRColor.h:128
Color operator*(float a, const Color &b)
Definition MRColor.h:118
MRMESH_CLASS Vector3
Definition MRMesh/MRMeshFwd.h:136
Color operator+(const Color &a, const Color &b)
Definition MRColor.h:108
returns 3 Euler angles, assuming this is a rotation matrix composed as follows: R=R(z)*R(y)*R(x)
Definition MRMesh/MRMatrix3.h:77
Matrix3 q
Definition MRMesh/MRMatrix3.h:78
Definition MRMesh/MRMatrix3.h:13
static constexpr Matrix3 scale(T sx, T sy, T sz) noexcept
returns a matrix that has its own scale along each axis
Definition MRMesh/MRMatrix3.h:32
Matrix3< T > outer(const Vector3< T > &a, const Vector3< T > &b)
x = a * b^T
Definition MRMesh/MRMatrix3.h:125
T ValueType
Definition MRMesh/MRMatrix3.h:14
static constexpr Matrix3 identity() noexcept
Definition MRMesh/MRMatrix3.h:28
constexpr Matrix3< T > inverse() const noexcept MR_REQUIRES_IF_SUPPORTED(!std constexpr Matrix3< T > transposed() const noexcept
computes inverse matrix
constexpr T det() const noexcept
computes determinant of the matrix
Vector3< T > x
rows, identity matrix by default
Definition MRMesh/MRMatrix3.h:18
constexpr const Vector3< T > & operator[](int row) const noexcept
row access
Definition MRMesh/MRMatrix3.h:50
constexpr T normSq() const noexcept
compute sum of squared matrix elements
Definition MRMesh/MRMatrix3.h:59
constexpr auto norm() const noexcept
Definition MRMesh/MRMatrix3.h:60
constexpr Vector3< T > col(int i) const noexcept
column access
Definition MRMesh/MRMatrix3.h:54
static constexpr Matrix3 scale(T s) noexcept
returns a matrix that scales uniformly
Definition MRMesh/MRMatrix3.h:30
Matrix3 & operator/=(T b)
Definition MRMesh/MRMatrix3.h:86
constexpr T trace() const noexcept
computes trace of the matrix
Definition MRMesh/MRMatrix3.h:57
static constexpr Matrix3 fromColumns(const Vector3< T > &x, const Vector3< T > &y, const Vector3< T > &z) noexcept
Definition MRMesh/MRMatrix3.h:47
Matrix3 & operator*=(T b)
Definition MRMesh/MRMatrix3.h:85
Vector3< T > y
Definition MRMesh/MRMatrix3.h:19
static constexpr Matrix3 zero() noexcept
Definition MRMesh/MRMatrix3.h:27
T dot(const Matrix3< T > &a, const Matrix3< T > &b)
double-dot product: x = a : b
Definition MRMesh/MRMatrix3.h:107
Matrix3 & operator-=(const Matrix3< T > &b)
Definition MRMesh/MRMatrix3.h:84
constexpr Matrix3(const Matrix3< U > &m)
Definition MRMesh/MRMatrix3.h:26
static constexpr Matrix3 static rotation(const Vector3< T > &axis, T angle) noexcept MR_REQUIRES_IF_SUPPORTED(std constexpr Matrix3 static rotation(const Vector3< T > &from, const Vector3< T > &to) noexcept MR_REQUIRES_IF_SUPPORTED(std constexpr Matrix3 static rotationFromEuler(const Vector3< T > &eulerAngles) noexcept MR_REQUIRES_IF_SUPPORTED(std constexpr Matrix3 static approximateLinearRotationMatrixFromEuler(const Vector3< T > &eulerAngles) noexcept MR_REQUIRES_IF_SUPPORTED(std constexpr Matrix fromRows)(const Vector3< T > &x, const Vector3< T > &y, const Vector3< T > &z) noexcept
creates matrix representing rotation around given axis on given angle
Definition MRMesh/MRMatrix3.h:44
Vector3< T > z
Definition MRMesh/MRMatrix3.h:20
constexpr Matrix3() noexcept=default
static constexpr Matrix3 scale(const Vector3< T > &s) noexcept
Definition MRMesh/MRMatrix3.h:33
Definition MRMesh/MRVector3.h:19
T x
Definition MRMesh/MRVector3.h:25
T y
Definition MRMesh/MRVector3.h:25
T z
Definition MRMesh/MRVector3.h:25