Main Page | Modules | Data Structures | File List | Data Fields | Globals | Related Pages

rotmat_to_ang.c

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------- 00002 @COPYRIGHT : 00003 Copyright 1993,1994,1995 David MacDonald, 00004 McConnell Brain Imaging Centre, 00005 Montreal Neurological Institute, McGill University. 00006 Permission to use, copy, modify, and distribute this 00007 software and its documentation for any purpose and without 00008 fee is hereby granted, provided that the above copyright 00009 notice appear in all copies. The author and McGill University 00010 make no representations about the suitability of this 00011 software for any purpose. It is provided "as is" without 00012 express or implied warranty. 00013 ---------------------------------------------------------------------------- */ 00014 00015 /* ----------------------------- MNI Header ----------------------------------- @NAME : rotmat_to_ang.c 00016 @INPUT : rot - rotation matrix (3x3 in num recipes form) calculated 00017 by the calling program. 00018 @OUTPUT : ang - vector giving rx,ry and rz rotation angles (in 00019 radians). This vector must be defined by the 00020 calling routine. 00021 @RETURNS : TRUE if ok, FALSE if error. 00022 @DESCRIPTION: this routine extracts the rotation angles from the rotation 00023 matrix. The rotation matrix is assumed to be a 3x3 matrix in 00024 numerical recipes form. It is locally copied into a 00025 4x4 homogeneous matrix for manipulation. 00026 00027 we assume that the matrix rotation center is (0,0,0). 00028 we assume that the application of this matrix to a vector 00029 is done with rot_mat*vec = premultiplication by matrix 00030 00031 the resulting angles rx=ang[1],ry=ang[2],rz=ang[3], follow 00032 the following assumptions: 00033 00034 -rotations are between -PI to PI 00035 -rotations are applied 1 - rx, 2 - ry and 3 - rz 00036 -applying these rotations to an identity matrix will 00037 result in a matrix equal to `rot' (the input matrix) 00038 -positive rotations are counter-clockwise when looking 00039 down the axis, from the positive end towards the origin. 00040 -I assume a coordinate system: 00041 ^ Y 00042 | 00043 | 00044 | 00045 | 00046 +---------> X 00047 / 00048 / 00049 / Z (towards the viewer). 00050 00051 -The problem is posed as: 00052 given a rotation matrix ROT, determine the rotations 00053 rx,ry,rz applied in order to give ROT 00054 solution: 00055 assume the rot matrix is equivalent to a normalized 00056 orthogonal local coord sys. i.e. row 1 of ROT is 00057 the local x direction, row 2 is the local y and row 3 00058 is the local z. 00059 00060 (note local is lower case, world is UPPER) 00061 00062 1- find RZ that brings local x into the XZ plane, on + size X 00063 2- find RY that brings local x*RZ onto X axis 00064 3- find RX that brings local z*RZ*RY onto Z axis 00065 00066 the required rotations are -RX,-RY and -RZ! 00067 00068 @GLOBALS : 00069 @CALLS : 00070 @CREATED : Feb 9, 1992 lc 00071 @MODIFIED : 00072 Tue Jun 8 08:44:59 EST 1993 LC 00073 changes all vec*matrix to matrix*vec. Std is premultiplication by matrix! 00074 @MODIFIED : July 4, 1995 D. MacDonald - removed recipes-style code, 00075 rewrote completely to handle angles from 00076 -PI to PI, instead of just -PI/2 to -PI/2 00077 @MODIFIED : July 19, 1996 D. MacDonald - now handles left-handed coordinate 00078 systems properly 00079 ---------------------------------------------------------------------------- */ 00080 00081 #include <volume_io/internal_volume_io.h> 00082 #include <bicpl/trans.h> 00083 00084 #ifndef lint 00085 static char rcsid[] = "$Header: /software/source//libraries/bicpl/Transforms/rotmat_to_ang.c,v 1.20 2000/02/06 15:30:51 stever Exp $"; 00086 #endif 00087 00088 #ifdef DEBUG 00089 private void are_rotations_equivalent( 00090 Transform *rot_trans, 00091 Real rx, 00092 Real ry, 00093 Real rz ); 00094 #endif 00095 00096 public BOOLEAN rotmat_to_ang( 00097 Transform *rot_trans, 00098 Real *ang ) 00099 { 00100 Real rx, ry, rz, vx, vy, vz, d; 00101 Vector x_axis, z_axis, y_axis, cross; 00102 Transform z_rot, y_rot; 00103 00104 /*--- get the x and z axis of the transform, these are all we need 00105 to compute the three angles, we simply compute the rz, ry, rx 00106 rotation needed to line up these on (1,0,0) and (0,0,1). The 00107 matrix is therefore equivalent to the inverse of this, which 00108 is the concatenation, in order of the rotations -rx, -ry, -rz */ 00109 00110 get_transform_x_axis( rot_trans, &x_axis ); 00111 get_transform_y_axis( rot_trans, &y_axis ); 00112 get_transform_z_axis( rot_trans, &z_axis ); 00113 00114 /*--- check if it is a left-handed coordinate system, if so 00115 switch it to right-handed */ 00116 00117 CROSS_VECTORS( cross, x_axis, y_axis ); 00118 d = DOT_VECTORS( cross, z_axis ); 00119 00120 if( d < 0.0 ) 00121 { 00122 print( "rotmat_to_ang: warning, input transform is left-handed.\n" ); 00123 SCALE_VECTOR( x_axis, x_axis, -1.0 ); 00124 } 00125 else if( d == 0.0 ) 00126 { 00127 print_error( "rotmat_to_ang: singular system passed in.\n" ); 00128 return( FALSE ); 00129 } 00130 00131 /*--- step one, find the RZ rotation reqd to bring 00132 the local x into the world XZ plane with a positive X */ 00133 00134 rz = compute_clockwise_rotation( (Real) Vector_x(x_axis), 00135 (Real) Vector_y(x_axis) ); 00136 00137 if( rz >= PI ) 00138 rz -= 2.0 * PI; 00139 00140 /*--- step two: find the RY rotation reqd to align 00141 the local x on the world X axis */ 00142 00143 make_rotation_transform( -rz, Z, &z_rot ); 00144 00145 transform_vector( &z_rot, (Real) Vector_x(x_axis), (Real) Vector_y(x_axis), 00146 (Real) Vector_z(x_axis), &vx, &vy, &vz ); 00147 00148 ry = - compute_clockwise_rotation( vx, vz ); 00149 00150 if( ry <= -PI ) 00151 ry += 2.0 * PI; 00152 00153 /*--- step three, rotate around RX to align the local z with Z */ 00154 00155 make_rotation_transform( -ry, Y, &y_rot ); 00156 00157 transform_vector( &z_rot, (Real) Vector_x(z_axis), (Real) Vector_y(z_axis), 00158 (Real) Vector_z(z_axis), &vx, &vy, &vz ); 00159 transform_vector( &y_rot, vx, vy, vz, &vx, &vy, &vz ); 00160 00161 rx = - compute_clockwise_rotation( vz, vy ); 00162 00163 if( rx <= -PI ) 00164 rx += 2.0 * PI; 00165 00166 /*--- the actual rotations to make up the transform are the negatives 00167 of these */ 00168 00169 rx = -rx; /* these are the required rotations */ 00170 ry = -ry; 00171 rz = -rz; 00172 00173 #ifdef DEBUG 00174 { 00175 Transform test; 00176 00177 make_identity_transform( &test ); 00178 set_transform_x_axis( &test, &x_axis ); 00179 set_transform_y_axis( &test, &y_axis ); 00180 set_transform_z_axis( &test, &z_axis ); 00181 00182 are_rotations_equivalent( &test, rx, ry, rz ); 00183 } 00184 #endif 00185 00186 ang[0] = rx; 00187 ang[1] = ry; 00188 ang[2] = rz; 00189 00190 return(TRUE); 00191 } 00192 00193 /* ----------------------------- MNI Header ----------------------------------- 00194 @NAME : are_rotations_equivalent 00195 @INPUT : rot_trans 00196 rx 00197 ry 00198 rz 00199 @OUTPUT : 00200 @RETURNS : 00201 @DESCRIPTION: Tests if the rot_transform is equivalent to the three 00202 successive counter-clockwise rotations. 00203 @METHOD : 00204 @GLOBALS : 00205 @CALLS : 00206 @CREATED : 1993 David MacDonald 00207 @MODIFIED : 00208 ---------------------------------------------------------------------------- */ 00209 00210 #ifdef DEBUG 00211 private void are_rotations_equivalent( 00212 Transform *rot_trans, 00213 Real rx, 00214 Real ry, 00215 Real rz ) 00216 { 00217 BOOLEAN error; 00218 Transform test, Rx, Ry, Rz; 00219 00220 /*--- use negatives, since make_rotation_transform assumes clockwise */ 00221 00222 make_rotation_transform( -rx, X, &Rx ) ; 00223 make_rotation_transform( -ry, Y, &Ry ) ; 00224 make_rotation_transform( -rz, Z, &Rz ) ; 00225 00226 concat_transforms( &test, &Rx, &Ry ); 00227 concat_transforms( &test, &test, &Rz ); 00228 00229 00230 error = FALSE; 00231 for_less( m, 0, N_DIMENSIONS ) 00232 for_less( n, 0, N_DIMENSIONS ) 00233 if( !numerically_close( Transform_elem(test,m,n), 00234 Transform_elem(*rot_trans,m,n), 1.0e-3 ) ) 00235 { 00236 error = TRUE; 00237 } 00238 00239 if( error ) 00240 { 00241 for_less( m, 0, N_DIMENSIONS ) 00242 { 00243 for_less( n, 0, N_DIMENSIONS ) 00244 print( " %g", Transform_elem(test,m,n) ); 00245 print( "\n" ); 00246 } 00247 print( "\n" ); 00248 for_less( m, 0, N_DIMENSIONS ) 00249 { 00250 for_less( n, 0, N_DIMENSIONS ) 00251 print( " %g", Transform_elem(*rot_trans,m,n) ); 00252 print( "\n" ); 00253 } 00254 00255 handle_internal_error( "rotmat_to_ang" ); 00256 } 00257 } 00258 #endif

Generated on Wed Jul 28 09:10:58 2004 for BICPL by doxygen 1.3.7