You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1563 lines
44 KiB

// D E F I N E S ///////////////////////////////////////////////////
// S T R U C T S ///////////////////////////////////////////////////
// G L O B A L S ///////////////////////////////////////////////////
namespace SEACAVE {
// C L A S S //////////////////////////////////////////////////////
template <typename TYPE>
inline TQuaternion<TYPE>::~TQuaternion()
{}
template <typename TYPE>
inline TQuaternion<TYPE>::TQuaternion()
: Base()
{}
template <typename TYPE>
inline TQuaternion<TYPE>::TQuaternion(const Base& q)
: Base(q)
{}
template <typename TYPE>
inline TQuaternion<TYPE>::TQuaternion(TYPE i, TYPE j, TYPE k, TYPE r)
: Base(cv::Vec<TYPE,4>(i, j, k, r))
{}
template <typename TYPE>
inline TQuaternion<TYPE>::TQuaternion(const Rot& R)
: Base(((const TRMatrixBase<TYPE>&)R).GetQuaternion())
{}
template <typename TYPE>
inline void TQuaternion<TYPE>::Invert()
{
Base::operator()(0) *=-1;
Base::operator()(1) *=-1;
Base::operator()(2) *=-1;
}
template <typename TYPE>
inline TQuaternion<TYPE> TQuaternion<TYPE>::Inverse() const
{
TQuaternion<TYPE> res(*this);
res.Invert();
return res;
}
template <typename TYPE>
inline void TQuaternion<TYPE>::MakeUnique()
{
//project quaternion to upper hemisphere (first ima.part >= 0)
TYPE *qThis = this->val;
if ((qThis[3] <= QUATERNION_EPSILON)
&&(qThis[3] >= -QUATERNION_EPSILON)) {
if ((qThis[1] <= QUATERNION_EPSILON)
&&(qThis[1] >= -QUATERNION_EPSILON)) {
if ((qThis[2] <= QUATERNION_EPSILON)
&&(qThis[2] >= -QUATERNION_EPSILON)) {
if (qThis[0] < 0.0) (*this) *= -1.0;
} else if (qThis[2] < 0.0) {
(*this) *= -1.0;
}
} else if (qThis[1] < 0.0) {
(*this) *= -1.0;
}
} else if (qThis[3] < 0.0) {
(*this) *= -1.0;
}
}
template <typename TYPE>
inline void TQuaternion<TYPE>::Mult(const TQuaternion<TYPE> &quat)
{
TYPE s1, s2, s3, s4, s5, s6, s7, s8, s9, t;
TYPE *qThis = this->val;
s1 = (qThis[2] - qThis[1]) * (quat[1] - quat[2]);
s2 = (qThis[3] + qThis[0]) * (quat[3] + quat[0]);
s3 = (qThis[3] - qThis[0]) * (quat[1] + quat[2]);
s4 = (qThis[2] + qThis[1]) * (quat[3] - quat[0]);
s5 = (qThis[2] - qThis[0]) * (quat[0] - quat[1]);
s6 = (qThis[2] + qThis[0]) * (quat[0] + quat[1]);
s7 = (qThis[3] + qThis[1]) * (quat[3] - quat[2]);
s8 = (qThis[3] - qThis[1]) * (quat[3] + quat[2]);
s9 = s6 + s7 + s8;
t = (s5 + s9) / 2.0f;
qThis[3] = s1 + t - s6;
qThis[0] = s2 + t - s9;
qThis[1] = s3 + t - s8;
qThis[2] = s4 + t - s7;
}
template <typename TYPE>
inline void TQuaternion<TYPE>::Mult(const TQuaternion<TYPE> &arg, TQuaternion<TYPE> &res) const
{
res = *this;
res.Mult(arg);
}
template <typename TYPE>
inline void TQuaternion<TYPE>::MultLeft(const TQuaternion<TYPE> &quatLeft)
{
TYPE s1, s2, s3, s4, s5, s6, s7, s8, s9, t;
TYPE *qThis = this->val;
s1 = (quatLeft[2] - quatLeft[1]) * (qThis[1] - qThis[2]);
s2 = (quatLeft[3] + quatLeft[0]) * (qThis[3] + qThis[0]);
s3 = (quatLeft[3] - quatLeft[0]) * (qThis[1] + qThis[2]);
s4 = (quatLeft[2] + quatLeft[1]) * (qThis[3] - qThis[0]);
s5 = (quatLeft[2] - quatLeft[0]) * (qThis[0] - qThis[1]);
s6 = (quatLeft[2] + quatLeft[0]) * (qThis[0] + qThis[1]);
s7 = (quatLeft[3] + quatLeft[1]) * (qThis[3] - qThis[2]);
s8 = (quatLeft[3] - quatLeft[1]) * (qThis[3] + qThis[2]);
s9 = s6 + s7 + s8;
t = (s5 + s9) / 2.0f;
qThis[3] = s1 + t - s6;
qThis[0] = s2 + t - s9;
qThis[1] = s3 + t - s8;
qThis[2] = s4 + t - s7;
}
/** rotates the given Vector with the quaternion ( q v q* )
the resulting vector is given in res
@returns 0 in case of no error
@author Daniel Grest, June 2003
*/
template <typename TYPE>
inline int TQuaternion<TYPE>::MultVec(const Vec &vec, Vec &res) const {
TYPE rx,ry,rz;
TYPE Vx= vec[0], Vy=vec[1], Vz=vec[2];
const TYPE *q = this->val;
{
TYPE QwQx, QwQy, QwQz, QxQy, QxQz, QyQz;
QwQx = q[3] * q[0]; QwQy = q[3] * q[1]; QwQz = q[3] * q[2];
QxQy = q[0] * q[1]; QxQz = q[0] * q[2]; QyQz = q[1] * q[2];
rx = 2* (Vy * (-QwQz + QxQy) + Vz *( QwQy + QxQz));
ry = 2* (Vx * ( QwQz + QxQy) + Vz *(-QwQx + QyQz));
rz = 2* (Vx * (-QwQy + QxQz) + Vy *( QwQx + QyQz));
}
TYPE QwQw, QxQx, QyQy, QzQz;
QwQw= q[3]*q[3]; QxQx = q[0]*q[0]; QyQy = q[1]*q[1]; QzQz= q[2]*q[2];
rx+= Vx * (QwQw + QxQx - QyQy - QzQz);
ry+= Vy * (QwQw - QxQx + QyQy - QzQz);
rz+= Vz * (QwQw - QxQx - QyQy + QzQz);
res[0]=rx; res[1]=ry; res[2]=rz;
return 0;
}
template <typename TYPE>
inline typename TQuaternion<TYPE>::Vec TQuaternion<TYPE>::MultVec(const Vec &vec) const
{
Vec r;
MultVec(vec,r);
return r;
}
template <typename TYPE>
inline void TQuaternion<TYPE>::SetIdentity()
{
Base::operator()(0) = Base::operator()(1) = Base::operator()(2) = 0;
Base::operator()(3) = 1;
}
template <typename TYPE>
inline void TQuaternion<TYPE>::SetQuaternion(TYPE real, TYPE i,
TYPE j, TYPE k)
{
//Components are stored in Vec4 in order imaginary part 1,2,3 and real part
this->Set(i,j,k,real);
}
template <typename TYPE>
inline void TQuaternion<TYPE>::SetValueAsAxisRad(const Vec &axis, TYPE angle)
{
SetValueAsAxisRad(axis[0], axis[1], axis[2], angle);
}
template <typename TYPE>
inline void TQuaternion<TYPE>::SetValueAsAxisRad(TYPE x, TYPE y, TYPE z, TYPE w)
{
TYPE rTmp = TYPE(sqrt(x * x + y * y + z * z));
if(rTmp > QUATERNION_EPSILON)
{
rTmp = TYPE(sin(w / 2.0f)) / rTmp;
Base::operator()(0) = x * rTmp;
Base::operator()(1) = y * rTmp;
Base::operator()(2) = z * rTmp;
Base::operator()(3) = TYPE(cos(w / 2.0f));
}
else
{
SetIdentity();
}
}
template <typename TYPE>
typename TQuaternion<TYPE>::Mat TQuaternion<TYPE>::GetQuaternionMultMatrixLeft() const
{
Mat res;
res(0,0) = (*this)[3];
res(0,1) = -(*this)[2];
res(0,2) = (*this)[1];
res(0,3) = (*this)[0];
res(1,0) = (*this)[2];
res(1,1) = (*this)[3];
res(1,2) = -(*this)[0];
res(1,3) = (*this)[1];
res(2,0) = -(*this)[1];
res(2,1) = (*this)[0];
res(2,2) = (*this)[3];
res(2,3) = (*this)[2];
res(3,0) = -(*this)[0];
res(3,1) = -(*this)[1];
res(3,2) = -(*this)[2];
res(3,3) = (*this)[3];
return res;
}
template <typename TYPE>
typename TQuaternion<TYPE>::Mat TQuaternion<TYPE>::GetQuaternionMultMatrixRight() const
{
Mat res;
res(0,0) = (*this)[3];
res(0,1) = (*this)[2];
res(0,2) = -(*this)[1];
res(0,3) = (*this)[0];
res(1,0) = -(*this)[2];
res(1,1) = (*this)[3];
res(1,2) = (*this)[0];
res(1,3) = (*this)[1];
res(2,0) = (*this)[1];
res(2,1) = -(*this)[0];
res(2,2) = (*this)[3];
res(2,3) = (*this)[2];
res(3,0) = -(*this)[0];
res(3,1) = -(*this)[1];
res(3,2) = -(*this)[2];
res(3,3) = (*this)[3];
return res;
}
template <typename TYPE>
int TQuaternion<TYPE>::GetAxisAngle(Vec& axis, TYPE& angle) const
{
// nicked from OpenSG
int res=0;
Vec q(cv::Vec<TYPE,3>((*this)[0], (*this)[1], (*this)[2]));
TYPE len = TYPE(norm(q));
if(len > QUATERNION_EPSILON) {
q *= TYPE(1.0) / len;
axis[0] = q[0];
axis[1] = q[1];
axis[2] = q[2];
angle = TYPE(2.0 * acos((*this)[3]));
} else {
axis[0] = 0.0;
axis[1] = 0.0;
axis[2] = 1.0;
angle = 0.0;
}
return res;
}
template <typename TYPE>
typename TQuaternion<TYPE>::Vec TQuaternion<TYPE>::GetRotationAxis() const
{
Vec r(cv::Vec<TYPE,3>((*this)[0], (*this)[1], (*this)[2]));
TYPE len = TYPE(norm(r));
if (len > QUATERNION_EPSILON)
return r * (1.0 / len);
else
return Vec(cv::Vec<TYPE,3>(0,0,1));
}
template <typename TYPE>
TYPE TQuaternion<TYPE>::GetRotationAngle() const
{
const TYPE angle = TYPE(2 * acos((*this)[3]));
return std::isnan(angle) && ABS(ABS((*this)[3]) - TYPE(1)) < QUATERNION_EPSILON ?
TYPE(0) :
angle;
}
template <typename TYPE>
TQuaternion<TYPE> TQuaternion<TYPE>::Power(const TYPE & scale) const
{
TQuaternion<TYPE> res = *this;
if ((scale < 1e-7) && (scale > -1e-7)) {
//scale near zero -> return identity
res.SetIdentity();
} else if ((res[3] > 0.999999) || (res[3] < -0.999999)) {
//this is near identity (numerical unstable) -> return identity
//res = *this
} else {
//else use slerp interpolation between identity and this with scale
TYPE temp1 = sin(scale * acos(res[3]))/sin(acos(res[3]));
TYPE res3 = res[3];
res *= temp1;
res[3] += TYPE(sin((1.0-scale) * acos(res3))/sin(acos(res3)));
}
return res;
}
template <typename TYPE>
TQuaternion<TYPE> TQuaternion<TYPE>::InterpolateLinear(const TQuaternion<TYPE> &to, const TYPE & t) const
{
BIASASSERT(t >= 0.0 && t <= 1.0);
TQuaternion<TYPE> p = *this;
TQuaternion<TYPE> q = to;
//p.Normalize();
//q.Normalize();
if (t < 1e-7) {
//t near zero -> return p
return p;
} else if (1.0-t < 1e-7) {
//t near one -> return q
return q;
}
//else use linear interpolation between this and q
TQuaternion<TYPE> res;
const TYPE cosPhi = (TYPE)p.ScalarProduct(q);
const TYPE a = (TYPE)1.0 - t;
const TYPE b = (cosPhi < 0 ? -t : t);
res[0] = a*p[0] + b*q[0];
res[1] = a*p[1] + b*q[1];
res[2] = a*p[2] + b*q[2];
res[3] = a*p[3] + b*q[3];
res.Normalize();
return res;
}
template <typename TYPE>
TQuaternion<TYPE> TQuaternion<TYPE>::
Interpolate(const TQuaternion<TYPE> &to, const TYPE & t) const
{
BIASASSERT(t >= 0.0 && t <= 1.0);
TQuaternion<TYPE> p = *this;
TQuaternion<TYPE> q = to;
//p.Normalize();
//q.Normalize();
if (t < 1e-7) {
//t near zero -> return p
return p;
} else if (1.0-t < 1e-7) {
//t near one -> return q
return q;
}
TQuaternion<TYPE> res;
TYPE a, b;
TYPE cosPhi = (TYPE)p.ScalarProduct(q);
//adjust angle if necessary
if (cosPhi < 0) {
q.MultiplyIP(-1.0);
cosPhi = -cosPhi;
}
if (cosPhi > 0.9999 || cosPhi < -0.9999) {
// p is very close to q, do linear interpolation instead of slerp
a = (TYPE)1.0 - t;
b = (cosPhi < 0 ? -t : t);
} else {
//else use slerp interpolation between p and q
const TYPE phi = acos(cosPhi < 0 ? -cosPhi : cosPhi);
const TYPE sinPhi = sin(phi);
a = sin(((TYPE)1.0 - t) * phi) / sinPhi;
b = sin(t * phi) / sinPhi;
if (cosPhi < 0) b = -b;
}
res[0] = a*p[0] + b*q[0];
res[1] = a*p[1] + b*q[1];
res[2] = a*p[2] + b*q[2];
res[3] = a*p[3] + b*q[3];
res.Normalize();
return res;
}
template <typename TYPE>
int TQuaternion<TYPE>::SetXYZ(TYPE radX, TYPE radY, TYPE radZ)
{
TQuaternion<TYPE> q_x;
TQuaternion<TYPE> q_y;
TQuaternion<TYPE> q_z;
q_x.SetValueAsAxisRad( 1.,0.,0., radX );
q_y.SetValueAsAxisRad( 0.,1.,0., radY );
q_z.SetValueAsAxisRad( 0.,0.,1., radZ );
q_x.Mult(q_y);
q_x.Mult(q_z);
*this = q_x;
return 0;
}
template <typename TYPE>
int TQuaternion<TYPE>::SetZYX(TYPE radX, TYPE radY, TYPE radZ)
{
TQuaternion<TYPE> q_x;
TQuaternion<TYPE> q_y;
TQuaternion<TYPE> q_z;
q_x.SetValueAsAxisRad( 1.,0.,0., radX );
q_y.SetValueAsAxisRad( 0.,1.,0., radY );
q_z.SetValueAsAxisRad( 0.,0.,1., radZ );
q_z.Mult(q_y);
q_z.Mult(q_x);
*this = q_z;
return 0;
}
template <typename TYPE>
TQuaternion<TYPE>& TQuaternion<TYPE>::operator=(const TQuaternion<TYPE>& vec)
{
memcpy((void *)val, (void *)vec.val, sizeof(TQuaternion<TYPE>));
return *this;
}
template <typename TYPE>
void TQuaternion<TYPE>::EnforceRigidCouplingConstraint(TQuaternion<TYPE> &other)
{
// @todo check unit norm constraint of this and other quaternion!!
// make this and other quaternion unique
MakeUnique();
other.MakeUnique();
// get aliases for both quaternions
TQuaternion<TYPE> &q0 = *this, &q1 = other;
// interpolate equal angle
q0[3] = q1[3] = TYPE(0.5) * (q0[3] + q1[3]);
// re-enforce unit length constraint for q0 and q1
TYPE q0norm = q0[0]*q0[0] + q0[1]*q0[1] + q0[2]*q0[2];
TYPE q1norm = q1[0]*q1[0] + q1[1]*q1[1] + q1[2]*q1[2];
if (q0norm > TYPE(1e-8) && q1norm > TYPE(1e-8)) {
TYPE qscale0 = (TYPE)sqrt(double((1-q0[3]*q0[3])/q0norm));
TYPE qscale1 = (TYPE)sqrt(double((1-q1[3]*q1[3])/q1norm));
for (int l = 0; l < 3; l++) {
q0[l] *= qscale0;
q1[l] *= qscale1;
}
}
// @todo check unit norm constraint of resulting quaternions!!
}
template <typename TYPE>
void TQuaternion<TYPE>::EnforceRigidCouplingConstraint(std::vector<TQuaternion<TYPE> > &quats)
{
// @todo check unit norm constraint of all quaternions!!
// make all quaternions unique
const int n = quats.size();
for (int i = 0; i < n; i++)
quats[i].MakeUnique();
// interpolate equal angle
double a = 0;
for (int i = 0; i < n; i++)
a += quats[i][3];
a /= TYPE(n);
for (int i = 0; i < n; i++)
quats[i][3] = a;
// re-enforce unit length constraint for all quaternions
for (int i = 0; i < n; i++) {
TQuaternion<TYPE> &q = quats[i];
TYPE qnorm = q[0]*q[0] + q[1]*q[1] + q[2]*q[2];
if (qnorm > TYPE(1e-8)) {
TYPE qscale = (TYPE)sqrt(double((1-q[3]*q[3])/qnorm));
for (int l = 0; l < 3; l++)
q[l] *= qscale;
}
}
// @todo check unit norm constraint of resulting quaternions!!
}
/*----------------------------------------------------------------*/
// C L A S S //////////////////////////////////////////////////////
// accuracy for constraint check in Check() function calls
#define R_CONSTRAINT_ACCURACY 1e-5 //ZEROTOLERANCE<TYPE>()
// if rotation angle is below this value, assume zero rotation
#define MINIMUM_ROTATION 1e-7
template <typename TYPE>
inline TRMatrixBase<TYPE>::TRMatrixBase()
: Base(Base::IDENTITY)
{}
template <typename TYPE>
inline TRMatrixBase<TYPE>::TRMatrixBase(const Mat& mat)
: Base(mat)
{
ASSERT(Check(R_CONSTRAINT_ACCURACY));
}
template <typename TYPE>
inline TRMatrixBase<TYPE>::TRMatrixBase(const Vec& w, TYPE phi)
{
Set(w, phi);
}
template <typename TYPE>
inline TRMatrixBase<TYPE>::TRMatrixBase(const Vec& rot)
{
SetRotationAxisAngle(rot);
}
template <typename TYPE>
inline TRMatrixBase<TYPE>::TRMatrixBase(const Quat& q)
{
SetFromQuaternion(q);
}
template <typename TYPE>
inline TRMatrixBase<TYPE>::TRMatrixBase(TYPE roll, TYPE pitch, TYPE yaw)
{
SetXYZ(roll, pitch, yaw);
}
template <typename TYPE>
inline TRMatrixBase<TYPE>::TRMatrixBase(const Vec& dir0, const Vec& dir1)
{
SetFromDir2Dir(dir0, dir1);
}
template <typename TYPE>
void TRMatrixBase<TYPE>::SetXYZ(TYPE PhiX, TYPE PhiY, TYPE PhiZ)
{
#if 0
TRMatrixBase<TYPE> Rx(TRMatrixBase<TYPE>::IDENTITY);
TRMatrixBase<TYPE> Ry(TRMatrixBase<TYPE>::IDENTITY);
TRMatrixBase<TYPE> Rz(TRMatrixBase<TYPE>::IDENTITY);
/* set Rz, Ry, Rx as rotation matrices */
Rz(0,0) = cos(PhiZ);
Rz(0,1) = -sin(PhiZ);
Rz(1,0) = -Rz(0,1);
Rz(1,1) = Rz(0,0);
//Rz(2,2) = 1;
Ry(0,0) = cos(PhiY);
Ry(0,2) = sin(PhiY);
//Ry(1,1) = 1;
Ry(2,0) = -Ry(0,2); //-sin(PhiY);
Ry(2,2) = Ry(0,0); //cos(PhiY);
//Rx(0,0) = 1;
Rx(1,1) = cos(PhiX);
Rx(1,2) = -sin(PhiX);
Rx(2,1) = -Rx(1,2); //sin(PhiX);
Rx(2,2) = Rx(1,1); //cos(PhiX);
*this = Rx*Ry*Rz;
#else
const TYPE sin_x = sin(PhiX);
const TYPE sin_y = sin(PhiY);
const TYPE sin_z = sin(PhiZ);
const TYPE cos_x = cos(PhiX);
const TYPE cos_y = cos(PhiY);
const TYPE cos_z = cos(PhiZ);
val[0] = cos_y * cos_z;
val[1] = -cos_y * sin_z;
val[2] = sin_y;
val[3] = cos_x * sin_z + cos_z * sin_x * sin_y;
val[4] = cos_x * cos_z - sin_x * sin_y * sin_z;
val[5] = -cos_y * sin_x;
val[6] = sin_x * sin_z - cos_x * cos_z * sin_y;
val[7] = cos_z * sin_x + cos_x * sin_y * sin_z;
val[8] = cos_x * cos_y;
#endif
}
template <typename TYPE>
void TRMatrixBase<TYPE>::SetZYX(TYPE PhiX, TYPE PhiY, TYPE PhiZ)
{
TRMatrixBase<TYPE> Rx(TRMatrixBase<TYPE>::IDENTITY);
TRMatrixBase<TYPE> Ry(TRMatrixBase<TYPE>::IDENTITY);
TRMatrixBase<TYPE> Rz(TRMatrixBase<TYPE>::IDENTITY);
/* set Rz, Ry, Rx as rotation matrices */
Rz(0,0) = cos(PhiZ);
Rz(0,1) = -sin(PhiZ);
Rz(1,0) = -Rz(0,1);
Rz(1,1) = Rz(0,0);
//Rz(2,2) = 1;
Ry(0,0) = cos(PhiY);
Ry(0,2) = sin(PhiY);
//Ry(1,1) = 1;
Ry(2,0) = -Ry(0,2); //-sin(PhiY);
Ry(2,2) = Ry(0,0); //cos(PhiY);
//Rx(0,0) = 1;
Rx(1,1) = cos(PhiX);
Rx(1,2) = -sin(PhiX);
Rx(2,1) = -Rx(1,2); //sin(PhiX);
Rx(2,2) = Rx(1,1); //cos(PhiX);
*this = Rz*Ry*Rx;
}
template <typename TYPE>
void TRMatrixBase<TYPE>::SetYXZ(TYPE PhiY, TYPE PhiX, TYPE PhiZ)
{
TRMatrixBase<TYPE> Rx(TRMatrixBase<TYPE>::IDENTITY);
TRMatrixBase<TYPE> Ry(TRMatrixBase<TYPE>::IDENTITY);
TRMatrixBase<TYPE> Rz(TRMatrixBase<TYPE>::IDENTITY);
/* set Rz, Ry, Rx as rotation matrices */
Rz(0,0) = cos(PhiZ);
Rz(0,1) = -sin(PhiZ);
Rz(1,0) = -Rz(0,1);
Rz(1,1) = Rz(0,0);
Ry(0,0) = cos(PhiY);
Ry(0,2) = sin(PhiY);
Ry(2,0) = -Ry(0,2); //-sin(PhiY);
Ry(2,2) = Ry(0,0); //cos(PhiY);
Rx(1,1) = cos(PhiX);
Rx(1,2) = -sin(PhiX);
Rx(2,1) = -Rx(1,2); //sin(PhiX);
Rx(2,2) = Rx(1,1); //cos(PhiX);
*this = Ry*Rx*Rz;
}
template <typename TYPE>
void TRMatrixBase<TYPE>::SetZXY(TYPE PhiX, TYPE PhiY, TYPE PhiZ)
{
TRMatrixBase<TYPE> Rx(TRMatrixBase<TYPE>::IDENTITY);
TRMatrixBase<TYPE> Ry(TRMatrixBase<TYPE>::IDENTITY);
TRMatrixBase<TYPE> Rz(TRMatrixBase<TYPE>::IDENTITY);
/* set Rz, Ry, Rx as rotation matrices */
Rz(0,0) = cos(PhiZ);
Rz(0,1) = -sin(PhiZ);
Rz(1,0) = -Rz(0,1);
Rz(1,1) = Rz(0,0);
Ry(0,0) = cos(PhiY);
Ry(0,2) = sin(PhiY);
Ry(2,0) = -Ry(0,2); //-sin(PhiY);
Ry(2,2) = Ry(0,0); //cos(PhiY);
Rx(1,1) = cos(PhiX);
Rx(1,2) = -sin(PhiX);
Rx(2,1) = -Rx(1,2); //sin(PhiX);
Rx(2,2) = Rx(1,1); //cos(PhiX);
*this = Rz*Rx*Ry;
}
template <typename TYPE>
void TRMatrixBase<TYPE>::Set(const Vec& wa, TYPE phi)
{
// zero rotation results in identity matrix
if (ISZERO(phi)) {
*this = Base::IDENTITY;
return;
}
const TYPE wnorm(norm(wa));
if (wnorm < std::numeric_limits<TYPE>::epsilon()) {
CPC_ERROR("Vector "<<wa<<" is close to zero (norm = "<<wnorm<<"), solution is instable!");
}
const Vec w(wa*(TYPE(1)/wnorm));
Mat Omega;
Omega(0,0) = TYPE(0);
Omega(0,1) = -w[2];
Omega(0,2) = w[1];
Omega(1,0) = w[2];
Omega(1,1) = TYPE(0);
Omega(1,2) = -w[0];
Omega(2,0) = -w[1] ;
Omega(2,1) = w[0];
Omega(2,2) = TYPE(0);
const Mat Sin_O(Omega * sin(phi));
const Mat Cos_O_O((Omega * Omega) * (TYPE(1)-cos(phi)));
*this = Base::IDENTITY + Sin_O + Cos_O_O;
}
template <typename TYPE>
void TRMatrixBase<TYPE>::SetFromColumnVectors(const Vec& v0, const Vec& v1, const Vec& v2)
{
val[0] = v0[0];
val[1] = v1[0];
val[2] = v2[0];
val[3] = v0[1];
val[4] = v1[1];
val[5] = v2[1];
val[6] = v0[2];
val[7] = v1[2];
val[8] = v2[2];
ASSERT(Check(R_CONSTRAINT_ACCURACY));
}
template <typename TYPE>
void TRMatrixBase<TYPE>::SetFromRowVectors(const Vec& v0, const Vec& v1, const Vec& v2)
{
val[0] = v0[0];
val[1] = v0[1];
val[2] = v0[2];
val[3] = v1[0];
val[4] = v1[1];
val[5] = v1[2];
val[6] = v2[0];
val[7] = v2[1];
val[8] = v2[2];
ASSERT(Check(R_CONSTRAINT_ACCURACY));
}
template <typename TYPE>
void TRMatrixBase<TYPE>::SetFromAxisAngle(const Vec& w)
{
#if 0
const TYPE dAngle(norm(w));
Set(w*INVERT(dAngle), dAngle);
#else
SetRotationAxisAngle(w);
#endif
}
template <typename TYPE>
void TRMatrixBase<TYPE>::GetQuaternion(Quat& quat) const
{
ASSERT(Check(R_CONSTRAINT_ACCURACY));
#if 1
// Conversion method from OpenSG
// @attention Removed old conversion in Linux build which had numerical
// issues for rotations close to 180 degree! (esquivel 03/2011)
TYPE tr = Base::operator()(0,0) + Base::operator()(1,1) + Base::operator()(2,2);
if (tr > 0.0)
{
// Use default formula if trace is large enough
TYPE s = sqrt(tr + 1.0);
quat[3] = s * 0.5;
s *= 2.0;
quat[0] = (Base::operator()(2,1) - Base::operator()(1,2)) / s;
quat[1] = (Base::operator()(0,2) - Base::operator()(2,0)) / s;
quat[2] = (Base::operator()(1,0) - Base::operator()(0,1)) / s;
}
else
{
// Use alternate formula using largest trace element
TYPE s;
unsigned i;
unsigned j;
unsigned k;
// Find largest trace element i and its successors j, k
if(Base::operator()(1,1) > Base::operator()(0,0))
i = 1;
else
i = 0;
if(Base::operator()(2,2) > Base::operator()(i,i))
i = 2;
j = (i + 1) % 3;
k = (j + 1) % 3;
// Compute discriminator using largest trace element
s = sqrt(Base::operator()(i,i) - (Base::operator()(j,j) + Base::operator()(k,k)) + 1.0);
// Compute quaternion entries
quat[i] = s * 0.5;
s *= 2.0;
quat[j] = (Base::operator()(i,j) + Base::operator()(j,i)) / s;
quat[k] = (Base::operator()(i,k) + Base::operator()(k,i)) / s;
quat[3] = (Base::operator()(k,j) - Base::operator()(j,k) ) / s;
}
#elif 1
// Conversion method using derivation depending on max. denominator
// @see http://en.wikipedia.org/wiki/Rotation_representation_%28mathematics%29#Rotation_matrix_.E2.86.94_quaternion
// @deprecated
// Determine max. denominator
TYPE d[4] = { 1 + Base::operator()(0,0) - Base::operator()(1,1) - Base::operator()(2,2),
1 - Base::operator()(0,0) + Base::operator()(1,1) - Base::operator()(2,2),
1 - Base::operator()(0,0) - Base::operator()(1,1) + Base::operator()(2,2),
1 + Base::operator()(0,0) + Base::operator()(1,1) + Base::operator()(2,2) };
int maxidx = 0;
for (int i = 1; i < 4; i++) {
if (d[maxidx] < d[i]) maxidx = i;
}
// Compute quaternion starting with max. denominator
if (maxidx == 0) {
quat[0]=0.5*sqrt(1 + Base::operator()(0,0) - Base::operator()(1,1) - Base::operator()(2,2));
quat[3]=0.25*(Base::operator()(2,1)-Base::operator()(1,2))/quat[0];
quat[1]=0.25*(Base::operator()(0,1)+Base::operator()(1,0))/quat[0];
quat[2]=0.25*(Base::operator()(0,2)+Base::operator()(2,0))/quat[0];
} else if (maxidx == 1) {
quat[1]=0.5*sqrt(1 - Base::operator()(0,0) + Base::operator()(1,1) - Base::operator()(2,2));
quat[3]=0.25*(Base::operator()(0,2)-Base::operator()(2,0))/quat[1];
quat[2]=0.25*(Base::operator()(1,2)+Base::operator()(2,1))/quat[1];
quat[0]=0.25*(Base::operator()(1,0)+Base::operator()(0,1))/quat[1];
} else if (maxidx == 2) {
quat[2]=0.5*sqrt(1 - Base::operator()(0,0) - Base::operator()(1,1) + Base::operator()(2,2));
quat[3]=0.25*(Base::operator()(1,0)-Base::operator()(0,1))/quat[2];
quat[0]=0.25*(Base::operator()(2,0)+Base::operator()(0,2))/quat[2];
quat[1]=0.25*(Base::operator()(2,1)+Base::operator()(1,2))/quat[2];
} else {
quat[3]=0.5*sqrt(1 + Base::operator()(0,0) + Base::operator()(1,1) + Base::operator()(2,2));
quat[0]=0.25*(Base::operator()(2,1)-Base::operator()(1,2))/quat[3];
quat[1]=0.25*(Base::operator()(0,2)-Base::operator()(2,0))/quat[3];
quat[2]=0.25*(Base::operator()(1,0)-Base::operator()(0,1))/quat[3];
}
#elif 1
// More compact implementation of the conversion method from OpenSG
// @deprecated
TYPE trace = Base::operator()(0,0) + Base::operator()(1,1) + Base::operator()(2,2);
if ( trace > 0 ) {
TYPE s = 2.0 * sqrt(trace + 1.0);
quat[3] = 0.25 * s;
quat[0] = ( Base::operator()(2,1) - Base::operator()(1,2) ) / s;
quat[1] = ( Base::operator()(0,2) - Base::operator()(2,0) ) / s;
quat[2] = ( Base::operator()(1,0) - Base::operator()(0,1) ) / s;
} else {
if ( Base::operator()(0,0) > Base::operator()(1,1) && Base::operator()(0,0) > Base::operator()(2,2) ) {
TYPE s = 2.0 * sqrt( 1.0 + Base::operator()(0,0) - Base::operator()(1,1) - Base::operator()(2,2));
quat[3] = (Base::operator()(2,1) - Base::operator()(1,2) ) / s;
quat[0] = 0.25 * s;
quat[1] = (Base::operator()(0,1) + Base::operator()(1,0) ) / s;
quat[2] = (Base::operator()(0,2) + Base::operator()(2,0) ) / s;
} else if (Base::operator()(1,1) > Base::operator()(2,2)) {
TYPE s = 2.0 * sqrt( 1.0 + Base::operator()(1,1) - Base::operator()(0,0) - Base::operator()(2,2));
quat[3] = (Base::operator()(0,2) - Base::operator()(2,0) ) / s;
quat[0] = (Base::operator()(0,1) + Base::operator()(1,0) ) / s;
quat[1] = 0.25 * s;
quat[2] = (Base::operator()(1,2) + Base::operator()(2,1) ) / s;
} else {
TYPE s = 2.0 * sqrt( 1.0 + Base::operator()(2,2) - Base::operator()(0,0) - Base::operator()(1,1) );
quat[3] = (Base::operator()(1,0) - Base::operator()(0,1) ) / s;
quat[0] = (Base::operator()(0,2) + Base::operator()(2,0) ) / s;
quat[1] = (Base::operator()(1,2) + Base::operator()(2,1) ) / s;
quat[2] = 0.25 * s;
}
}
#else
// Old conversion method
// @see http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
// @deprecated
// @attention Computes wrong quaternion for rotation close to 180 degree!
quat[3] = sqrt( max( 0.0, 1.0 + Base::operator()(0,0) + Base::operator()(1,1) + Base::operator()(2,2) ) ) / 2.0;
quat[0] = sqrt( max( 0.0, 1.0 + Base::operator()(0,0) - Base::operator()(1,1) - Base::operator()(2,2) ) ) / 2.0;
quat[1] = sqrt( max( 0.0, 1.0 - Base::operator()(0,0) + Base::operator()(1,1) - Base::operator()(2,2) ) ) / 2.0;
quat[2] = sqrt( max( 0.0, 1.0 - Base::operator()(0,0) - Base::operator()(1,1) + Base::operator()(2,2) ) ) / 2.0;
quat[0] = copysign( quat[0], Base::operator()(2,1) - Base::operator()(1,2) ) ;
quat[1] = copysign( quat[1], Base::operator()(0,2) - Base::operator()(2,0) ) ;
quat[2] = copysign( quat[2], Base::operator()(1,0) - Base::operator()(0,1) ) ;
#endif
// Normalize resulting quaternion
quat.Normalize();
// Correct quaternion so that scalar part is non-negative
if (quat[3] < 0) quat *= -1.0;
}
template <typename TYPE>
void TRMatrixBase<TYPE>::GetRotationAxisAngle(Vec& Axis, TYPE& Angle) const
{
// nicked from OpenSG
GetQuaternion().GetAxisAngle(Axis, Angle);
}
template <typename TYPE>
typename TRMatrixBase<TYPE>::Vec TRMatrixBase<TYPE>::GetRotationAxis() const
{
Vec Axis;
TYPE Angle;
GetRotationAxisAngle(Axis, Angle);
return Axis;
}
template <typename TYPE>
TYPE TRMatrixBase<TYPE>::GetRotationAngle() const
{
Vec Axis;
TYPE Angle;
GetRotationAxisAngle(Axis, Angle);
return Angle;
}
template <typename TYPE>
int TRMatrixBase<TYPE>::GetRotationAnglesXYZ(TYPE& PhiX, TYPE& PhiY, TYPE& PhiZ) const
{
#if 1
if (Base::operator()(0,2) < 1)
{
if (Base::operator()(0,2) > -1)
{
PhiY = asin(Base::operator()(0,2));
PhiX = atan2(-Base::operator()(1,2), Base::operator()(2,2));
PhiZ = atan2(-Base::operator()(0,1), Base::operator()(0,0));
}
else
{ // WARNING. Not a unique solution.
PhiY = -FHALF_PI;
PhiX = -atan2(Base::operator()(1,0), Base::operator()(1,1));
PhiZ = 0.f; // any angle works
}
}
else
{ // WARNING. Not a unique solution.
PhiY = FHALF_PI;
PhiX = atan2(Base::operator()(1,0), Base::operator()(1,1));
PhiZ = 0.f; // any angle works
}
#else
if ((Base::operator()(0,2) == 1.0)||(Base::operator()(0,2) == -1.0)) {
ASSERT("Rotation for Y-axis is +-PI/2, can not decompose X-/Z-component!" == NULL);
return -1;
}
PhiY = asin(Base::operator()(0,2));
if (ISINFORNAN(PhiY)) return -1;
// changed this from atan to atan2 (koeser)
PhiX = atan2(-Base::operator()(1,2),Base::operator()(2,2));
if (ISINFORNAN(PhiX)) return -2;
PhiZ = atan2(-Base::operator()(0,1),Base::operator()(0,0));
if (ISINFORNAN(PhiZ)) return -3;
#endif
// #ifdef _CPC_DEBUG
// TRMatrixBase<TYPE> R;
// R.SetXYZ(PhiX, PhiY, PhiZ);
// if (R == (*this))
// res = 0;
// else
// res = -1;
// #endif
return 0;
}
template <typename TYPE>
int TRMatrixBase<TYPE>::GetRotationAnglesZXY(TYPE& PhiX, TYPE& PhiY, TYPE& PhiZ) const
{
if ((Base::operator()(0,2) == 1.0)||(Base::operator()(0,2) == -1.0)) {
DEBUG("Rotation for Y-axis is +-PI/2, can not decompose X-/Z-component!");
return -1;
}
PhiZ = atan2(-Base::operator()(0,1),Base::operator()(1,1));
if (ISINFORNAN(PhiZ)) return -3;
PhiX = asin(Base::operator()(2,1));
if (ISINFORNAN(PhiX)) return -2;
PhiY = atan2(-Base::operator()(2,0),Base::operator()(2,2));
if (ISINFORNAN(PhiY)) return -1;
// #ifdef _CPC_DEBUG
// TRMatrixBase<TYPE> R;
// R.SetZXY(PhiX, PhiY, PhiZ);
// cout<<"Erg R: "<<R<<endl;
// if (R == (*this))
// res = 0;
// else
// res = -1;
// #endif
return 0;
}
template <typename TYPE>
int TRMatrixBase<TYPE>::GetRotationAnglesYXZ(TYPE& PhiY, TYPE& PhiX, TYPE& PhiZ) const
{
if ((Base::operator()(0,2) == 1.0)||(Base::operator()(0,2) == -1.0)) {
DEBUG("Rotation for Y-axis is +-PI/2, can not decompose X-/Z-component!");
return -1;
}
PhiZ = atan2(Base::operator()(0,2),Base::operator()(2,2));
if (ISINFORNAN(PhiZ)) return -3;
PhiX = asin(-Base::operator()(1,2));
if (ISINFORNAN(PhiX)) return -2;
PhiY = atan2(Base::operator()(1,0),Base::operator()(1,1));
if (ISINFORNAN(PhiY)) return -1;
// #ifdef _CPC_DEBUG
// TRMatrixBase<TYPE> R;
// R.SetZXY(PhiX, PhiY, PhiZ);
// cout<<"Erg R: "<<R<<endl;
// if (R == (*this))
// res = 0;
// else
// res = -1;
// #endif
return 0;
}
template <typename TYPE>
int TRMatrixBase<TYPE>::GetRotationAnglesZYX(TYPE& PhiX, TYPE& PhiY, TYPE& PhiZ) const
{
if ((Base::operator()(0,2) == 1.0)||(Base::operator()(0,2) == -1.0)) {
DEBUG("Rotation for Y-axis is +-PI/2, cannot decompose X-/Z-component!");
return -1;
}
PhiY = asin(-Base::operator()(2,0));
if (ISINFORNAN(PhiY)) return -1;
// changed this from atan to atan2 (koeser)
PhiX = atan2(Base::operator()(2,1),Base::operator()(2,2));
if (ISINFORNAN(PhiX)) return -2;
PhiZ = atan2(Base::operator()(1,0),Base::operator()(0,0));
if (ISINFORNAN(PhiZ)) return -3;
// #ifdef _CPC_DEBUG
// TRMatrixBase<TYPE> R;
// R.SetZYX(PhiX, PhiY, PhiZ);
// if (R == (*this))
// res = 0;
// else
// res = -1;
// #endif
return 0;
}
template <typename TYPE>
void TRMatrixBase<TYPE>::SetFromQuaternion(const Quat& qu)
{
// fast version, see below for old code:
const TYPE nrm = 1.0/norm(qu);
const TYPE q0 = qu[0]*nrm;
const TYPE q1 = qu[1]*nrm;
const TYPE q2 = qu[2]*nrm;
const TYPE q3 = qu[3]*nrm;
TYPE* pData = val;
*pData++ = 1.0 - 2.0 * (q1 * q1 + q2 * q2);
*pData++ = 2.0 * (q0 * q1 - q2 * q3);
*pData++ = 2.0 * (q2 * q0 + q1 * q3);
*pData++ = 2.0 * (q0 * q1 + q2 * q3);
*pData++ = 1.0 - 2.0 * (q2 * q2 + q0 * q0);
*pData++ = 2.0 * (q1 * q2 - q0 * q3);
*pData++ = 2.0 * (q2 * q0 - q1 * q3);
*pData++ = 2.0 * (q1 * q2 + q0 * q3);
*pData++ = 1.0 - 2.0 * (q1 * q1 + q0 * q0);
#ifdef WANT_TO_COMPARE_WITH_OLD_CODE
Quat q = qu; // de-const
q.Normalize();
// nicked from OpenSG
TRMatrixBase<TYPE> RCompare(MatrixZero);
RCompare[0][0] = 1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]);
RCompare[1][0] = 2.0 * (q[0] * q[1] + q[2] * q[3]);
RCompare[2][0] = 2.0 * (q[2] * q[0] - q[1] * q[3]);
RCompare[0][1] = 2.0 * (q[0] * q[1] - q[2] * q[3]);
RCompare[1][1] = 1.0 - 2.0 * (q[2] * q[2] + q[0] * q[0]);
RCompare[2][1] = 2.0 * (q[1] * q[2] + q[0] * q[3]);
RCompare[0][2] = 2.0 * (q[2] * q[0] + q[1] * q[3]);
RCompare[1][2] = 2.0 * (q[1] * q[2] - q[0] * q[3]);
RCompare[2][2] = 1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]);
for (unsigned i=0; i<3; i++) {
for (unsigned j=0; j<3; j++) {
if (!equal(Base::operator()(i,j), RCompare[i][j], TYPE(1e-12))) {
SLOG("Matrices are not same !"<<*this<<" "<<RCompare<<std::endl);
SLOG(" at "<<i<<" "<<j<<" "<< (Base::operator()(i,j))-(RCompare[i][j])<<std::endl);
ABORT("BIASABORT");
}
}
}
#endif
}
template <typename TYPE>
void TRMatrixBase<TYPE>::SetFromOrthogonalBasis(const Vec& xxx, const Vec& yyy, const Vec& zzz)
{
SetFromRowVectors(normalized(xxx),
normalized(yyy),
normalized(zzz));
}
template <typename TYPE>
void TRMatrixBase<TYPE>::SetFromHV(const Vec& xxx, const Vec& yyy)
{
// normalize
const Vec x0(normalized(xxx));
// compute base z in rhs:
const Vec z0(normalized(cross(xxx, yyy)));
// compute y base orthogonal in rhs
const Vec y0(normalized(cross(z0, x0)));
SetFromColumnVectors(x0, y0, z0);
}
template <typename TYPE>
TRMatrixBase<TYPE>& TRMatrixBase<TYPE>::SetFromDir2Dir(const Vec& dir0, const Vec& dir1)
{
ASSERT(ISEQUAL(norm(dir0), TYPE(1)));
ASSERT(ISEQUAL(norm(dir1), TYPE(1)));
const TYPE cos01(CLAMP(dir1.dot(dir0), TYPE(-1), TYPE(1)));
const TYPE sin01Sq(TYPE(1) - SQUARE(cos01));
if (sin01Sq > EPSILONTOLERANCE<TYPE>()) {
const Vec v(cross(dir0, dir1));
const Mat V(CreateCrossProductMatrix3T<TYPE>(v));
*this = Mat::IDENTITY + V + (V*V)*((TYPE(1)-cos01)/sin01Sq);
} else {
*this = Mat::ZERO;
if (cos01 > TYPE(0)) {
Base::operator()(0,0) = TYPE(1);
Base::operator()(1,1) = TYPE(1);
Base::operator()(2,2) = TYPE(1);
} else {
Base::operator()(0,0) = TYPE(-1);
Base::operator()(1,1) = TYPE(-1);
Base::operator()(2,2) = TYPE(-1);
}
}
return *this;
}
template <typename TYPE>
void TRMatrixBase<TYPE>::SetFromDirUpGL(const Vec& viewDir, const Vec& viewUp)
{
ASSERT(ISEQUAL(norm(viewDir), TYPE(1)));
ASSERT(ISEQUAL(norm(viewUp), TYPE(1)));
const Vec right(normalized(cross(viewDir, viewUp)));
const Vec up(normalized(cross(right, viewDir)));
const Vec forward(viewDir * TYPE(-1)); // convert to right handed system
SetFromColumnVectors(right, up, forward);
}
template <typename TYPE>
void TRMatrixBase<TYPE>::SetFromDirUp(const Vec& viewDir, const Vec& viewUp)
{
ASSERT(ISEQUAL(norm(viewDir), TYPE(1)));
ASSERT(ISEQUAL(norm(viewUp), TYPE(1)));
const Vec right(normalized(cross(viewDir, viewUp)));
const Vec up(normalized(cross(viewDir, right)));
const Vec& forward(viewDir);
SetFromColumnVectors(right, up, forward);
}
template <typename TYPE>
void TRMatrixBase<TYPE>::LookAt(const Vec& from, const Vec& to, const Vec& up)
{
SetFromDirUp(normalized(to-from), up);
}
template <typename TYPE>
inline void TRMatrixBase<TYPE>::SetRotationAxisAngle(const Vec& rot)
{
#if 0
// set rotation using Rodriguez formula
*this = Mat::IDENTITY;
const TYPE thetaSq = normSq(rot);
if (thetaSq < TYPE(1e-12))
return;
const TYPE theta = sqrt(thetaSq);
// make cross product matrix of rot
Mat J;
J(0,0) = TYPE(0); J(0,1) = -rot.z; J(0,2) = rot.y;
J(1,0) = rot.z; J(1,1) = TYPE(0); J(1,2) = -rot.x;
J(2,0) = -rot.y; J(2,1) = rot.x; J(2,2) = TYPE(0);
// compute R matrix
const Mat J2 = J * J;
const TYPE c1 = sin(theta)/theta;
const TYPE c2 = (TYPE(1)-cos(theta))/thetaSq;
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 3; ++j)
(*this)(i,j) += c1*J(i,j) + c2*J2(i,j);
#elif !defined(_USE_EIGEN)
// set rotation using Rodriguez formula
const TYPE x2 = rot.x*rot.x;
const TYPE y2 = rot.y*rot.y;
const TYPE z2 = rot.z*rot.z;
const TYPE t2 = x2+y2+z2;
if (t2 > TYPE(1e-12)) {
// We want to be careful to only evaluate the square root if the
// norm of the angle_axis vector is greater than zero. Otherwise
// we get a division by zero.
const TYPE t = sqrt(t2);
const TYPE ct = /*t==0.0?0.5:*/(TYPE(1)-cos(t))/t2;
const TYPE st = /*t==0.0?1.0:*/sin(t)/t;
val[0] = TYPE(1) - (y2 + z2)*ct;
val[1] = rot.x*rot.y*ct - rot.z*st;
val[2] = rot.z*rot.x*ct + rot.y*st;
val[3] = rot.x*rot.y*ct + rot.z*st;
val[4] = TYPE(1) - (z2 + x2)*ct;
val[5] = rot.y*rot.z*ct - rot.x*st;
val[6] = rot.z*rot.x*ct - rot.y*st;
val[7] = rot.y*rot.z*ct + rot.x*st;
val[8] = TYPE(1) - (x2 + y2)*ct;
} else {
// At zero, we switch to using the first order Taylor expansion.
val[0] = TYPE(1);
val[1] =-rot.z;
val[2] = rot.y;
val[3] = rot.z;
val[4] = TYPE(1);
val[5] =-rot.x;
val[6] =-rot.y;
val[7] = rot.x;
val[8] = TYPE(1);
}
#else
*this = Eigen::SO3<TYPE>(rot).get_matrix();
#endif
}
template <typename TYPE>
inline void TRMatrixBase<TYPE>::Apply(const Vec& delta)
{
const TRMatrixBase dR(delta);
*this = dR * (*this);
}
template <typename TYPE>
inline typename TRMatrixBase<TYPE>::Vec TRMatrixBase<TYPE>::GetRotationAxisAngle() const
{
#if 0
// get parametrized rotation using quaternions
Vec angle_axis;
TYPE angle;
GetQuaternion().GetAxisAngle(angle_axis, angle);
angle_axis.Normalize();
angle_axis *= angle;
return angle_axis;
#elif 0
// get parametrized rotation using Rodriguez formula
Vec angle_axis;
// x = k * 2 * sin(theta), where k is the axis of rotation.
angle_axis[0] = (*this)(2, 1) - (*this)(1, 2);
angle_axis[1] = (*this)(0, 2) - (*this)(2, 0);
angle_axis[2] = (*this)(1, 0) - (*this)(0, 1);
static const TYPE kZero(0);
static const TYPE kOne(1);
static const TYPE kTwo(2);
// Since the right hand side may give numbers just above 1.0 or
// below -1.0 leading to atan misbehaving, we threshold.
const TYPE costheta(MINF(MAXF(((*this)(0, 0) + (*this)(1, 1) + (*this)(2, 2) - kOne)/kTwo, TYPE(-1.0)), kOne));
// sqrt is guaranteed to give non-negative results, so we only
// threshold above.
const TYPE sintheta(MINF(norm(angle_axis)/kTwo, kOne));
// Use the arctan2 to get the right sign on theta
const TYPE theta(atan2(sintheta, costheta));
// Case 1: sin(theta) is large enough, so dividing by it is not a
// problem. We do not use abs here, because while jets.h imports
// std::abs into the namespace, here in this file, abs resolves to
// the int version of the function, which returns zero always.
//
// We use a threshold much larger then the machine epsilon, because
// if sin(theta) is small, not only do we risk overflow but even if
// that does not occur, just dividing by a small number will result
// in numerical garbage. So we play it safe.
static const TYPE kThreshold(TYPE(1e-12));
if ((sintheta > kThreshold) || (sintheta < -kThreshold)) {
angle_axis *= theta / (kTwo * sintheta);
return angle_axis;
}
// Case 2: theta ~ 0, means sin(theta) ~ theta to a good
// approximation.
if (costheta > kZero) {
angle_axis *= TYPE(0.5);
return angle_axis;
}
// Case 3: theta ~ pi, this is the hard case. Since theta is large,
// and sin(theta) is small. Dividing theta by sin(theta) will either
// give an overflow or worse still numerically meaningless results.
// Thus we use an alternate more complicated and expensive formula.
#ifndef _USE_EIGEN
// Since cos(theta) is negative, division by (1-cos(theta)) cannot
// overflow.
const TYPE inv_one_minus_costheta(kOne / (kOne - costheta));
// We now compute the absolute value of coordinates of the axis
// vector using the diagonal entries of R. To resolve the sign of
// these entries, we compare the sign of angle_axis[i]*sin(theta)
// with the sign of sin(theta). If they are the same, then
// angle_axis[i] should be positive, otherwise negative.
for (int i = 0; i < 3; ++i) {
angle_axis[i] = theta * sqrt(((*this)(i, i) - costheta) * inv_one_minus_costheta);
if (((sintheta < kZero) && (angle_axis[i] > kZero)) ||
((sintheta > kZero) && (angle_axis[i] < kZero)))
angle_axis[i] = -angle_axis[i];
}
#else
Eigen::AngleAxis<TYPE> aa;
aa.fromRotationMatrix(Base::EMatMap((TYPE*)this));
angle_axis[0] = aa.angle() * aa.axis()[0];
angle_axis[1] = aa.angle() * aa.axis()[1];
angle_axis[2] = aa.angle() * aa.axis()[2];
#endif
return angle_axis;
#else
return reinterpret_cast<const Eigen::SO3<TYPE>*>(this)->ln();
#endif
}
template <typename TYPE>
bool TRMatrixBase<TYPE>::Check(const TYPE eps, int verbose) const
{
// check determinant
bool ok = equal(TYPE(cv::determinant(*this)), TYPE(1), eps);
// check unit column vector length
Vec cl[3];
for (unsigned i = 0; i < 3 && ok; i++) {
cl[i] = Base::col(i);
ok = equal(norm(cl[i]), TYPE(1), eps);
}
// check orthogonality
if (ok)
ok = equal(cl[0].dot(cl[1]), TYPE(0), eps);
if (ok)
ok = equal(cl[0].dot(cl[2]), TYPE(0), eps);
if (ok)
ok = equal(cl[1].dot(cl[2]), TYPE(0), eps);
#if TD_VERBOSE != TD_VERBOSE_OFF
// print the reason in case of failure
if (!ok && VERBOSITY_LEVEL > verbose) {
std::ostringstream res(" ");
const TYPE det(cv::determinant(*this));
if (!equal(det, TYPE(1), eps)) {
res << "det != 1 (det=" << std::setprecision(30) << det << ") ";
}
for (unsigned i = 0; i < 3; i++) {
cl[i] = Base::col(i);
if (!equal(norm(cl[i]), TYPE(1), eps)) {
res << "col[" << i << "].NormL2() != 1) (= "
<< norm(cl[i]) << ") ";
}
}
if (!equal(cl[0].dot(cl[1]), TYPE(0), eps)) {
res << "col[0].ScalarProduct(c[1]) != 0 (= "
<< cl[0].dot(cl[1]) << ") ";
}
if (!equal(cl[0].dot(cl[2]), TYPE(0), eps)) {
res << "col[0].ScalarProduct(c[2]) != 0 (= "
<< cl[0].dot(cl[2]) << ") ";
}
if (!equal(cl[1].dot(cl[2]), TYPE(0), eps)) {
res << "col[1].ScalarProduct(c[2]) != 0 (= "
<< cl[1].dot(cl[2]) << ") ";
}
SLOG("Rotation matrix is invalid: " << res.str() << std::endl);
}
#endif
return ok;
}
template <typename TYPE>
void TRMatrixBase<TYPE>::EnforceOrthogonality()
{
#if 1
// use SVD decomposition to find the closest orthogonal matrix
const cv::SVD svd(*this, cv::SVD::MODIFY_A|cv::SVD::FULL_UV);
*this = svd.u*svd.vt;
#elif 1
// replaces the 3 x 3 matrix with the nearest (least squares) orthogonal matrix;
// a combination of Babylonian iteration and Berthold KP Horn's formula R = M (MT M)^-1/2
TYPE* r = this->val;
TYPE m[9], ri[9], x[9];
memcpy(m, r, 9*sizeof(TYPE));
//By trial and error I found that 4 iterates always works unless your matrix is waaay off. Limit 10.
for (unsigned iterate = 0; iterate != 10; iterate++) {
//Invert r. Use inverse and not transpose since r is only approximately orthogonal (transpose will result in slow, oscillating convergence).
InvertMatrix3x3(r, ri);
//Get x = ri m + mt r.
x[0] = m[6]*r[6]+ri[2]*m[6]+m[3]*r[3]+ri[1]*m[3]+m[0]*ri[0]+m[0]*r[0];
x[1] = m[6]*r[7]+ri[2]*m[7]+m[3]*r[4]+ri[1]*m[4]+m[0]*r[1]+ri[0]*m[1];
x[2] = m[6]*r[8]+ri[2]*m[8]+m[3]*r[5]+ri[1]*m[5]+m[0]*r[2]+ri[0]*m[2];
x[3] = r[6]*m[7]+ri[5]*m[6]+m[3]*ri[4]+r[3]*m[4]+m[0]*ri[3]+r[0]*m[1];
x[4] = m[7]*r[7]+ri[5]*m[7]+m[4]*ri[4]+m[4]*r[4]+m[1]*ri[3]+m[1]*r[1];
x[5] = m[7]*r[8]+ri[5]*m[8]+m[4]*r[5]+ri[4]*m[5]+m[2]*ri[3]+m[1]*r[2];
x[6] = m[6]*ri[8]+r[6]*m[8]+m[3]*ri[7]+m[0]*ri[6]+r[3]*m[5]+r[0]*m[2];
x[7] = m[7]*ri[8]+r[7]*m[8]+m[4]*ri[7]+m[1]*ri[6]+r[4]*m[5]+r[1]*m[2];
x[8] = m[8]*ri[8]+m[8]*r[8]+m[5]*ri[7]+m[2]*ri[6]+m[5]*r[5]+m[2]*r[2];
//Invert into ri.
InvertMatrix3x3(x, ri);
//Replace r with 2 m ri, where ri is as replaced above.
r[0] = 2*(m[2]*ri[6]+m[1]*ri[3]+m[0]*ri[0]);
r[1] = 2*(m[2]*ri[7]+m[1]*ri[4]+m[0]*ri[1]);
r[2] = 2*(m[2]*ri[8]+m[1]*ri[5]+m[0]*ri[2]);
r[3] = 2*(m[5]*ri[6]+ri[3]*m[4]+ri[0]*m[3]);
r[4] = 2*(m[5]*ri[7]+m[4]*ri[4]+ri[1]*m[3]);
r[5] = 2*(m[5]*ri[8]+m[4]*ri[5]+ri[2]*m[3]);
r[6] = 2*(ri[6]*m[8]+ri[3]*m[7]+ri[0]*m[6]);
r[7] = 2*(ri[7]*m[8]+ri[4]*m[7]+ri[1]*m[6]);
r[8] = 2*(m[8]*ri[8]+ri[5]*m[7]+ri[2]*m[6]);
//Check how off it is.
x[0] = ABS(r[0]*r[0] + r[3]*r[3] + r[6]*r[6] - TYPE(1));
x[1] = ABS(r[1]*r[1] + r[4]*r[4] + r[7]*r[7] - TYPE(1));
x[2] = ABS(r[2]*r[2] + r[5]*r[5] + r[8]*r[8] - TYPE(1));
x[3] = ABS(r[0]*r[1] + r[3]*r[4] + r[6]*r[7]);
x[4] = ABS(r[1]*r[2] + r[4]*r[5] + r[7]*r[8]);
x[5] = ABS(r[2]*r[0] + r[5]*r[3] + r[8]*r[6]);
//Max norm, by all means, really make it as accurate as possible.
TYPE maxElement(-FLT_MAX);
for (unsigned n=6; n != 0; )
if(x[--n] > maxElement)
maxElement = x[n];
if (maxElement < TYPE(1e-15)) return;
}
#else
// Matrix Orthogonalization
// by Eric Raible from "Graphics Gems", Academic Press, 1990
//
// Reorthogonalize matrix R - that is find an orthogonal matrix that is
// "close" to R by computing an approximation to the orthogonal matrix
//
// T -1/2
// RC = R(R R)
// T -1
// [RC is orthogonal because (RC) = (RC) ]
// -1/2
// To compute C, we evaluate the Taylor expansion of F(x) = (I + x)
// (where x = C - I) about x=0.
// This gives C = I - (1/2)x + (3/8)x^2 - (5/16)x^3 + ...
// By default, limit should be 8.
const unsigned max_limit = 8;
static const TYPE coef[10] = { 1, -1/2., 3/8., -5/16., 35/128., -63/256., 231/1024., -429/2048., 6435/32768., -12155/65536. };
Base& R(*this);
const Base RtR(R.t()*R);
const Base X(RtR - Matrix3x3::IDENTITY); /* RtR - I */
Base X_power(Matrix3x3::IDENTITY); /* X^0 */
Base Sum(Matrix3x3::IDENTITY); /* coef[0] * X^0 */
const unsigned limit(MINF(max_limit, (unsigned)10));
for (unsigned power=1; power<limit; ++power) {
X_power = X_power * X;
Sum += coef[power] * X_power;
}
R = R * Sum;
#endif
if (cv::determinant(*this) < 0)
*this *= TYPE(-1);
ASSERT(Check(R_CONSTRAINT_ACCURACY));
}
/*----------------------------------------------------------------*/
// if the matrix is a rotation, then the the transpose should be the inverse
template<typename TYPE>
inline bool IsRotationMatrix(const TMatrix<TYPE,3,3>& R) {
ASSERT(sizeof(TMatrix<TYPE,3,3>) == sizeof(TRMatrixBase<TYPE>));
return ((const TRMatrixBase<TYPE>&)R).IsValid();
} // IsRotationMatrix
template<typename TYPE, int O>
inline bool IsRotationMatrix(const Eigen::Matrix<TYPE,3,3,O>& R) {
// the trace should be three and the determinant should be one
return (ISEQUAL(R.determinant(), TYPE(1)) && ISEQUAL((R*R.transpose()).trace(), TYPE(3)));
} // IsRotationMatrix
/*----------------------------------------------------------------*/
// enforce matrix orthogonality
template<typename TYPE>
inline void EnsureRotationMatrix(TMatrix<TYPE,3,3>& R) {
ASSERT(sizeof(TMatrix<TYPE,3,3>) == sizeof(TRMatrixBase<TYPE>));
((TRMatrixBase<TYPE>&)R).EnforceOrthogonality();
} // EnsureRotationMatrix
/*----------------------------------------------------------------*/
// compute the distance on SO(3) between the two given rotations
// using log(R) as in: "Efficient and Robust Large-Scale Rotation Averaging", 2013
// same result as above, but returns directly the angle
template<typename TYPE>
inline TYPE ComputeAngleSO3(const TMatrix<TYPE,3,3>& I) {
return TYPE(norm(((const TRMatrixBase<TYPE>&)I).GetRotationAxisAngle()));
} // ComputeAngleSO3
template<typename TYPE>
FORCEINLINE TYPE ComputeAngleSO3(const TMatrix<TYPE,3,3>& R1, const TMatrix<TYPE,3,3>& R2) {
return ComputeAngleSO3(TMatrix<TYPE,3,3>(R1*R2.t()));
} // ComputeAngleSO3
/*----------------------------------------------------------------*/
} // namespace SEACAVE