cgma
|
#include <geometry.hpp>
Public Types | |
enum | mat_format { C_STYLE, FORTRAN_STYLE } |
Public Member Functions | |
Transform () | |
Transform (const Vector3d &v) | |
Transform (const std::vector< double > &inputs, bool degree_format_p=false, enum mat_format=FORTRAN_STYLE) | |
Transform (double rot[9], const Vector3d &trans, enum mat_format=C_STYLE) | |
const Vector3d & | getTranslation () const |
bool | hasRot () const |
bool | hasInversion () const |
double | getTheta () const |
const Vector3d & | getAxis () const |
void | print (std::ostream &str) const |
Transform | reverse () const |
Protected Member Functions | |
void | set_rots_from_matrix (double raw_matrix[9], enum mat_format) |
Protected Attributes | |
Vector3d | translation |
bool | has_rot |
double | theta |
Vector3d | axis |
bool | invert |
Definition at line 111 of file geometry.hpp.
Definition at line 114 of file geometry.hpp.
{ C_STYLE, FORTRAN_STYLE };
Transform::Transform | ( | ) | [inline] |
Definition at line 125 of file geometry.hpp.
:translation(),has_rot(false),invert(false){}
Transform::Transform | ( | const Vector3d & | v | ) | [inline] |
Definition at line 126 of file geometry.hpp.
:translation(v),has_rot(false),invert(false){}
Transform::Transform | ( | const std::vector< double > & | inputs, |
bool | degree_format_p = false , |
||
enum mat_format | f = FORTRAN_STYLE |
||
) |
Definition at line 146 of file geometry.cpp.
: has_rot(false), invert(false) { size_t num_inputs = inputs.size(); // translation is always defined by first three inputs translation = Vector3d(inputs); if( num_inputs == 9 || // translation matrix with third vector missing num_inputs == 12 || num_inputs == 13 ) // translation matrix fully specified { has_rot = true; double raw_matrix[9]; if( num_inputs == 9 ){ for( int i = 3; i < 9; ++i){ raw_matrix[i-3] = degree_format_p ? cos(inputs.at(i) * M_PI / 180.0 ) : inputs.at(i); } Vector3d v1( raw_matrix ); //v1 = v1.normalize(); Vector3d v2( raw_matrix+3 ); //v2 = v2.normalize(); Vector3d v3 = v1.cross(v2);//.normalize(); raw_matrix[6] = v3.v[0]; raw_matrix[7] = v3.v[1]; raw_matrix[8] = v3.v[2]; } else{ for( int i = 3; i < 12; ++i){ raw_matrix[i-3] = degree_format_p ? cos(inputs.at(i) * M_PI / 180.0 ) : inputs.at(i); } if( num_inputs == 13 && inputs.at(12) == -1.0 ){ std::cout << "Notice: a transformation has M = -1. Inverting the translation;" << std::endl; std::cout << " though this might not be what you wanted." << std::endl; translation = -translation; } } set_rots_from_matrix( raw_matrix, f ); } else if( num_inputs != 3 ){ // an unsupported number of transformation inputs std::cerr << "Warning: transformation with " << num_inputs << " input items is unsupported" << std::endl; std::cerr << " (will pretend there's no rotation: expect incorrect geometry.)" << std::endl; } }
Transform::Transform | ( | double | rot[9], |
const Vector3d & | trans, | ||
enum mat_format | f = C_STYLE |
||
) |
Definition at line 140 of file geometry.cpp.
: translation(trans), has_rot(true), invert(false) { set_rots_from_matrix( rot, f ); }
const Vector3d& Transform::getAxis | ( | ) | const [inline] |
Definition at line 134 of file geometry.hpp.
{ return axis; }
double Transform::getTheta | ( | ) | const [inline] |
Definition at line 133 of file geometry.hpp.
{ return theta; }
const Vector3d& Transform::getTranslation | ( | ) | const [inline] |
Definition at line 130 of file geometry.hpp.
{ return translation; }
bool Transform::hasInversion | ( | ) | const [inline] |
Definition at line 132 of file geometry.hpp.
{ return invert; }
bool Transform::hasRot | ( | ) | const [inline] |
Definition at line 131 of file geometry.hpp.
{ return has_rot; }
void Transform::print | ( | std::ostream & | str | ) | const |
Definition at line 206 of file geometry.cpp.
{ str << "[trans " << translation; if(has_rot){ str << "(" << theta << ":" << axis << ")"; } if(invert){ str << "(I)"; } str << "]"; }
Transform Transform::reverse | ( | void | ) | const |
Definition at line 196 of file geometry.cpp.
void Transform::set_rots_from_matrix | ( | double | raw_matrix[9], |
enum mat_format | f | ||
) | [protected] |
Compute Euler axis/angle, given a rotation matix. See en.wikipedia.org/wiki/Rotation_representation_(mathematics)
Definition at line 26 of file geometry.cpp.
{ double mat[3][3] = {{ raw_matrix[0], raw_matrix[3], raw_matrix[6] }, { raw_matrix[1], raw_matrix[4], raw_matrix[7] }, { raw_matrix[2], raw_matrix[5], raw_matrix[8] } }; if( f == C_STYLE ){ /* row-major ordering: rewrite mat as mat = { { raw_matrix[0], raw_matrix[1], raw_matrix[2] }; { raw_matrix[3], raw_matrix[4], raw_matrix[5] }, { raw_matrix[6], raw_matrix[7], raw_matrix[8] } }; */ mat[0][1] = raw_matrix [1]; mat[0][2] = raw_matrix [2]; mat[1][0] = raw_matrix [3]; mat[1][2] = raw_matrix [5]; mat[2][0] = raw_matrix [6]; mat[2][1] = raw_matrix [7]; } double det = matrix_det(raw_matrix); // determinant is the same regardless of ordering if( OPT_DEBUG ){ std::cout << "Constructing rotation: " << std::endl; for( int i = 0; i < 3; i++ ){ std::cout << " [ "; for ( int j = 0; j < 3; j++ ){ std::cout << mat[i][j] << " "; } std::cout << "]" << std::endl; } std::cout << " det = " << det << std::endl; } if( det < 0.0 ){ // negative determinant-> this transformation contains a reflection. invert = true; det *= -1; for( int i = 0; i < 9; i++){ mat[i/3][i%3] = -mat[i/3][i%3]; } if( OPT_DEBUG ) std::cout << " negative determinant => improper rotation (adding inversion)" << std::endl; } if( fabs( det - 1.0 ) > DBL_EPSILON ){ std::cout << "Warning: determinant of rotation matrix " << det << " != +-1" << std::endl; } /* Older, more straightforward approach: theta = acos( (mat[0][0] + mat[1][1] + mat[2][2] - 1) / 2 ); double twoSinTheta = 2 * sin(theta); axis.v[0] = ( mat[2][1]-mat[1][2]) / twoSinTheta; axis.v[1] = ( mat[0][2]-mat[2][0]) / twoSinTheta; axis.v[2] = ( mat[1][0]-mat[0][1]) / twoSinTheta; */ /* I have switched from the simple implementation above to the more robust and complex * approach below. It has better numerical stability and (what is more important) * handles correctly the cases where theta is a multiple of 180 degrees. * See also * en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle (for why to use atan2 instead of acos) * www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm (for handling 180-degree case) */ double x = mat[2][1]-mat[1][2]; double y = mat[0][2]-mat[2][0]; double z = mat[1][0]-mat[0][1]; double r = hypot( x, hypot( y,z )); double t = mat[0][0] + mat[1][1] + mat[2][2]; theta = atan2(r,t-1); if( OPT_DEBUG ){ std:: cout << " r = " << r << " t = " << t << " theta = " << theta << std::endl; std:: cout << " x = " << x << " y = " << y << " z = " << z << std::endl; } if( std::fabs(theta) <= DBL_EPSILON ){ // theta is 0 or extremely close to it, so let's say there's no rotation after all. has_rot = false; axis = Vector3d(); // zero vector if( OPT_DEBUG ) std::cout << " (0) "; // std::endl comes below } else if( std::fabs( theta - M_PI ) <= DBL_EPSILON ){ // theta is pi (180 degrees) or extremely close to it // find the column of mat with the largest diagonal int col = 0; if( mat[1][1] > mat[col][col] ){ col = 1; } if( mat[2][2] > mat[col][col] ){ col = 2; } axis.v[col] = sqrt( (mat[col][col]+1)/2 ); double denom = 2*axis.v[col]; axis.v[(col+1)%3] = mat[col][(col+1)%3] / denom; axis.v[(col+2)%3] = mat[col][(col+2)%3] / denom; if( OPT_DEBUG ) std::cout << " (180) "; // std::endl comes below } else{ // standard case: theta isn't 0 or 180 axis.v[0] = x / r; axis.v[1] = y / r; axis.v[2] = z / r; } // convert theta back to degrees, as used by iGeom theta *= 180.0 / M_PI; if( OPT_DEBUG ) std::cerr << "computed rotation: " << *this << std::endl; }
Vector3d Transform::axis [protected] |
Definition at line 119 of file geometry.hpp.
bool Transform::has_rot [protected] |
Definition at line 118 of file geometry.hpp.
bool Transform::invert [protected] |
Definition at line 120 of file geometry.hpp.
double Transform::theta [protected] |
Definition at line 119 of file geometry.hpp.
Vector3d Transform::translation [protected] |
Definition at line 117 of file geometry.hpp.