MeshLib
 
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 template <typename U>
23 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 ) ) { }
24 static constexpr SymMatrix3 identity() noexcept { SymMatrix3 res; res.xx = res.yy = res.zz = 1; return res; }
25 static constexpr SymMatrix3 diagonal( T diagVal ) noexcept { SymMatrix3 res; res.xx = res.yy = res.zz = diagVal; return res; }
26
28 constexpr T trace() const noexcept { return xx + yy + zz; }
30 constexpr T normSq() const noexcept;
32 constexpr T det() const noexcept;
34 constexpr SymMatrix3<T> inverse() const noexcept { return inverse( det() ); }
36 constexpr SymMatrix3<T> inverse( T det ) const noexcept;
37
38 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; }
39 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; }
40 SymMatrix3 & operator *=( T b ) { xx *= b; xy *= b; xz *= b; yy *= b; yz *= b; zz *= b; return * this; }
42 {
43 if constexpr ( std::is_integral_v<T> )
44 { xx /= b; xy /= b; xz /= b; yy /= b; yz /= b; zz /= b; return * this; }
45 else
46 return *this *= ( 1 / b );
47 }
48
52 Vector3<T> eigens( Matrix3<T> * eigenvectors = nullptr ) const MR_REQUIRES_IF_SUPPORTED( !std::is_integral_v<T> );
54 Vector3<T> eigenvector( T eigenvalue ) const MR_REQUIRES_IF_SUPPORTED( !std::is_integral_v<T> );
55
61 SymMatrix3<T> pseudoinverse( T tol = std::numeric_limits<T>::epsilon(), int * rank = nullptr, Vector3<T> * space = nullptr ) const MR_REQUIRES_IF_SUPPORTED( !std::is_integral_v<T> );
62};
63
66
68template <typename T>
69inline Vector3<T> operator *( const SymMatrix3<T> & a, const Vector3<T> & b )
70{
71 return
72 {
73 a.xx * b.x + a.xy * b.y + a.xz * b.z,
74 a.xy * b.x + a.yy * b.y + a.yz * b.z,
75 a.xz * b.x + a.yz * b.y + a.zz * b.z
76 };
77}
78
80template <typename T>
82{
83 SymMatrix3<T> res;
84 res.xx = a.x * a.x;
85 res.xy = a.x * a.y;
86 res.xz = a.x * a.z;
87 res.yy = a.y * a.y;
88 res.yz = a.y * a.z;
89 res.zz = a.z * a.z;
90 return res;
91}
92
94template <typename T>
95inline SymMatrix3<T> outerSquare( T k, const Vector3<T> & a )
96{
97 const auto ka = k * a;
98 SymMatrix3<T> res;
99 res.xx = ka.x * a.x;
100 res.xy = ka.x * a.y;
101 res.xz = ka.x * a.z;
102 res.yy = ka.y * a.y;
103 res.yz = ka.y * a.z;
104 res.zz = ka.z * a.z;
105 return res;
106}
107
111template <typename T>
113{
114 SymMatrix3<T> res = outerSquare( a );
115 const auto d = a.lengthSq();
116 res.xx -= d;
117 res.yy -= d;
118 res.zz -= d;
119 return res;
120}
121
122template <typename T>
123inline bool operator ==( const SymMatrix3<T> & a, const SymMatrix3<T> & b )
124 { 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; }
125
126template <typename T>
127inline bool operator !=( const SymMatrix3<T> & a, const SymMatrix3<T> & b )
128 { return !( a == b ); }
129
130template <typename T>
131inline SymMatrix3<T> operator +( const SymMatrix3<T> & a, const SymMatrix3<T> & b )
132 { SymMatrix3<T> res{ a }; res += b; return res; }
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 *( T a, const SymMatrix3<T> & b )
140 { SymMatrix3<T> res{ b }; res *= a; return res; }
141
142template <typename T>
143inline SymMatrix3<T> operator *( const SymMatrix3<T> & b, T a )
144 { SymMatrix3<T> res{ b }; res *= a; return res; }
145
146template <typename T>
148 { b /= a; return b; }
149
150template <typename T>
151constexpr T SymMatrix3<T>::det() const noexcept
152{
153 return
154 xx * ( yy * zz - yz * yz )
155 - xy * ( xy * zz - yz * xz )
156 + xz * ( xy * yz - yy * xz );
157}
158
159template <typename T>
160constexpr T SymMatrix3<T>::normSq() const noexcept
161{
162 return sqr( xx ) + sqr( yy ) + sqr( zz ) +
163 2 * ( sqr( xy ) + sqr( xz ) + sqr( yz ) );
164}
165
166template <typename T>
167constexpr SymMatrix3<T> SymMatrix3<T>::inverse( T det ) const noexcept
168{
169 if ( det == 0 )
170 return {};
171 SymMatrix3<T> res;
172 res.xx = ( yy * zz - yz * yz ) / det;
173 res.xy = ( xz * yz - xy * zz ) / det;
174 res.xz = ( xy * yz - xz * yy ) / det;
175 res.yy = ( xx * zz - xz * xz ) / det;
176 res.yz = ( xz * xy - xx * yz ) / det;
177 res.zz = ( xx * yy - xy * xy ) / det;
178 return res;
179}
180
181template <typename T>
182Vector3<T> SymMatrix3<T>::eigens( Matrix3<T> * eigenvectors ) const MR_REQUIRES_IF_SUPPORTED( !std::is_integral_v<T> )
183{
184 //https://en.wikipedia.org/wiki/Eigenvalue_algorithm#3%C3%973_matrices
185 const auto q = trace() / 3;
186 const auto B = *this - diagonal( q );
187 const auto p2 = B.normSq();
188 const auto p = std::sqrt( p2 / 6 );
189 Vector3<T> eig;
190 if ( p <= std::abs( q ) * std::numeric_limits<T>::epsilon() )
191 {
192 // this is proportional to identity matrix
193 eig = { q, q, q };
194 if ( eigenvectors )
195 *eigenvectors = Matrix3<T>{};
196 return eig;
197 }
198 const auto r = B.det() / ( 2 * p * p * p );
199
200 // In exact arithmetic for a symmetric matrix - 1 <= r <= 1
201 // but computation error can leave it slightly outside this range.
202 if ( r <= -1 )
203 {
204 //phi = PI / 3;
205 eig[0] = q - 2 * p;
206 eig[1] = eig[2] = q + p;
207 if ( eigenvectors )
208 {
209 const auto x = eigenvector( eig[0] ).normalized();
210 const auto [ y, z ] = x.perpendicular();
211 *eigenvectors = Matrix3<T>::fromRows( x, y, z );
212 }
213 return eig;
214 }
215 if ( r >= 1 )
216 {
217 //phi = 0;
218 eig[0] = eig[1] = q - p;
219 eig[2] = q + 2 * p;
220 if ( eigenvectors )
221 {
222 const auto z = eigenvector( eig[2] ).normalized();
223 const auto [ x, y ] = z.perpendicular();
224 *eigenvectors = Matrix3<T>::fromRows( x, y, z );
225 }
226 return eig;
227 }
228 const auto phi = std::acos( r ) / 3;
229 eig[0] = q + 2 * p * cos( phi + T( 2 * PI / 3 ) );
230 eig[2] = q + 2 * p * cos( phi );
231 eig[1] = 3 * q - eig[0] - eig[2]; // 2 * q = trace() = eig[0] + eig[1] + eig[2]
232 if ( eigenvectors )
233 {
234 const auto x = eigenvector( eig[0] ).normalized();
235 const auto z = eigenvector( eig[2] ).normalized();
236 const auto y = cross( z, x );
237 *eigenvectors = Matrix3<T>::fromRows( x, y, z );
238 }
239 return eig;
240}
241
242template <typename T>
243Vector3<T> SymMatrix3<T>::eigenvector( T eigenvalue ) const MR_REQUIRES_IF_SUPPORTED( !std::is_integral_v<T> )
244{
245 const Vector3<T> row0( xx - eigenvalue, xy, xz );
246 const Vector3<T> row1( xy, yy - eigenvalue, yz );
247 const Vector3<T> row2( xz, yz, zz - eigenvalue );
248 // not-repeating eigenvalue means that some two rows are linearly independent
249 const Vector3<T> crs01 = cross( row0, row1 );
250 const Vector3<T> crs12 = cross( row1, row2 );
251 const Vector3<T> crs20 = cross( row2, row0 );
252 const T lsq01 = crs01.lengthSq();
253 const T lsq12 = crs12.lengthSq();
254 const T lsq20 = crs20.lengthSq();
255 if ( lsq01 > lsq12 )
256 {
257 if ( lsq01 > lsq20 )
258 return crs01;
259 }
260 else if ( lsq12 > lsq20 )
261 return crs12;
262 return crs20;
263}
264
265template <typename T>
266SymMatrix3<T> SymMatrix3<T>::pseudoinverse( T tol, int * rank, Vector3<T> * space ) const MR_REQUIRES_IF_SUPPORTED( !std::is_integral_v<T> )
267{
268 SymMatrix3<T> res;
269 Matrix3<T> eigenvectors;
270 const auto eigenvalues = eigens( &eigenvectors );
271 const auto threshold = std::max( std::abs( eigenvalues[0] ), std::abs( eigenvalues[2] ) ) * tol;
272 int myRank = 0;
273 for ( int i = 0; i < 3; ++i )
274 {
275 if ( std::abs( eigenvalues[i] ) <= threshold )
276 continue;
277 res += outerSquare( 1 / eigenvalues[i], eigenvectors[i] );
278 ++myRank;
279 if ( space )
280 {
281 if ( myRank == 1 )
282 *space = eigenvectors[i];
283 else if ( myRank == 2 )
284 *space = cross( *space, eigenvectors[i] );
285 else
286 *space = Vector3<T>{};
287 }
288 }
289 if ( rank )
290 *rank = myRank;
291 return res;
292}
293
295
296} // 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
Definition MRCameraOrientationPlugin.h:7
constexpr T sqr(T x) noexcept
Definition MRMesh/MRMeshFwd.h:613
Color operator/(const Color &b, float a)
Definition MRColor.h:128
MRMESH_CLASS Vector3
Definition MRMesh/MRMeshFwd.h:136
Color operator+(const Color &a, const Color &b)
Definition MRColor.h:108
Definition MRMesh/MRMatrix3.h:13
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
Definition MRSymMatrix3.h:15
static constexpr SymMatrix3 identity() noexcept
Definition MRSymMatrix3.h:24
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:112
constexpr SymMatrix3() noexcept=default
SymMatrix3< T > outerSquare(const Vector3< T > &a)
x = a * a^T
Definition MRSymMatrix3.h:81
T yz
Definition MRSymMatrix3.h:19
SymMatrix3 & operator+=(const SymMatrix3< T > &b)
Definition MRSymMatrix3.h:38
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:40
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:28
SymMatrix3 & operator-=(const SymMatrix3< T > &b)
Definition MRSymMatrix3.h:39
static constexpr SymMatrix3 diagonal(T diagVal) noexcept
Definition MRSymMatrix3.h:25
T zz
Definition MRSymMatrix3.h:19
constexpr SymMatrix3< T > inverse() const noexcept
computes inverse matrix
Definition MRSymMatrix3.h:34
T yy
Definition MRSymMatrix3.h:19
SymMatrix3< T > outerSquare(T k, const Vector3< T > &a)
x = k * a * a^T
Definition MRSymMatrix3.h:95
SymMatrix3 & operator/=(T b)
Definition MRSymMatrix3.h:41
Vector3< T > operator*(const SymMatrix3< T > &a, const Vector3< T > &b)
x = a * b
Definition MRSymMatrix3.h:69
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
T lengthSq() const
Definition MRMesh/MRVector3.h:46