#include "pch.h"
float Quaternion::GetRotation(Vector& vec) const
{
if (m_vec.X() == 0.0f && m_vec.Y() == 0.0f && m_vec.Z() == 0.0f) {
vec = Vector(0, 0, 1);
return 0;
} else {
vec = m_vec.Normalize();
return 2 * acos(m_a);
}
}
bool operator==(const Quaternion& q1, const Quaternion& q2)
{
return q1.m_a == q2.m_a && q1.m_vec == q2.m_vec;
}
bool operator!=(const Quaternion& q1, const Quaternion& q2)
{
return q1.m_a != q2.m_a || q1.m_vec != q2.m_vec;
}
Quaternion::Quaternion(const Orientation& o)
{
float trace = o[0][0] + o[1][1] + o[2][2];
if (trace > 0.001f)
{
float scale = (float)sqrt(1.0f + trace);
m_a = scale * 0.5f;
scale = -0.5f / scale;
m_vec.x = scale * (o[2][1] - o[1][2]);
m_vec.y = scale * (o[0][2] - o[2][0]);
m_vec.z = scale * (o[1][0] - o[0][1]);
}
else
{
int i,j,k;
if (o[1][1] > o[0][0])
if (o[2][2] > o[1][1])
i = 2, j = 0, k = 1;
else
i = 1, j = 2, k = 0;
else
if (o[2][2] > o[0][0])
i = 2, j = 0, k = 1;
else
i = 0, j = 1, k = 2;
float dojk = o[j][k] - o[k][j];
float scale = (dojk >= 0.0f)
? float( sqrt(1.0f + o[i][i] - o[j][j] - o[k][k]))
: float(-sqrt(1.0f + o[i][i] - o[j][j] - o[k][k]));
((float*)(&m_vec.x))[i] = scale * 0.5f;
scale = 0.5f / scale;
m_a = scale * dojk;
((float*)(&m_vec.x))[j] = scale * (o[j][i] + o[i][j]);
((float*)(&m_vec.x))[k] = scale * (o[k][i] + o[i][k]);
}
if (!(m_a >= 0.0f)) {
debugf("mmf Zlib quaternion.cpp:85 commented out assert(m_a >= 0.0f)");
}
}
Quaternion::operator Orientation(void) const
{
float m[3][3];
double s = m_a;
double x = m_vec.x;
double y = m_vec.y;
double z = m_vec.z;
double i2 = 2.0 * x; double j2 = 2.0 * y;
double k2 = 2.0 * z;
double l2 = s*s + x*x + y*y + z*z;
assert (l2 > 0.0);
{
double ii2 = (x * i2) / l2;
double jj2 = (y * j2) / l2;
double kk2 = (z * k2) / l2;
m[0][0] = float(1.0 - jj2 - kk2);
m[1][1] = float(1.0 - kk2 - ii2);
m[2][2] = float(1.0 - ii2 - jj2);
}
{
double ij2 = (x * j2) / l2;
double sk2 = (s * k2) / l2;
m[0][1] = float(ij2 + sk2);
m[1][0] = float(ij2 - sk2);
}
{
double jk2 = (y * k2) / l2;
double si2 = (s * i2) / l2;
m[1][2] = float(jk2 + si2);
m[2][1] = float(jk2 - si2);
}
{
double ki2 = (z * i2) / l2;
double sj2 = (s * j2) / l2;
m[0][2] = float(ki2 - sj2);
m[2][0] = float(ki2 + sj2);
}
Orientation o(m);
o.Renormalize();
return o;
}
Quaternion Slerp(const Quaternion& q1, const Quaternion& q2, float alpha)
{
double cTheta = q1.m_a * q2.m_a +
q1.m_vec * q2.m_vec;
double l1 = q1.m_a * q1.m_a +
q1.m_vec * q1.m_vec;
double l2 = q2.m_a * q2.m_a +
q2.m_vec * q2.m_vec;
float beta = 1.0f - alpha;
if (cTheta < 0.0f)
{
alpha = -alpha;
cTheta = -cTheta;
}
cTheta /= sqrt(l1 * l2);
assert (cTheta >= 0.0f);
Quaternion q;
if (cTheta > 0.999)
{
q.m_a = q1.m_a * beta + q2.m_a * alpha;
q.m_vec = q1.m_vec * beta + q2.m_vec * alpha;
q.Normalize();
}
else
{
double theta = acos(cTheta);
double sTheta = sin(theta);
float s1 = (float)(sin(beta * theta) / sTheta);
float s2 = (float)(sin(alpha * theta) / sTheta);
q.m_a = q1.m_a * s1 + q2.m_a * s2;
q.m_vec = q1.m_vec * s1 + q2.m_vec * s2;
}
return q;
}
Quaternion& Quaternion::Normalize(void)
{
float s = m_vec * m_vec + m_a * m_a;
if (s == 0.0f)
{
m_a = 0.0f;
m_vec.SetX(0.0f);
m_vec.SetY(0.0f);
m_vec.SetZ(1.0f);
}
else
{
s = (float)(1.0 / sqrt(s));
m_a *= s;
m_vec *= s;
}
return *this;
}