📄 wm4matrix3.inl
字号:
Real Matrix3<Real>::QForm (const Vector3<Real>& rkU, const Vector3<Real>& rkV)
const
{
return rkU.Dot((*this)*rkV);
}
//----------------------------------------------------------------------------
template <class Real>
Matrix3<Real> Matrix3<Real>::TimesDiagonal (const Vector3<Real>& rkDiag) const
{
return Matrix3<Real>(
m_afEntry[0]*rkDiag[0],m_afEntry[1]*rkDiag[1],m_afEntry[2]*rkDiag[2],
m_afEntry[3]*rkDiag[0],m_afEntry[4]*rkDiag[1],m_afEntry[5]*rkDiag[2],
m_afEntry[6]*rkDiag[0],m_afEntry[7]*rkDiag[1],m_afEntry[8]*rkDiag[2]);
}
//----------------------------------------------------------------------------
template <class Real>
Matrix3<Real> Matrix3<Real>::DiagonalTimes (const Vector3<Real>& rkDiag) const
{
return Matrix3<Real>(
rkDiag[0]*m_afEntry[0],rkDiag[0]*m_afEntry[1],rkDiag[0]*m_afEntry[2],
rkDiag[1]*m_afEntry[3],rkDiag[1]*m_afEntry[4],rkDiag[1]*m_afEntry[5],
rkDiag[2]*m_afEntry[6],rkDiag[2]*m_afEntry[7],rkDiag[2]*m_afEntry[8]);
}
//----------------------------------------------------------------------------
template <class Real>
void Matrix3<Real>::ToAxisAngle (Vector3<Real>& rkAxis, Real& rfAngle) const
{
// Let (x,y,z) be the unit-length axis and let A be an angle of rotation.
// The rotation matrix is R = I + sin(A)*P + (1-cos(A))*P^2 where
// I is the identity and
//
// +- -+
// P = | 0 -z +y |
// | +z 0 -x |
// | -y +x 0 |
// +- -+
//
// If A > 0, R represents a counterclockwise rotation about the axis in
// the sense of looking from the tip of the axis vector towards the
// origin. Some algebra will show that
//
// cos(A) = (trace(R)-1)/2 and R - R^t = 2*sin(A)*P
//
// In the event that A = pi, R-R^t = 0 which prevents us from extracting
// the axis through P. Instead note that R = I+2*P^2 when A = pi, so
// P^2 = (R-I)/2. The diagonal entries of P^2 are x^2-1, y^2-1, and
// z^2-1. We can solve these for axis (x,y,z). Because the angle is pi,
// it does not matter which sign you choose on the square roots.
Real fTrace = m_afEntry[0] + m_afEntry[4] + m_afEntry[8];
Real fCos = ((Real)0.5)*(fTrace-(Real)1.0);
rfAngle = Math<Real>::ACos(fCos); // in [0,PI]
if (rfAngle > (Real)0.0)
{
if (rfAngle < Math<Real>::PI)
{
rkAxis[0] = m_afEntry[7]-m_afEntry[5];
rkAxis[1] = m_afEntry[2]-m_afEntry[6];
rkAxis[2] = m_afEntry[3]-m_afEntry[1];
rkAxis.Normalize();
}
else
{
// angle is PI
Real fHalfInverse;
if (m_afEntry[0] >= m_afEntry[4])
{
// r00 >= r11
if (m_afEntry[0] >= m_afEntry[8])
{
// r00 is maximum diagonal term
rkAxis[0] = ((Real)0.5)*Math<Real>::Sqrt(m_afEntry[0] -
m_afEntry[4] - m_afEntry[8] + (Real)1.0);
fHalfInverse = ((Real)0.5)/rkAxis[0];
rkAxis[1] = fHalfInverse*m_afEntry[1];
rkAxis[2] = fHalfInverse*m_afEntry[2];
}
else
{
// r22 is maximum diagonal term
rkAxis[2] = ((Real)0.5)*Math<Real>::Sqrt(m_afEntry[8] -
m_afEntry[0] - m_afEntry[4] + (Real)1.0);
fHalfInverse = ((Real)0.5)/rkAxis[2];
rkAxis[0] = fHalfInverse*m_afEntry[2];
rkAxis[1] = fHalfInverse*m_afEntry[5];
}
}
else
{
// r11 > r00
if (m_afEntry[4] >= m_afEntry[8])
{
// r11 is maximum diagonal term
rkAxis[1] = ((Real)0.5)*Math<Real>::Sqrt(m_afEntry[4] -
m_afEntry[0] - m_afEntry[8] + (Real)1.0);
fHalfInverse = ((Real)0.5)/rkAxis[1];
rkAxis[0] = fHalfInverse*m_afEntry[1];
rkAxis[2] = fHalfInverse*m_afEntry[5];
}
else
{
// r22 is maximum diagonal term
rkAxis[2] = ((Real)0.5)*Math<Real>::Sqrt(m_afEntry[8] -
m_afEntry[0] - m_afEntry[4] + (Real)1.0);
fHalfInverse = ((Real)0.5)/rkAxis[2];
rkAxis[0] = fHalfInverse*m_afEntry[2];
rkAxis[1] = fHalfInverse*m_afEntry[5];
}
}
}
}
else
{
// The angle is 0 and the matrix is the identity. Any axis will
// work, so just use the x-axis.
rkAxis[0] = (Real)1.0;
rkAxis[1] = (Real)0.0;
rkAxis[2] = (Real)0.0;
}
}
//----------------------------------------------------------------------------
template <class Real>
void Matrix3<Real>::Orthonormalize ()
{
// Algorithm uses Gram-Schmidt orthogonalization. If 'this' matrix is
// M = [m0|m1|m2], then orthonormal output matrix is Q = [q0|q1|q2],
//
// q0 = m0/|m0|
// q1 = (m1-(q0*m1)q0)/|m1-(q0*m1)q0|
// q2 = (m2-(q0*m2)q0-(q1*m2)q1)/|m2-(q0*m2)q0-(q1*m2)q1|
//
// where |V| indicates length of vector V and A*B indicates dot
// product of vectors A and B.
// compute q0
Real fInvLength = Math<Real>::InvSqrt(m_afEntry[0]*m_afEntry[0] +
m_afEntry[3]*m_afEntry[3] + m_afEntry[6]*m_afEntry[6]);
m_afEntry[0] *= fInvLength;
m_afEntry[3] *= fInvLength;
m_afEntry[6] *= fInvLength;
// compute q1
Real fDot0 = m_afEntry[0]*m_afEntry[1] + m_afEntry[3]*m_afEntry[4] +
m_afEntry[6]*m_afEntry[7];
m_afEntry[1] -= fDot0*m_afEntry[0];
m_afEntry[4] -= fDot0*m_afEntry[3];
m_afEntry[7] -= fDot0*m_afEntry[6];
fInvLength = Math<Real>::InvSqrt(m_afEntry[1]*m_afEntry[1] +
m_afEntry[4]*m_afEntry[4] + m_afEntry[7]*m_afEntry[7]);
m_afEntry[1] *= fInvLength;
m_afEntry[4] *= fInvLength;
m_afEntry[7] *= fInvLength;
// compute q2
Real fDot1 = m_afEntry[1]*m_afEntry[2] + m_afEntry[4]*m_afEntry[5] +
m_afEntry[7]*m_afEntry[8];
fDot0 = m_afEntry[0]*m_afEntry[2] + m_afEntry[3]*m_afEntry[5] +
m_afEntry[6]*m_afEntry[8];
m_afEntry[2] -= fDot0*m_afEntry[0] + fDot1*m_afEntry[1];
m_afEntry[5] -= fDot0*m_afEntry[3] + fDot1*m_afEntry[4];
m_afEntry[8] -= fDot0*m_afEntry[6] + fDot1*m_afEntry[7];
fInvLength = Math<Real>::InvSqrt(m_afEntry[2]*m_afEntry[2] +
m_afEntry[5]*m_afEntry[5] + m_afEntry[8]*m_afEntry[8]);
m_afEntry[2] *= fInvLength;
m_afEntry[5] *= fInvLength;
m_afEntry[8] *= fInvLength;
}
//----------------------------------------------------------------------------
template <class Real>
void Matrix3<Real>::EigenDecomposition (Matrix3& rkRot, Matrix3& rkDiag) const
{
// Factor M = R*D*R^T. The columns of R are the eigenvectors. The
// diagonal entries of D are the corresponding eigenvalues.
Real afDiag[3], afSubd[2];
rkRot = *this;
bool bReflection = rkRot.Tridiagonalize(afDiag,afSubd);
bool bConverged = rkRot.QLAlgorithm(afDiag,afSubd);
assert(bConverged);
// (insertion) sort eigenvalues in increasing order, d0 <= d1 <= d2
int i;
Real fSave;
if (afDiag[1] < afDiag[0])
{
// swap d0 and d1
fSave = afDiag[0];
afDiag[0] = afDiag[1];
afDiag[1] = fSave;
// swap V0 and V1
for (i = 0; i < 3; i++)
{
fSave = rkRot[i][0];
rkRot[i][0] = rkRot[i][1];
rkRot[i][1] = fSave;
}
bReflection = !bReflection;
}
if (afDiag[2] < afDiag[1])
{
// swap d1 and d2
fSave = afDiag[1];
afDiag[1] = afDiag[2];
afDiag[2] = fSave;
// swap V1 and V2
for (i = 0; i < 3; i++)
{
fSave = rkRot[i][1];
rkRot[i][1] = rkRot[i][2];
rkRot[i][2] = fSave;
}
bReflection = !bReflection;
}
if (afDiag[1] < afDiag[0])
{
// swap d0 and d1
fSave = afDiag[0];
afDiag[0] = afDiag[1];
afDiag[1] = fSave;
// swap V0 and V1
for (i = 0; i < 3; i++)
{
fSave = rkRot[i][0];
rkRot[i][0] = rkRot[i][1];
rkRot[i][1] = fSave;
}
bReflection = !bReflection;
}
rkDiag.MakeDiagonal(afDiag[0],afDiag[1],afDiag[2]);
if (bReflection)
{
// The orthogonal transformation that diagonalizes M is a reflection.
// Make the eigenvectors a right--handed system by changing sign on
// the last column.
rkRot[0][2] = -rkRot[0][2];
rkRot[1][2] = -rkRot[1][2];
rkRot[2][2] = -rkRot[2][2];
}
}
//----------------------------------------------------------------------------
template <class Real>
Matrix3<Real>& Matrix3<Real>::FromEulerAnglesXYZ (Real fXAngle, Real fYAngle,
Real fZAngle)
{
Real fCos, fSin;
fCos = Math<Real>::Cos(fXAngle);
fSin = Math<Real>::Sin(fXAngle);
Matrix3 kXMat(
(Real)1.0,(Real)0.0,(Real)0.0,
(Real)0.0,fCos,-fSin,
(Real)0.0,fSin,fCos);
fCos = Math<Real>::Cos(fYAngle);
fSin = Math<Real>::Sin(fYAngle);
Matrix3 kYMat(
fCos,(Real)0.0,fSin,
(Real)0.0,(Real)1.0,(Real)0.0,
-fSin,(Real)0.0,fCos);
fCos = Math<Real>::Cos(fZAngle);
fSin = Math<Real>::Sin(fZAngle);
Matrix3 kZMat(
fCos,-fSin,(Real)0.0,
fSin,fCos,(Real)0.0,
(Real)0.0,(Real)0.0,(Real)1.0);
*this = kXMat*(kYMat*kZMat);
return *this;
}
//----------------------------------------------------------------------------
template <class Real>
Matrix3<Real>& Matrix3<Real>::FromEulerAnglesXZY (Real fXAngle, Real fZAngle,
Real fYAngle)
{
Real fCos, fSin;
fCos = Math<Real>::Cos(fXAngle);
fSin = Math<Real>::Sin(fXAngle);
Matrix3 kXMat(
(Real)1.0,(Real)0.0,(Real)0.0,
(Real)0.0,fCos,-fSin,
(Real)0.0,fSin,fCos);
fCos = Math<Real>::Cos(fZAngle);
fSin = Math<Real>::Sin(fZAngle);
Matrix3 kZMat(
fCos,-fSin,(Real)0.0,
fSin,fCos,(Real)0.0,
(Real)0.0,(Real)0.0,(Real)1.0);
fCos = Math<Real>::Cos(fYAngle);
fSin = Math<Real>::Sin(fYAngle);
Matrix3 kYMat(
fCos,(Real)0.0,fSin,
(Real)0.0,(Real)1.0,(Real)0.0,
-fSin,(Real)0.0,fCos);
*this = kXMat*(kZMat*kYMat);
return *this;
}
//----------------------------------------------------------------------------
template <class Real>
Matrix3<Real>& Matrix3<Real>::FromEulerAnglesYXZ (Real fYAngle, Real fXAngle,
Real fZAngle)
{
Real fCos, fSin;
fCos = Math<Real>::Cos(fYAngle);
fSin = Math<Real>::Sin(fYAngle);
Matrix3 kYMat(
fCos,(Real)0.0,fSin,
(Real)0.0,(Real)1.0,(Real)0.0,
-fSin,(Real)0.0,fCos);
fCos = Math<Real>::Cos(fXAngle);
fSin = Math<Real>::Sin(fXAngle);
Matrix3 kXMat(
(Real)1.0,(Real)0.0,(Real)0.0,
(Real)0.0,fCos,-fSin,
(Real)0.0,fSin,fCos);
fCos = Math<Real>::Cos(fZAngle);
fSin = Math<Real>::Sin(fZAngle);
Matrix3 kZMat(
fCos,-fSin,(Real)0.0,
fSin,fCos,(Real)0.0,
(Real)0.0,(Real)0.0,(Real)1.0);
*this = kYMat*(kXMat*kZMat);
return *this;
}
//----------------------------------------------------------------------------
template <class Real>
Matrix3<Real>& Matrix3<Real>::FromEulerAnglesYZX (Real fYAngle, Real fZAngle,
Real fXAngle)
{
Real fCos, fSin;
fCos = Math<Real>::Cos(fYAngle);
fSin = Math<Real>::Sin(fYAngle);
Matrix3 kYMat(
fCos,(Real)0.0,fSin,
(Real)0.0,(Real)1.0,(Real)0.0,
-fSin,(Real)0.0,fCos);
fCos = Math<Real>::Cos(fZAngle);
fSin = Math<Real>::Sin(fZAngle);
Matrix3 kZMat(
fCos,-fSin,(Real)0.0,
fSin,fCos,(Real)0.0,
(Real)0.0,(Real)0.0,(Real)1.0);
fCos = Math<Real>::Cos(fXAngle);
fSin = Math<Real>::Sin(fXAngle);
Matrix3 kXMat(
(Real)1.0,(Real)0.0,(Real)0.0,
(Real)0.0,fCos,-fSin,
(Real)0.0,fSin,fCos);
*this = kYMat*(kZMat*kXMat);
return *this;
}
//----------------------------------------------------------------------------
template <class Real>
Matrix3<Real>& Matrix3<Real>::FromEulerAnglesZXY (Real fZAngle, Real fXAngle,
Real fYAngle)
{
Real fCos, fSin;
fCos = Math<Real>::Cos(fZAngle);
fSin = Math<Real>::Sin(fZAngle);
Matrix3 kZMat(
fCos,-fSin,(Real)0.0,
fSin,fCos,(Real)0.0,
(Real)0.0,(Real)0.0,(Real)1.0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -