BELFEM 0.9.0
Berkeley Lab Finite Element Framework
Loading...
Searching...
No Matches
fn_quaternion_from_rotation_matrix.hpp
Go to the documentation of this file.
1/*
2 * BELFEM -- The Berkeley Lab Finite Element Framework
3 * Copyright (c) 2026, The Regents of the University of California,
4 * through Lawrence Berkeley National Laboratory (subject to receipt of any required
5 * approvals from the U.S. Dept. of Energy). All rights reserved.
6 *
7 * Developers: Christian Messe, Gregory Giard
8 *
9 * See the top-level LICENSE file for the complete license and disclaimer.
10 */
11
12#ifndef BELFEM_FN_QUATERNION_FROM_ROTATION_MATRIX_HPP
13#define BELFEM_FN_QUATERNION_FROM_ROTATION_MATRIX_HPP
14
15#include "cl_Quaternion.hpp"
16#include "cl_Matrix.hpp"
17#include "assert.hpp"
18
19namespace belfem
20{
21//------------------------------------------------------------------------------
22
34 template < typename T >
35 Quaternion < T >
36 quaternion_from_rotation_matrix( const Matrix < T > & aMatrix )
37 {
38 BELFEM_ASSERT( aMatrix.n_rows() == 3 && aMatrix.n_cols() == 3,
39 "Input matrix must be 3x3" );
40
41 T r00 = aMatrix( 0, 0 );
42 T r01 = aMatrix( 0, 1 );
43 T r02 = aMatrix( 0, 2 );
44 T r10 = aMatrix( 1, 0 );
45 T r11 = aMatrix( 1, 1 );
46 T r12 = aMatrix( 1, 2 );
47 T r20 = aMatrix( 2, 0 );
48 T r21 = aMatrix( 2, 1 );
49 T r22 = aMatrix( 2, 2 );
50
51 // check that the matrix is a proper rotation (det = +1); the determinant
52 // is formed inside the assert so it costs nothing once asserts compile out
53 BELFEM_ASSERT( std::abs( r00 * ( r11 * r22 - r12 * r21 )
54 - r01 * ( r10 * r22 - r12 * r20 )
55 + r02 * ( r10 * r21 - r11 * r20 )
56 - T( 1 ) ) < T( 100 ) * BELFEM_EPSILON,
57 "Input must be a proper rotation matrix (det = +1)" );
58 T tTrace = r00 + r11 + r22;
59
60 T w, x, y, z;
61
62 if ( tTrace > T( 0 ) )
63 {
64 // trace > 0: recover w from the trace (w^2 >= 1/4, safe division)
65 T s = T( 0.5 ) / std::sqrt( tTrace + T( 1 ) );
66 w = T( 0.25 ) / s;
67 x = ( r21 - r12 ) * s;
68 y = ( r02 - r20 ) * s;
69 z = ( r10 - r01 ) * s;
70 }
71 else if ( r00 > r11 && r00 > r22 )
72 {
73 // x is the largest component
74 T s = T( 2 ) * std::sqrt( T( 1 ) + r00 - r11 - r22 );
75 w = ( r21 - r12 ) / s;
76 x = T( 0.25 ) * s;
77 y = ( r01 + r10 ) / s;
78 z = ( r02 + r20 ) / s;
79 }
80 else if ( r11 > r22 )
81 {
82 // y is the largest component
83 T s = T( 2 ) * std::sqrt( T( 1 ) + r11 - r00 - r22 );
84 w = ( r02 - r20 ) / s;
85 x = ( r01 + r10 ) / s;
86 y = T( 0.25 ) * s;
87 z = ( r12 + r21 ) / s;
88 }
89 else
90 {
91 // z is the largest component
92 T s = T( 2 ) * std::sqrt( T( 1 ) + r22 - r00 - r11 );
93 w = ( r10 - r01 ) / s;
94 x = ( r02 + r20 ) / s;
95 y = ( r12 + r21 ) / s;
96 z = T( 0.25 ) * s;
97 }
98
99 Quaternion < T > tQ( w, x, y, z );
100 tQ.normalize();
101 return tQ;
102 }
103
104//------------------------------------------------------------------------------
105}
106#endif //BELFEM_FN_QUATERNION_FROM_ROTATION_MATRIX_HPP
#define BELFEM_ASSERT(aCheck,...)
Definition assert.hpp:244
size_t n_rows() const
Definition cl_AR_Matrix.hpp:205
size_t n_cols() const
Definition cl_AR_Matrix.hpp:213
Quaternion< T > & normalize()
Definition cl_Quaternion.hpp:269
USER GUIDES:
Definition cl_Capacitor.cpp:16
Quaternion< T > quaternion_from_rotation_matrix(const Matrix< T > &aMatrix)
Extract a unit quaternion from a 3x3 rotation matrix.
Definition fn_quaternion_from_rotation_matrix.hpp:36
constexpr real BELFEM_EPSILON
Definition typedefs.hpp:90