490 CONFORMAL OPERATORS CHAPTER 16
column-major order, while we use row-major order). Once normalized, the translation
part of the matrix is easily extracted as
vector t.
To separate the rotation from the scale, we initialize three vectors that are the images of the
basis vectors
imageOfE1, imageOfE2, and imageOfE3. In principle, the overall scale is
the norm of any of these three vectors. However, to increase precision slightly we set
scale
to the average of the norm all three vectors.
Once s
1
is found, we can normalize the rotation matrix and convert it to a rotor R using
the existing
matrixToRotor() function from Section 7.10.3. There is one problem, how-
ever; the scaling may be negative. In Section 16.3.2, we have described this as the appli-
cation of an extra versor o ∧∞. The algorithm needs to detect and handle this, for the
(Euclidean) norm of a vector is always positive, hence so is s
1
. Negative scaling can be
detected by computing the determinant of the rotation matrix. We implement this as
follows:
if ((imageOfE1 ^ imageOfE2 ^ imageOfE3).e1e2e3() < 0.0f) {
// negative scaling detected ...
}
When negative scaling has been detected, a negative scaling versor o ∧∞is appended to
the final versor. Hence, the code that handles the scaling and extracts the rotation is:
// get scale of the 3x3 part (e1, e2, e3)
mv::Float scale = _Float(norm_e(imageOfE1) + norm_e(imageOfE2) +
norm_e(imageOfE3)) / 3.0f;
// compute determinant of matrix
// (if negative, negate all matrix elements)
mv::Float n = 1.0f; // used to negate the matrix
scalor negScale = _scalor(1.0f);
if ((imageOfE1 ^ imageOfE2 ^ imageOfE3).e1e2e3() < 0.0f) {
n = — 1.0f;
// no^ni provides the negative scaling in the final versor
negScale = noni;
}
// initialize 3x3 ’rotation’ matrix RM, call e3ga::matrixToRotor
mv::Float si=n/scale;
mv::Float RM[3 * 3] = {
M[0*4+0]*si,M[0*4+1]*si,M[0*4+2]*si,
M[1*4+0]*si,M[1*4+1]*si,M[1*4+2]*si,
M[2*4+0]*si,M[2*4+1]*si,M[2*4+2]*si
};
e3ga::rotor tmpR = e3ga::matrixToRotor(RM);
Note that the var iable negScale will either hold the value 1 or no∧ni to handle absence
or presence of negative scaling, respectively. The final versor is returned as