0ad/source/terrain/Quaternion.cpp
notpete cc2b6afdac Initial revision.
This was SVN commit r96.
2003-11-25 18:34:05 +00:00

180 lines
3.1 KiB
C++
Executable File

/************************************************************
*
* File Name: Quaternion.Cpp
*
* Description:
*
************************************************************/
#include "Quaternion.h"
const float EPSILON=0.0001f;
CQuaternion::CQuaternion()
{
m_V.Clear ();
m_W = 0;
}
//quaternion addition
CQuaternion CQuaternion::operator + (CQuaternion &quat)
{
CQuaternion Temp;
Temp.m_W = m_W + quat.m_W;
Temp.m_V = m_V + quat.m_V;
return Temp;
}
//quaternion addition/assignment
CQuaternion &CQuaternion::operator += (CQuaternion &quat)
{
m_W += quat.m_W;
m_V += quat.m_V;
return (*this);
}
//quaternion multiplication
CQuaternion CQuaternion::operator * (CQuaternion &quat)
{
CQuaternion Temp;
Temp.m_W = (m_W * quat.m_W) - (m_V.Dot(quat.m_V));
Temp.m_V = (m_V.Cross(quat.m_V)) + (quat.m_V * m_W) + (m_V * quat.m_W);
return Temp;
}
//quaternion multiplication/assignment
CQuaternion &CQuaternion::operator *= (CQuaternion &quat)
{
(*this) = (*this) * quat;
return (*this);
}
void CQuaternion::FromEularAngles (float x, float y, float z)
{
float cr, cp, cy;
float sr, sp, sy;
CQuaternion QRoll, QPitch, QYaw;
cr = cosf(x * 0.5f);
cp = cosf(y * 0.5f);
cy = cosf(z * 0.5f);
sr = sinf(x * 0.5f);
sp = sinf(y * 0.5f);
sy = sinf(z * 0.5f);
QRoll.m_V.Set (sr,0,0);
QRoll.m_W = cr;
QPitch.m_V.Set (0,sp,0);
QPitch.m_W = cp;
QYaw.m_V.Set (0,0,sy);
QYaw.m_W = cy;
(*this) = QYaw * QPitch * QRoll;
}
CMatrix3D CQuaternion::ToMatrix ()
{
CMatrix3D R;
float x2, y2, z2;
float wx, wy, wz, xx, xy, xz, yy, yz, zz;
// calculate coefficients
x2 = m_V.X + m_V.X;
y2 = m_V.Y + m_V.Y;
z2 = m_V.Z + m_V.Z;
xx = m_V.X * x2;
xy = m_V.X * y2;
xz = m_V.X * z2;
yy = m_V.Y * y2;
yz = m_V.Y * z2;
zz = m_V.Z * z2;
wx = m_W * x2;
wy = m_W * y2;
wz = m_W * z2;
R.SetIdentity();
R._11 = 1.0f - (yy + zz);
R._12 = xy - wz;
R._13 = xz + wy;
R._21 = xy + wz;
R._22 = 1.0f - (xx + zz);
R._23 = yz - wx;
R._31 = xz - wy;
R._32 = yz + wx;
R._33 = 1.0f - (xx + yy);
return R;
}
void CQuaternion::Slerp(CQuaternion &from, CQuaternion &to, float ratio)
{
float to1[4];
float omega, cosom, sinom, scale0, scale1;
// calc cosine
cosom = from.m_V.X * to.m_V.X +
from.m_V.Y * to.m_V.Y +
from.m_V.Z * to.m_V.Z +
from.m_W * to.m_W;
// adjust signs (if necessary)
if (cosom < 0.0)
{
cosom = -cosom;
to1[0] = -to.m_V.X;
to1[1] = -to.m_V.Y;
to1[2] = -to.m_V.Z;
to1[3] = -to.m_W;
}
else
{
to1[0] = to.m_V.X;
to1[1] = to.m_V.Y;
to1[2] = to.m_V.Z;
to1[3] = to.m_W;
}
// calculate coefficients
if ((1.0f - cosom) > EPSILON)
{
// standard case (slerp)
omega = acosf(cosom);
sinom = sinf(omega);
scale0 = sinf((1.0f - ratio) * omega) / sinom;
scale1 = sinf(ratio * omega) / sinom;
}
else
{
// "from" and "to" quaternions are very close
// ... so we can do a linear interpolation
scale0 = 1.0f - ratio;
scale1 = ratio;
}
// calculate final values
m_V.X = scale0 * from.m_V.X + scale1 * to1[0];
m_V.Y = scale0 * from.m_V.Y + scale1 * to1[1];
m_V.Z = scale0 * from.m_V.Z + scale1 * to1[2];
m_W = scale0 * from.m_W + scale1 * to1[3];
}