[Chimera-users] Get angles in degree out of Rotation matrix
Thomas Goddard
goddard at cgl.ucsf.edu
Mon Nov 20 13:35:25 PST 2006
Hi Michael,
It is not very common to specify a 3-dimensional rotation in terms
of a x-axis rotation, y-axis rotation and z-axis rotation because this
decomposition depends on the order of the x, y, and z rotations.
If you rotate 90 degrees about the x-axis, then 90 about the y-axis
you get a different orientation than if you do the y-axis rotation
first followed by the x-axis rotation.
Chimera has a routine to produce the rotation axis (a unit vector in
3-dimensions) and rotation angle about that vector corresponding to a
3x3 rotation matrix. You could use that in Chimera with some Python code.
If you just want the rotation angle and don't need the axis then the
formula is simple
Tr(R) = 1 + 2*cos(theta)
where
Tr(R) = sum of rotation matrix diagonal elements
so the rotation angle
theta = arccos((Tr(R) - 1)/2)
Below I give the Chimera C++ code that also computes the axis. There
are corner cases handled by this code for 0 degree and 180 degree rotations.
Tom
void Xform::getRotation(Vector *axis, Real *angle) const
{
Real cosTheta = (rot[0][0] + rot[1][1] + rot[2][2] - 1) / 2;
if (fuzzyEqual(cosTheta, 1)) {
*angle = 0;
(*axis)[0] = (*axis)[1] = 0;
(*axis)[2] = 1;
return;
}
if (!fuzzyEqual(cosTheta, -1)) {
*angle = degrees(acos(cosTheta));
Real sinTheta = sqrt(1 - cosTheta * cosTheta);
(*axis)[0] = (rot[2][1] - rot[1][2]) / 2 / sinTheta;
(*axis)[1] = (rot[0][2] - rot[2][0]) / 2 / sinTheta;
(*axis)[2] = (rot[1][0] - rot[0][1]) / 2 / sinTheta;
return;
}
*angle = 180;
if (rot[0][0] >= rot[1][1]) {
if (rot[0][0] >= rot[2][2]) {
// rot00 is maximal diagonal term
(*axis)[0] = sqrt(rot[0][0] - rot[1][1] - rot[2][2]
+ 1.0f) / 2;
Real halfInverse = 1 / (2 * (*axis)[0]);
(*axis)[1] = halfInverse * rot[0][1];
(*axis)[2] = halfInverse * rot[0][2];
} else {
// rot22 is maximal diagonal term
(*axis)[2] = sqrt(rot[2][2] - rot[0][0] - rot[1][1]
+ 1.0f) / 2;
Real halfInverse = 1 / (2 * (*axis)[2]);
(*axis)[0] = halfInverse * rot[0][2];
(*axis)[1] = halfInverse * rot[1][2];
}
} else {
if (rot[1][1] >= rot[2][2]) {
// rot11 is maximal diagonal term
(*axis)[1] = sqrt(rot[1][1] - rot[0][0] - rot[2][2]
+ 1.0f) / 2;
Real halfInverse = 1 / (2 * (*axis)[1]);
(*axis)[0] = halfInverse * rot[0][1];
(*axis)[2] = halfInverse * rot[1][2];
} else {
// rot22 is maximal diagonal term
(*axis)[2] = sqrt(rot[2][2] - rot[0][0] - rot[1][1]
+ 1.0f) / 2;
Real halfInverse = 1 / (2 * (*axis)[2]);
(*axis)[0] = halfInverse * rot[0][2];
(*axis)[1] = halfInverse * rot[1][2];
}
}
}
More information about the Chimera-users
mailing list