MeshLib C++ Docs
Loading...
Searching...
No Matches
MRSymMatrix3.h
Go to the documentation of this file.
1#pragma once
2
3#include "MRVector3.h"
4#include "MRMatrix3.h"
5#include "MRConstants.h"
6#include <limits>
7
8namespace MR
9{
10
13template <typename T>
15{
16 using ValueType = T;
17
19 T xx = 0, xy = 0, xz = 0, yy = 0, yz = 0, zz = 0;
20
21 constexpr SymMatrix3() noexcept = default;
22
23 // Here `T == U` doesn't seem to cause any issues in the C++ code, but we're still disabling it because it somehow gets emitted
24 // when generating the bindings, and results in duplicate functions in C#.
25 template <typename U> MR_REQUIRES_IF_SUPPORTED( !std::is_same_v<T, U> )
26 constexpr explicit SymMatrix3( const SymMatrix3<U> & m ) : xx( T( m.xx ) ), xy( T( m.xy ) ), xz( T( m.xz ) ), yy( T( m.yy ) ), yz( T( m.yz ) ), zz( T( m.zz ) ) { }
27
28 static constexpr SymMatrix3 identity() noexcept { SymMatrix3 res; res.xx = res.yy = res.zz = 1; return res; }
29 static constexpr SymMatrix3 diagonal( T diagVal ) noexcept { SymMatrix3 res; res.xx = res.yy = res.zz = diagVal; return res; }
30
32 constexpr T trace() const noexcept { return xx + yy + zz; }
34 constexpr T normSq() const noexcept;
36 constexpr T det() const noexcept;
38 constexpr SymMatrix3<T> inverse() const noexcept { return inverse( det() ); }
40 constexpr SymMatrix3<T> inverse( T det ) const noexcept;
41
42 SymMatrix3 & operator +=( const SymMatrix3<T> & b ) { xx += b.xx; xy += b.xy; xz += b.xz; yy += b.yy; yz += b.yz; zz += b.zz; return * this; }
43 SymMatrix3 & operator -=( const SymMatrix3<T> & b ) { xx -= b.xx; xy -= b.xy; xz -= b.xz; yy -= b.yy; yz -= b.yz; zz -= b.zz; return * this; }
44 SymMatrix3 & operator *=( T b ) { xx *= b; xy *= b; xz *= b; yy *= b; yz *= b; zz *= b; return * this; }
46 {
47 if constexpr ( std::is_integral_v<T> )
48 { xx /= b; xy /= b; xz /= b; yy /= b; yz /= b; zz /= b; return * this; }
49 else
50 return *this *= ( 1 / b );
51 }
52
56 Vector3<T> eigens( Matrix3<T> * eigenvectors = nullptr ) const MR_REQUIRES_IF_SUPPORTED( std::is_floating_point_v<T> );
58 Vector3<T> eigenvector( T eigenvalue ) const MR_REQUIRES_IF_SUPPORTED( !std::is_integral_v<T> );
59
65 SymMatrix3<T> pseudoinverse( T tol = std::numeric_limits<T>::epsilon(), int * rank = nullptr, Vector3<T> * space = nullptr ) const MR_REQUIRES_IF_SUPPORTED( std::is_floating_point_v<T> );
66};
67
70
72template <typename T>
73inline Vector3<T> operator *( const SymMatrix3<T> & a, const Vector3<T> & b )
74{
75 return
76 {
77 a.xx * b.x + a.xy * b.y + a.xz * b.z,
78 a.xy * b.x + a.yy * b.y + a.yz * b.z,
79 a.xz * b.x + a.yz * b.y + a.zz * b.z
80 };
81}
82
84template <typename T>
86{
87 SymMatrix3<T> res;
88 res.xx = a.x * a.x;
89 res.xy = a.x * a.y;
90 res.xz = a.x * a.z;
91 res.yy = a.y * a.y;
92 res.yz = a.y * a.z;
93 res.zz = a.z * a.z;
94 return res;
95}
96
98template <typename T>
99inline SymMatrix3<T> outerSquare( T k, const Vector3<T> & a )
100{
101 const auto ka = k * a;
102 SymMatrix3<T> res;
103 res.xx = ka.x * a.x;
104 res.xy = ka.x * a.y;
105 res.xz = ka.x * a.z;
106 res.yy = ka.y * a.y;
107 res.yz = ka.y * a.z;
108 res.zz = ka.z * a.z;
109 return res;
110}
111
115template <typename T>
117{
118 SymMatrix3<T> res = outerSquare( a );
119 const auto d = a.lengthSq();
120 res.xx -= d;
121 res.yy -= d;
122 res.zz -= d;
123 return res;
124}
125
126template <typename T>
127inline bool operator ==( const SymMatrix3<T> & a, const SymMatrix3<T> & b )
128 { return a.xx = b.xx && a.xy = b.xy && a.xz = b.xz && a.yy = b.yy && a.yz = b.yz && a.zz = b.zz; }
129
130template <typename T>
131inline bool operator !=( const SymMatrix3<T> & a, const SymMatrix3<T> & b )
132 { return !( a == b ); }
133
134template <typename T>
135inline SymMatrix3<T> operator +( const SymMatrix3<T> & a, const SymMatrix3<T> & b )
136 { SymMatrix3<T> res{ a }; res += b; return res; }
137
138template <typename T>
139inline SymMatrix3<T> operator -( const SymMatrix3<T> & a, const SymMatrix3<T> & b )
140 { SymMatrix3<T> res{ a }; res -= b; return res; }
141
142template <typename T>
143inline SymMatrix3<T> operator *( T a, const SymMatrix3<T> & b )
144 { SymMatrix3<T> res{ b }; res *= a; return res; }
145
146template <typename T>
147inline SymMatrix3<T> operator *( const SymMatrix3<T> & b, T a )
148 { SymMatrix3<T> res{ b }; res *= a; return res; }
149
150template <typename T>
152 { b /= a; return b; }
153
154template <typename T>
155constexpr T SymMatrix3<T>::det() const noexcept
156{
157 return
158 xx * ( yy * zz - yz * yz )
159 - xy * ( xy * zz - yz * xz )
160 + xz * ( xy * yz - yy * xz );
161}
162
163template <typename T>
164constexpr T SymMatrix3<T>::normSq() const noexcept
165{
166 return sqr( xx ) + sqr( yy ) + sqr( zz ) +
167 2 * ( sqr( xy ) + sqr( xz ) + sqr( yz ) );
168}
169
170template <typename T>
171constexpr SymMatrix3<T> SymMatrix3<T>::inverse( T det ) const noexcept
172{
173 if ( det == 0 )
174 return {};
175 SymMatrix3<T> res;
176 res.xx = ( yy * zz - yz * yz ) / det;
177 res.xy = ( xz * yz - xy * zz ) / det;
178 res.xz = ( xy * yz - xz * yy ) / det;
179 res.yy = ( xx * zz - xz * xz ) / det;
180 res.yz = ( xz * xy - xx * yz ) / det;
181 res.zz = ( xx * yy - xy * xy ) / det;
182 return res;
183}
184
185template <typename T>
186Vector3<T> SymMatrix3<T>::eigens( Matrix3<T> * eigenvectors ) const MR_REQUIRES_IF_SUPPORTED( std::is_floating_point_v<T> )
187{
188 //https://en.wikipedia.org/wiki/Eigenvalue_algorithm#3%C3%973_matrices
189 const auto q = trace() / 3;
190 const auto B = *this - diagonal( q );
191 const auto p2 = B.normSq();
192 const auto p = std::sqrt( p2 / 6 );
193 Vector3<T> eig;
194 if ( p <= std::abs( q ) * std::numeric_limits<T>::epsilon() )
195 {
196 // this is proportional to identity matrix
197 eig = { q, q, q };
198 if ( eigenvectors )
199 *eigenvectors = Matrix3<T>{};
200 return eig;
201 }
202 const auto r = B.det() / ( 2 * p * p * p );
203
204 // In exact arithmetic for a symmetric matrix - 1 <= r <= 1
205 // but computation error can leave it slightly outside this range.
206 if ( r <= -1 )
207 {
208 //phi = PI / 3;
209 eig[0] = q - 2 * p;
210 eig[1] = eig[2] = q + p;
211 if ( eigenvectors )
212 {
213 const auto x = eigenvector( eig[0] ).normalized();
214 const auto [ y, z ] = x.perpendicular();
215 *eigenvectors = Matrix3<T>::fromRows( x, y, z );
216 }
217 return eig;
218 }
219 if ( r >= 1 )
220 {
221 //phi = 0;
222 eig[0] = eig[1] = q - p;
223 eig[2] = q + 2 * p;
224 if ( eigenvectors )
225 {
226 const auto z = eigenvector( eig[2] ).normalized();
227 const auto [ x, y ] = z.perpendicular();
228 *eigenvectors = Matrix3<T>::fromRows( x, y, z );
229 }
230 return eig;
231 }
232 const auto phi = std::acos( r ) / 3;
233 eig[0] = q + 2 * p * cos( phi + T( 2 * PI / 3 ) );
234 eig[2] = q + 2 * p * cos( phi );
235 eig[1] = 3 * q - eig[0] - eig[2]; // 2 * q = trace() = eig[0] + eig[1] + eig[2]
236 if ( eigenvectors )
237 {
238 const auto x = eigenvector( eig[0] ).normalized();
239 const auto z = eigenvector( eig[2] ).normalized();
240 const auto y = cross( z, x );
241 *eigenvectors = Matrix3<T>::fromRows( x, y, z );
242 }
243 return eig;
244}
245
246template <typename T>
247Vector3<T> SymMatrix3<T>::eigenvector( T eigenvalue ) const MR_REQUIRES_IF_SUPPORTED( !std::is_integral_v<T> )
248{
249 const Vector3<T> row0( xx - eigenvalue, xy, xz );
250 const Vector3<T> row1( xy, yy - eigenvalue, yz );
251 const Vector3<T> row2( xz, yz, zz - eigenvalue );
252 // not-repeating eigenvalue means that some two rows are linearly independent
253 const Vector3<T> crs01 = cross( row0, row1 );
254 const Vector3<T> crs12 = cross( row1, row2 );
255 const Vector3<T> crs20 = cross( row2, row0 );
256 const T lsq01 = crs01.lengthSq();
257 const T lsq12 = crs12.lengthSq();
258 const T lsq20 = crs20.lengthSq();
259 if ( lsq01 > lsq12 )
260 {
261 if ( lsq01 > lsq20 )
262 return crs01;
263 }
264 else if ( lsq12 > lsq20 )
265 return crs12;
266 return crs20;
267}
268
269template <typename T>
270SymMatrix3<T> SymMatrix3<T>::pseudoinverse( T tol, int * rank, Vector3<T> * space ) const MR_REQUIRES_IF_SUPPORTED( std::is_floating_point_v<T> )
271{
272 SymMatrix3<T> res;
273 Matrix3<T> eigenvectors;
274 const auto eigenvalues = eigens( &eigenvectors );
275 const auto threshold = std::max( std::abs( eigenvalues[0] ), std::abs( eigenvalues[2] ) ) * tol;
276 int myRank = 0;
277 for ( int i = 0; i < 3; ++i )
278 {
279 if ( std::abs( eigenvalues[i] ) <= threshold )
280 continue;
281 res += outerSquare( 1 / eigenvalues[i], eigenvectors[i] );
282 ++myRank;
283 if ( space )
284 {
285 if ( myRank == 1 )
286 *space = eigenvectors[i];
287 else if ( myRank == 2 )
288 *space = cross( *space, eigenvectors[i] );
289 else
290 *space = Vector3<T>{};
291 }
292 }
293 if ( rank )
294 *rank = myRank;
295 return res;
296}
297
299
300} // namespace MR
#define MR_REQUIRES_IF_SUPPORTED(...)
Definition MRMacros.h:34
BitSet operator-(const BitSet &a, const BitSet &b)
Definition MRMesh/MRBitSet.h:442
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...
Definition MRCameraOrientationPlugin.h:8
constexpr T sqr(T x) noexcept
squared value
Definition MRMeshFwd.h:752
bool operator!=(const Color &a, const Color &b)
Definition MRMesh/MRColor.h:101
Color operator/(const Color &b, float a)
Definition MRMesh/MRColor.h:126
Color operator+(const Color &a, const Color &b)
Definition MRMesh/MRColor.h:106
float cross(Vector2f a, Vector2f b)
Definition MRMesh/MRMatrix3.h:21
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:59
Definition MRSymMatrix3.h:15
static constexpr SymMatrix3 identity() noexcept
Definition MRSymMatrix3.h:28
constexpr T det() const noexcept
computes determinant of the matrix
T xy
Definition MRSymMatrix3.h:19
T ValueType
Definition MRSymMatrix3.h:16
SymMatrix3< T > crossSquare(const Vector3< T > &a)
Definition MRSymMatrix3.h:116
constexpr SymMatrix3() noexcept=default
SymMatrix3< T > outerSquare(const Vector3< T > &a)
x = a * a^T
Definition MRSymMatrix3.h:85
T yz
Definition MRSymMatrix3.h:19
SymMatrix3 & operator+=(const SymMatrix3< T > &b)
Definition MRSymMatrix3.h:42
constexpr T normSq() const noexcept
computes the squared norm of the matrix, which is equal to the sum of 9 squared elements
T xz
Definition MRSymMatrix3.h:19
T xx
zero matrix by default
Definition MRSymMatrix3.h:19
SymMatrix3 & operator*=(T b)
Definition MRSymMatrix3.h:44
constexpr SymMatrix3< T > inverse(T det) const noexcept
computes inverse matrix given determinant of this
constexpr T trace() const noexcept
computes trace of the matrix
Definition MRSymMatrix3.h:32
SymMatrix3 & operator-=(const SymMatrix3< T > &b)
Definition MRSymMatrix3.h:43
static constexpr SymMatrix3 diagonal(T diagVal) noexcept
Definition MRSymMatrix3.h:29
T zz
Definition MRSymMatrix3.h:19
constexpr SymMatrix3< T > inverse() const noexcept
computes inverse matrix
Definition MRSymMatrix3.h:38
T yy
Definition MRSymMatrix3.h:19
SymMatrix3< T > outerSquare(T k, const Vector3< T > &a)
x = k * a * a^T
Definition MRSymMatrix3.h:99
SymMatrix3 & operator/=(T b)
Definition MRSymMatrix3.h:45
Vector3< T > operator*(const SymMatrix3< T > &a, const Vector3< T > &b)
x = a * b
Definition MRSymMatrix3.h:73
Definition MRMesh/MRVector3.h:30
T x
Definition MRMesh/MRVector3.h:36
T y
Definition MRMesh/MRVector3.h:36
T z
Definition MRMesh/MRVector3.h:36
T lengthSq() const
Definition MRMesh/MRVector3.h:65