2014-02-10 01:10:30 +00:00
/*************************************************************************/
/* matrix3.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 12:11:45 +00:00
/* https://godotengine.org */
2014-02-10 01:10:30 +00:00
/*************************************************************************/
2017-01-01 21:01:57 +00:00
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
2017-04-07 22:45:00 +00:00
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
2014-02-10 01:10:30 +00:00
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
# include "matrix3.h"
# include "math_funcs.h"
# include "os/copymem.h"
2017-08-07 18:07:43 +00:00
# include "print_string.h"
2017-03-18 23:36:26 +00:00
# define cofac(row1, col1, row2, col2) \
2014-02-10 01:10:30 +00:00
( elements [ row1 ] [ col1 ] * elements [ row2 ] [ col2 ] - elements [ row1 ] [ col2 ] * elements [ row2 ] [ col1 ] )
2017-03-18 23:36:26 +00:00
void Matrix3 : : from_z ( const Vector3 & p_z ) {
2014-02-10 01:10:30 +00:00
2017-03-18 23:36:26 +00:00
if ( Math : : abs ( p_z . z ) > Math_SQRT12 ) {
2014-02-10 01:10:30 +00:00
// choose p in y-z plane
2017-03-18 23:36:26 +00:00
real_t a = p_z [ 1 ] * p_z [ 1 ] + p_z [ 2 ] * p_z [ 2 ] ;
real_t k = 1.0 / Math : : sqrt ( a ) ;
elements [ 0 ] = Vector3 ( 0 , - p_z [ 2 ] * k , p_z [ 1 ] * k ) ;
elements [ 1 ] = Vector3 ( a * k , - p_z [ 0 ] * elements [ 0 ] [ 2 ] , p_z [ 0 ] * elements [ 0 ] [ 1 ] ) ;
2014-02-10 01:10:30 +00:00
} else {
// choose p in x-y plane
2017-03-18 23:36:26 +00:00
real_t a = p_z . x * p_z . x + p_z . y * p_z . y ;
real_t k = 1.0 / Math : : sqrt ( a ) ;
elements [ 0 ] = Vector3 ( - p_z . y * k , p_z . x * k , 0 ) ;
elements [ 1 ] = Vector3 ( - p_z . z * elements [ 0 ] . y , p_z . z * elements [ 0 ] . x , a * k ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-18 23:36:26 +00:00
elements [ 2 ] = p_z ;
2014-02-10 01:10:30 +00:00
}
void Matrix3 : : invert ( ) {
2017-03-18 23:36:26 +00:00
real_t co [ 3 ] = {
2014-02-10 01:10:30 +00:00
cofac ( 1 , 1 , 2 , 2 ) , cofac ( 1 , 2 , 2 , 0 ) , cofac ( 1 , 0 , 2 , 1 )
} ;
2017-03-18 23:36:26 +00:00
real_t det = elements [ 0 ] [ 0 ] * co [ 0 ] +
elements [ 0 ] [ 1 ] * co [ 1 ] +
elements [ 0 ] [ 2 ] * co [ 2 ] ;
2016-03-08 23:00:52 +00:00
2017-03-18 23:36:26 +00:00
ERR_FAIL_COND ( det = = 0 ) ;
real_t s = 1.0 / det ;
2014-02-10 01:10:30 +00:00
2017-03-18 23:36:26 +00:00
set ( co [ 0 ] * s , cofac ( 0 , 2 , 2 , 1 ) * s , cofac ( 0 , 1 , 1 , 2 ) * s ,
co [ 1 ] * s , cofac ( 0 , 0 , 2 , 2 ) * s , cofac ( 0 , 2 , 1 , 0 ) * s ,
co [ 2 ] * s , cofac ( 0 , 1 , 2 , 0 ) * s , cofac ( 0 , 0 , 1 , 1 ) * s ) ;
2014-02-10 01:10:30 +00:00
}
void Matrix3 : : orthonormalize ( ) {
// Gram-Schmidt Process
2017-03-18 23:36:26 +00:00
Vector3 x = get_axis ( 0 ) ;
Vector3 y = get_axis ( 1 ) ;
Vector3 z = get_axis ( 2 ) ;
2014-02-10 01:10:30 +00:00
x . normalize ( ) ;
2017-03-18 23:36:26 +00:00
y = ( y - x * ( x . dot ( y ) ) ) ;
2014-02-10 01:10:30 +00:00
y . normalize ( ) ;
2017-03-18 23:36:26 +00:00
z = ( z - x * ( x . dot ( z ) ) - y * ( y . dot ( z ) ) ) ;
2014-02-10 01:10:30 +00:00
z . normalize ( ) ;
2017-03-18 23:36:26 +00:00
set_axis ( 0 , x ) ;
set_axis ( 1 , y ) ;
set_axis ( 2 , z ) ;
2014-02-10 01:10:30 +00:00
}
Matrix3 Matrix3 : : orthonormalized ( ) const {
Matrix3 c = * this ;
c . orthonormalize ( ) ;
return c ;
}
Matrix3 Matrix3 : : inverse ( ) const {
2017-03-18 23:36:26 +00:00
Matrix3 inv = * this ;
2014-02-10 01:10:30 +00:00
inv . invert ( ) ;
return inv ;
}
void Matrix3 : : transpose ( ) {
2017-03-18 23:36:26 +00:00
SWAP ( elements [ 0 ] [ 1 ] , elements [ 1 ] [ 0 ] ) ;
SWAP ( elements [ 0 ] [ 2 ] , elements [ 2 ] [ 0 ] ) ;
SWAP ( elements [ 1 ] [ 2 ] , elements [ 2 ] [ 1 ] ) ;
2014-02-10 01:10:30 +00:00
}
Matrix3 Matrix3 : : transposed ( ) const {
2017-03-18 23:36:26 +00:00
Matrix3 tr = * this ;
2014-02-10 01:10:30 +00:00
tr . transpose ( ) ;
return tr ;
}
2017-03-18 23:36:26 +00:00
void Matrix3 : : scale ( const Vector3 & p_scale ) {
elements [ 0 ] [ 0 ] * = p_scale . x ;
elements [ 1 ] [ 0 ] * = p_scale . x ;
elements [ 2 ] [ 0 ] * = p_scale . x ;
elements [ 0 ] [ 1 ] * = p_scale . y ;
elements [ 1 ] [ 1 ] * = p_scale . y ;
elements [ 2 ] [ 1 ] * = p_scale . y ;
elements [ 0 ] [ 2 ] * = p_scale . z ;
elements [ 1 ] [ 2 ] * = p_scale . z ;
elements [ 2 ] [ 2 ] * = p_scale . z ;
2014-02-10 01:10:30 +00:00
}
2017-03-18 23:36:26 +00:00
Matrix3 Matrix3 : : scaled ( const Vector3 & p_scale ) const {
2014-02-10 01:10:30 +00:00
Matrix3 m = * this ;
m . scale ( p_scale ) ;
return m ;
}
Vector3 Matrix3 : : get_scale ( ) const {
return Vector3 (
2017-03-18 23:36:26 +00:00
Vector3 ( elements [ 0 ] [ 0 ] , elements [ 1 ] [ 0 ] , elements [ 2 ] [ 0 ] ) . length ( ) ,
Vector3 ( elements [ 0 ] [ 1 ] , elements [ 1 ] [ 1 ] , elements [ 2 ] [ 1 ] ) . length ( ) ,
Vector3 ( elements [ 0 ] [ 2 ] , elements [ 1 ] [ 2 ] , elements [ 2 ] [ 2 ] ) . length ( ) ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-18 23:36:26 +00:00
void Matrix3 : : rotate ( const Vector3 & p_axis , real_t p_phi ) {
2014-02-10 01:10:30 +00:00
* this = * this * Matrix3 ( p_axis , p_phi ) ;
}
2017-03-18 23:36:26 +00:00
Matrix3 Matrix3 : : rotated ( const Vector3 & p_axis , real_t p_phi ) const {
2014-02-10 01:10:30 +00:00
return * this * Matrix3 ( p_axis , p_phi ) ;
}
Vector3 Matrix3 : : get_euler ( ) const {
// rot = cy*cz -cy*sz sy
2017-03-18 23:36:26 +00:00
// cz*sx*sy+cx*sz cx*cz-sx*sy*sz -cy*sx
// -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy
2014-02-10 01:10:30 +00:00
Matrix3 m = * this ;
m . orthonormalize ( ) ;
Vector3 euler ;
euler . y = Math : : asin ( m [ 0 ] [ 2 ] ) ;
2017-03-18 23:36:26 +00:00
if ( euler . y < Math_PI * 0.5 ) {
if ( euler . y > - Math_PI * 0.5 ) {
2017-08-07 18:07:43 +00:00
//if rotation is Y-only, return a proper -pi,pi range like in x or z for the same case.
if ( m [ 1 ] [ 0 ] = = 0.0 & & m [ 0 ] [ 1 ] = = 0.0 & & m [ 0 ] [ 0 ] < 0.0 ) {
if ( euler . y > 0.0 )
euler . y = Math_PI - euler . y ;
else
euler . y = - ( Math_PI + euler . y ) ;
} else {
euler . x = Math : : atan2 ( - m [ 1 ] [ 2 ] , m [ 2 ] [ 2 ] ) ;
euler . z = Math : : atan2 ( - m [ 0 ] [ 1 ] , m [ 0 ] [ 0 ] ) ;
}
2014-02-10 01:10:30 +00:00
} else {
2017-03-18 23:36:26 +00:00
real_t r = Math : : atan2 ( m [ 1 ] [ 0 ] , m [ 1 ] [ 1 ] ) ;
2014-02-10 01:10:30 +00:00
euler . z = 0.0 ;
euler . x = euler . z - r ;
}
} else {
2017-03-18 23:36:26 +00:00
real_t r = Math : : atan2 ( m [ 0 ] [ 1 ] , m [ 1 ] [ 1 ] ) ;
2014-02-10 01:10:30 +00:00
euler . z = 0 ;
euler . x = r - euler . z ;
}
return euler ;
}
2017-03-18 23:36:26 +00:00
void Matrix3 : : set_euler ( const Vector3 & p_euler ) {
2014-02-10 01:10:30 +00:00
real_t c , s ;
c = Math : : cos ( p_euler . x ) ;
s = Math : : sin ( p_euler . x ) ;
2017-03-18 23:36:26 +00:00
Matrix3 xmat ( 1.0 , 0.0 , 0.0 , 0.0 , c , - s , 0.0 , s , c ) ;
2014-02-10 01:10:30 +00:00
c = Math : : cos ( p_euler . y ) ;
s = Math : : sin ( p_euler . y ) ;
2017-03-18 23:36:26 +00:00
Matrix3 ymat ( c , 0.0 , s , 0.0 , 1.0 , 0.0 , - s , 0.0 , c ) ;
2014-02-10 01:10:30 +00:00
c = Math : : cos ( p_euler . z ) ;
s = Math : : sin ( p_euler . z ) ;
2017-03-18 23:36:26 +00:00
Matrix3 zmat ( c , - s , 0.0 , s , c , 0.0 , 0.0 , 0.0 , 1.0 ) ;
2014-02-10 01:10:30 +00:00
//optimizer will optimize away all this anyway
2017-03-18 23:36:26 +00:00
* this = xmat * ( ymat * zmat ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-18 23:36:26 +00:00
bool Matrix3 : : operator = = ( const Matrix3 & p_matrix ) const {
2014-02-10 01:10:30 +00:00
2017-03-18 23:36:26 +00:00
for ( int i = 0 ; i < 3 ; i + + ) {
for ( int j = 0 ; j < 3 ; j + + ) {
if ( elements [ i ] [ j ] ! = p_matrix . elements [ i ] [ j ] )
2014-02-10 01:10:30 +00:00
return false ;
}
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
return true ;
}
2017-03-18 23:36:26 +00:00
bool Matrix3 : : operator ! = ( const Matrix3 & p_matrix ) const {
2014-02-10 01:10:30 +00:00
2017-03-18 23:36:26 +00:00
return ( ! ( * this = = p_matrix ) ) ;
2014-02-10 01:10:30 +00:00
}
Matrix3 : : operator String ( ) const {
2016-07-28 12:41:15 +00:00
String mtx ;
2017-03-18 23:36:26 +00:00
for ( int i = 0 ; i < 3 ; i + + ) {
2016-03-08 23:00:52 +00:00
2017-03-18 23:36:26 +00:00
for ( int j = 0 ; j < 3 ; j + + ) {
2016-03-08 23:00:52 +00:00
2017-03-18 23:36:26 +00:00
if ( i ! = 0 | | j ! = 0 )
mtx + = " , " ;
2016-03-08 23:00:52 +00:00
2017-03-18 23:36:26 +00:00
mtx + = rtos ( elements [ i ] [ j ] ) ;
2014-02-10 01:10:30 +00:00
}
}
2016-03-08 23:00:52 +00:00
2016-07-28 12:41:15 +00:00
return mtx ;
2014-02-10 01:10:30 +00:00
}
Matrix3 : : operator Quat ( ) const {
2017-03-18 23:36:26 +00:00
Matrix3 m = * this ;
2014-02-10 01:10:30 +00:00
m . orthonormalize ( ) ;
real_t trace = m . elements [ 0 ] [ 0 ] + m . elements [ 1 ] [ 1 ] + m . elements [ 2 ] [ 2 ] ;
real_t temp [ 4 ] ;
2016-03-08 23:00:52 +00:00
2017-03-18 23:36:26 +00:00
if ( trace > 0.0 ) {
2014-02-10 01:10:30 +00:00
real_t s = Math : : sqrt ( trace + 1.0 ) ;
2017-03-18 23:36:26 +00:00
temp [ 3 ] = ( s * 0.5 ) ;
2014-02-10 01:10:30 +00:00
s = 0.5 / s ;
2016-03-08 23:00:52 +00:00
2017-03-18 23:36:26 +00:00
temp [ 0 ] = ( ( m . elements [ 2 ] [ 1 ] - m . elements [ 1 ] [ 2 ] ) * s ) ;
temp [ 1 ] = ( ( m . elements [ 0 ] [ 2 ] - m . elements [ 2 ] [ 0 ] ) * s ) ;
temp [ 2 ] = ( ( m . elements [ 1 ] [ 0 ] - m . elements [ 0 ] [ 1 ] ) * s ) ;
} else {
2014-02-10 01:10:30 +00:00
int i = m . elements [ 0 ] [ 0 ] < m . elements [ 1 ] [ 1 ] ?
2017-03-18 23:36:26 +00:00
( m . elements [ 1 ] [ 1 ] < m . elements [ 2 ] [ 2 ] ? 2 : 1 ) :
( m . elements [ 0 ] [ 0 ] < m . elements [ 2 ] [ 2 ] ? 2 : 0 ) ;
2016-03-08 23:00:52 +00:00
int j = ( i + 1 ) % 3 ;
2014-02-10 01:10:30 +00:00
int k = ( i + 2 ) % 3 ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
real_t s = Math : : sqrt ( m . elements [ i ] [ i ] - m . elements [ j ] [ j ] - m . elements [ k ] [ k ] + 1.0 ) ;
temp [ i ] = s * 0.5 ;
s = 0.5 / s ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
temp [ 3 ] = ( m . elements [ k ] [ j ] - m . elements [ j ] [ k ] ) * s ;
temp [ j ] = ( m . elements [ j ] [ i ] + m . elements [ i ] [ j ] ) * s ;
temp [ k ] = ( m . elements [ k ] [ i ] + m . elements [ i ] [ k ] ) * s ;
}
2016-03-08 23:00:52 +00:00
2017-03-18 23:36:26 +00:00
return Quat ( temp [ 0 ] , temp [ 1 ] , temp [ 2 ] , temp [ 3 ] ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-18 23:36:26 +00:00
static const Matrix3 _ortho_bases [ 24 ] = {
2014-02-10 01:10:30 +00:00
Matrix3 ( 1 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 1 ) ,
Matrix3 ( 0 , - 1 , 0 , 1 , 0 , 0 , 0 , 0 , 1 ) ,
Matrix3 ( - 1 , 0 , 0 , 0 , - 1 , 0 , 0 , 0 , 1 ) ,
Matrix3 ( 0 , 1 , 0 , - 1 , 0 , 0 , 0 , 0 , 1 ) ,
Matrix3 ( 1 , 0 , 0 , 0 , 0 , - 1 , 0 , 1 , 0 ) ,
Matrix3 ( 0 , 0 , 1 , 1 , 0 , 0 , 0 , 1 , 0 ) ,
Matrix3 ( - 1 , 0 , 0 , 0 , 0 , 1 , 0 , 1 , 0 ) ,
Matrix3 ( 0 , 0 , - 1 , - 1 , 0 , 0 , 0 , 1 , 0 ) ,
Matrix3 ( 1 , 0 , 0 , 0 , - 1 , 0 , 0 , 0 , - 1 ) ,
Matrix3 ( 0 , 1 , 0 , 1 , 0 , 0 , 0 , 0 , - 1 ) ,
Matrix3 ( - 1 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , - 1 ) ,
Matrix3 ( 0 , - 1 , 0 , - 1 , 0 , 0 , 0 , 0 , - 1 ) ,
Matrix3 ( 1 , 0 , 0 , 0 , 0 , 1 , 0 , - 1 , 0 ) ,
Matrix3 ( 0 , 0 , - 1 , 1 , 0 , 0 , 0 , - 1 , 0 ) ,
Matrix3 ( - 1 , 0 , 0 , 0 , 0 , - 1 , 0 , - 1 , 0 ) ,
Matrix3 ( 0 , 0 , 1 , - 1 , 0 , 0 , 0 , - 1 , 0 ) ,
Matrix3 ( 0 , 0 , 1 , 0 , 1 , 0 , - 1 , 0 , 0 ) ,
Matrix3 ( 0 , - 1 , 0 , 0 , 0 , 1 , - 1 , 0 , 0 ) ,
Matrix3 ( 0 , 0 , - 1 , 0 , - 1 , 0 , - 1 , 0 , 0 ) ,
Matrix3 ( 0 , 1 , 0 , 0 , 0 , - 1 , - 1 , 0 , 0 ) ,
Matrix3 ( 0 , 0 , 1 , 0 , - 1 , 0 , 1 , 0 , 0 ) ,
Matrix3 ( 0 , 1 , 0 , 0 , 0 , 1 , 1 , 0 , 0 ) ,
Matrix3 ( 0 , 0 , - 1 , 0 , 1 , 0 , 1 , 0 , 0 ) ,
Matrix3 ( 0 , - 1 , 0 , 0 , 0 , - 1 , 1 , 0 , 0 )
} ;
int Matrix3 : : get_orthogonal_index ( ) const {
//could be sped up if i come up with a way
2017-03-18 23:36:26 +00:00
Matrix3 orth = * this ;
for ( int i = 0 ; i < 3 ; i + + ) {
for ( int j = 0 ; j < 3 ; j + + ) {
2014-02-10 01:10:30 +00:00
float v = orth [ i ] [ j ] ;
2017-03-18 23:36:26 +00:00
if ( v > 0.5 )
v = 1.0 ;
else if ( v < - 0.5 )
v = - 1.0 ;
2014-02-10 01:10:30 +00:00
else
2017-03-18 23:36:26 +00:00
v = 0 ;
2014-02-10 01:10:30 +00:00
2017-03-18 23:36:26 +00:00
orth [ i ] [ j ] = v ;
2014-02-10 01:10:30 +00:00
}
}
2017-03-18 23:36:26 +00:00
for ( int i = 0 ; i < 24 ; i + + ) {
2014-02-10 01:10:30 +00:00
2017-03-18 23:36:26 +00:00
if ( _ortho_bases [ i ] = = orth )
2014-02-10 01:10:30 +00:00
return i ;
}
return 0 ;
}
2017-03-18 23:36:26 +00:00
void Matrix3 : : set_orthogonal_index ( int p_index ) {
2014-02-10 01:10:30 +00:00
//there only exist 24 orthogonal bases in r3
2017-03-18 23:36:26 +00:00
ERR_FAIL_INDEX ( p_index , 24 ) ;
2014-02-10 01:10:30 +00:00
2017-03-18 23:36:26 +00:00
* this = _ortho_bases [ p_index ] ;
2014-02-10 01:10:30 +00:00
}
2017-03-18 23:36:26 +00:00
void Matrix3 : : get_axis_and_angle ( Vector3 & r_axis , real_t & r_angle ) const {
2014-02-10 01:10:30 +00:00
2017-03-18 23:36:26 +00:00
double angle , x , y , z ; // variables for result
double epsilon = 0.01 ; // margin to allow for rounding errors
double epsilon2 = 0.1 ; // margin to distinguish between 0 and 180 degrees
2014-02-10 01:10:30 +00:00
2017-03-18 23:36:26 +00:00
if ( ( Math : : abs ( elements [ 1 ] [ 0 ] - elements [ 0 ] [ 1 ] ) < epsilon ) & & ( Math : : abs ( elements [ 2 ] [ 0 ] - elements [ 0 ] [ 2 ] ) < epsilon ) & & ( Math : : abs ( elements [ 2 ] [ 1 ] - elements [ 1 ] [ 2 ] ) < epsilon ) ) {
// singularity found
// first check for identity matrix which must have +1 for all terms
// in leading diagonaland zero in other terms
if ( ( Math : : abs ( elements [ 1 ] [ 0 ] + elements [ 0 ] [ 1 ] ) < epsilon2 ) & & ( Math : : abs ( elements [ 2 ] [ 0 ] + elements [ 0 ] [ 2 ] ) < epsilon2 ) & & ( Math : : abs ( elements [ 2 ] [ 1 ] + elements [ 1 ] [ 2 ] ) < epsilon2 ) & & ( Math : : abs ( elements [ 0 ] [ 0 ] + elements [ 1 ] [ 1 ] + elements [ 2 ] [ 2 ] - 3 ) < epsilon2 ) ) {
2014-02-10 01:10:30 +00:00
// this singularity is identity matrix so angle = 0
2017-03-18 23:36:26 +00:00
r_axis = Vector3 ( 0 , 1 , 0 ) ;
r_angle = 0 ;
2014-02-10 01:10:30 +00:00
return ;
}
// otherwise this singularity is angle = 180
angle = Math_PI ;
2017-03-18 23:36:26 +00:00
double xx = ( elements [ 0 ] [ 0 ] + 1 ) / 2 ;
double yy = ( elements [ 1 ] [ 1 ] + 1 ) / 2 ;
double zz = ( elements [ 2 ] [ 2 ] + 1 ) / 2 ;
double xy = ( elements [ 1 ] [ 0 ] + elements [ 0 ] [ 1 ] ) / 4 ;
double xz = ( elements [ 2 ] [ 0 ] + elements [ 0 ] [ 2 ] ) / 4 ;
double yz = ( elements [ 2 ] [ 1 ] + elements [ 1 ] [ 2 ] ) / 4 ;
2014-02-10 01:10:30 +00:00
if ( ( xx > yy ) & & ( xx > zz ) ) { // elements[0][0] is the largest diagonal term
2017-03-18 23:36:26 +00:00
if ( xx < epsilon ) {
2014-02-10 01:10:30 +00:00
x = 0 ;
y = 0.7071 ;
z = 0.7071 ;
} else {
x = Math : : sqrt ( xx ) ;
2017-03-18 23:36:26 +00:00
y = xy / x ;
z = xz / x ;
2014-02-10 01:10:30 +00:00
}
} else if ( yy > zz ) { // elements[1][1] is the largest diagonal term
2017-03-18 23:36:26 +00:00
if ( yy < epsilon ) {
2014-02-10 01:10:30 +00:00
x = 0.7071 ;
y = 0 ;
z = 0.7071 ;
} else {
y = Math : : sqrt ( yy ) ;
2017-03-18 23:36:26 +00:00
x = xy / y ;
z = yz / y ;
2014-02-10 01:10:30 +00:00
}
} else { // elements[2][2] is the largest diagonal term so base result on this
2017-03-18 23:36:26 +00:00
if ( zz < epsilon ) {
2014-02-10 01:10:30 +00:00
x = 0.7071 ;
y = 0.7071 ;
z = 0 ;
} else {
z = Math : : sqrt ( zz ) ;
2017-03-18 23:36:26 +00:00
x = xz / z ;
y = yz / z ;
2014-02-10 01:10:30 +00:00
}
}
2017-03-18 23:36:26 +00:00
r_axis = Vector3 ( x , y , z ) ;
r_angle = angle ;
2014-02-10 01:10:30 +00:00
return ;
}
// as we have reached here there are no singularities so we can handle normally
2017-03-18 23:36:26 +00:00
double s = Math : : sqrt ( ( elements [ 1 ] [ 2 ] - elements [ 2 ] [ 1 ] ) * ( elements [ 1 ] [ 2 ] - elements [ 2 ] [ 1 ] ) + ( elements [ 2 ] [ 0 ] - elements [ 0 ] [ 2 ] ) * ( elements [ 2 ] [ 0 ] - elements [ 0 ] [ 2 ] ) + ( elements [ 0 ] [ 1 ] - elements [ 1 ] [ 0 ] ) * ( elements [ 0 ] [ 1 ] - elements [ 1 ] [ 0 ] ) ) ; // used to normalise
if ( Math : : abs ( s ) < 0.001 ) s = 1 ;
// prevent divide by zero, should not happen if matrix is orthogonal and should be
// caught by singularity test above, but I've left it in just in case
angle = Math : : acos ( ( elements [ 0 ] [ 0 ] + elements [ 1 ] [ 1 ] + elements [ 2 ] [ 2 ] - 1 ) / 2 ) ;
x = ( elements [ 1 ] [ 2 ] - elements [ 2 ] [ 1 ] ) / s ;
y = ( elements [ 2 ] [ 0 ] - elements [ 0 ] [ 2 ] ) / s ;
z = ( elements [ 0 ] [ 1 ] - elements [ 1 ] [ 0 ] ) / s ;
r_axis = Vector3 ( x , y , z ) ;
r_angle = angle ;
2014-02-10 01:10:30 +00:00
}
2017-03-18 23:36:26 +00:00
Matrix3 : : Matrix3 ( const Vector3 & p_euler ) {
2016-03-08 23:00:52 +00:00
2017-03-18 23:36:26 +00:00
set_euler ( p_euler ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-18 23:36:26 +00:00
Matrix3 : : Matrix3 ( const Quat & p_quat ) {
2014-02-10 01:10:30 +00:00
real_t d = p_quat . length_squared ( ) ;
real_t s = 2.0 / d ;
2017-03-18 23:36:26 +00:00
real_t xs = p_quat . x * s , ys = p_quat . y * s , zs = p_quat . z * s ;
real_t wx = p_quat . w * xs , wy = p_quat . w * ys , wz = p_quat . w * zs ;
real_t xx = p_quat . x * xs , xy = p_quat . x * ys , xz = p_quat . x * zs ;
real_t yy = p_quat . y * ys , yz = p_quat . y * zs , zz = p_quat . z * zs ;
set ( 1.0 - ( yy + zz ) , xy - wz , xz + wy ,
xy + wz , 1.0 - ( xx + zz ) , yz - wx ,
xz - wy , yz + wx , 1.0 - ( xx + yy ) ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-18 23:36:26 +00:00
Matrix3 : : Matrix3 ( const Vector3 & p_axis , real_t p_phi ) {
2014-02-10 01:10:30 +00:00
2017-03-18 23:36:26 +00:00
Vector3 axis_sq ( p_axis . x * p_axis . x , p_axis . y * p_axis . y , p_axis . z * p_axis . z ) ;
2014-02-10 01:10:30 +00:00
2017-03-18 23:36:26 +00:00
real_t cosine = Math : : cos ( p_phi ) ;
real_t sine = Math : : sin ( p_phi ) ;
2014-02-10 01:10:30 +00:00
2017-03-18 23:36:26 +00:00
elements [ 0 ] [ 0 ] = axis_sq . x + cosine * ( 1.0 - axis_sq . x ) ;
elements [ 0 ] [ 1 ] = p_axis . x * p_axis . y * ( 1.0 - cosine ) + p_axis . z * sine ;
elements [ 0 ] [ 2 ] = p_axis . z * p_axis . x * ( 1.0 - cosine ) - p_axis . y * sine ;
2014-02-10 01:10:30 +00:00
2017-03-18 23:36:26 +00:00
elements [ 1 ] [ 0 ] = p_axis . x * p_axis . y * ( 1.0 - cosine ) - p_axis . z * sine ;
elements [ 1 ] [ 1 ] = axis_sq . y + cosine * ( 1.0 - axis_sq . y ) ;
elements [ 1 ] [ 2 ] = p_axis . y * p_axis . z * ( 1.0 - cosine ) + p_axis . x * sine ;
2014-02-10 01:10:30 +00:00
2017-03-18 23:36:26 +00:00
elements [ 2 ] [ 0 ] = p_axis . z * p_axis . x * ( 1.0 - cosine ) + p_axis . y * sine ;
elements [ 2 ] [ 1 ] = p_axis . y * p_axis . z * ( 1.0 - cosine ) - p_axis . x * sine ;
elements [ 2 ] [ 2 ] = axis_sq . z + cosine * ( 1.0 - axis_sq . z ) ;
2014-02-10 01:10:30 +00:00
}