/**
Decompose the rotation on to 2 parts.
1. Twist - rotation around the "direction" axis
2. Swing - rotation around axis that is perpendicular to "direction"
axis
The rotation can be composed back by
composite_rotation = swing * twist ( == orientation )
have singularity in case of swing_rotation close to 180 degrees rotation.
input quaternion can be nonunit length
output is unit quats if input unit
*/
void swing_twist_decomposition( const xxquaternion& rotation,
const vector3& direction,
xxquaternion& swing,
xxquaternion& twist)
{
vector3 rotation_axis( rotation.x, rotation.y, rotation.z );
// return projection v1 on to v2 (parallel component)
// here can be optimized if direction is unit
vector3 proj = projection( rotation_axis, direction );
twist.set( proj.x, proj.y, proj.z, rotation.w );
twist.normalize();
swing = rotation * twist.conjugated();
}
In your terms all this right.
Rotation -> is a full quaternion rotation
direction -> is a "direction vector"
But the full rotation
rotation == swing*twist
and
rotation != twist*swing
The rotation compositions is not commutative.
//------------------------------------
from your page :
D = original vector direction
N = new vector direction
A = axis of swing rotation
R = axis of combined rotation
Let Us take by Twist quaternion the quaternion of look
Twist ( TR, W )
where
TR = axis of twist rotation
W = combined rotation scalar part of quaternion
TR = axis of twist rotation computed like Projection of
R = axis of combined rotation
to the
D = original vector direction
TR = projection(R, D );
If the
combined_rotation = swing*twist
than
swing = combined_rotation/twist =
swing = combined_rotation*twist.inversed() ;
( or conjugated if the twist is unit quat)
swing = combined_rotation*twist.inversed() ;
combined_rotation have two parts
vector part -> R
and scalar part W
combined_rotation( R, W)
twist represented as
twist(TR, W)
and twist conjugatad as twist( -TR, W)
than swing rotation can be calculated by quaternion multiplication rule
q*q' = q( cross(v,v') + wv' + w'v, ww' - dot(v,v') )
as
combined_rotation( R, W) * twist( -TR, W) =
swing( cross(R, -TR) + R*W - TR * W, W*W - dot(R, -TR) ) =
swing( cross(R, -TR) + W*(R - TR), W*W - dot(R, -TR) )
The vector cross(R, -TR) perpendicular to the D because -TR lay on the
"D", and W*(R - TR) perpendicular because:
W*( R - TR ) -> is a W*( R - projection (R, D )) ->
is a W*( perpendicular_component(R, D )) ;
The sum of two perpendicular to D vectors give the vector that is perprndicular
to D too, because thay lay in one plane , and tham composition lay in
that plane.
because of swing was computed as
swing = combined_rotation*twist.inversed() ;
their composition
combined_rotation = swing*twist;
And we know their properties that Twist rotate only about D vector and
Swing only about vector that is parallel to D.
It all work in the Pure rotation , when D represent the direction in LOCAL
object orientation frame.
So if we have the Rotation R1 and R2 , and want to find Swing and Twist
from R1 to R2 about any Direction vector. We need to made such :
find the delta rotation such that
R2 = R1 * Delta_Rotation
Delta_Rotation = R2/R1
Than decompose the Delta_Rotation by Direction Vector in the Delta_Rotation
Frame.
More info can be found in Shoemake "Fiber bundle twist reduction"
or in it's tutorial.
There he finf the Swing rotation first , by finding "shortest arc"
between
Direction Vector
and
New Direction Vector
And than find the Twist.
|