/** * @file Dcm.hpp * * A direction cosine matrix class. * All rotations and axis systems follow the right-hand rule. * * This library uses the convention that premultiplying a three dimensional * vector represented in coordinate system 1 will apply a rotation from coordinate system * 1 to coordinate system 2 to the vector. * Likewise, a matrix instance of this class also represents a coordinate transformation * from frame 2 to frame 1. * * @author James Goppert */ #pragma once #include "math.hpp" namespace matrix { template class Quaternion; template class Euler; template class AxisAngle; /** * Direction cosine matrix class * * The rotation between two coordinate frames is * described by this class. */ template class Dcm : public SquareMatrix { public: typedef Matrix Vector3; /** * Standard constructor * * Initializes to identity */ Dcm() { (*this) = eye(); } /** * Constructor from array * * @param _data pointer to array */ Dcm(const Type *data_) : SquareMatrix(data_) { } /** * Copy constructor * * @param other Matrix33 to set dcm to */ Dcm(const Matrix &other) : SquareMatrix(other) { } /** * Constructor from quaternion * * Instance is initialized from quaternion representing * coordinate transformation from frame 2 to frame 1. * * @param q quaternion to set dcm to */ Dcm(const Quaternion &q) { Dcm &dcm = *this; const Type a = q(0); const Type b = q(1); const Type c = q(2); const Type d = q(3); const Type aa = a * a; const Type ab = a * b; const Type ac = a * c; const Type ad = a * d; const Type bb = b * b; const Type bc = b * c; const Type bd = b * d; const Type cc = c * c; const Type cd = c * d; const Type dd = d * d; dcm(0, 0) = aa + bb - cc - dd; dcm(0, 1) = 2 * (bc - ad); dcm(0, 2) = 2 * (ac + bd); dcm(1, 0) = 2 * (bc + ad); dcm(1, 1) = aa - bb + cc - dd; dcm(1, 2) = 2 * (cd - ab); dcm(2, 0) = 2 * (bd - ac); dcm(2, 1) = 2 * (ab + cd); dcm(2, 2) = aa - bb - cc + dd; } /** * Constructor from euler angles * * This sets the transformation matrix from frame 2 to frame 1 where the rotation * from frame 1 to frame 2 is described by a 3-2-1 intrinsic Tait-Bryan rotation sequence. * * * @param euler euler angle instance */ Dcm(const Euler &euler) { Dcm &dcm = *this; Type cosPhi = Type(cos(euler.phi())); Type sinPhi = Type(sin(euler.phi())); Type cosThe = Type(cos(euler.theta())); Type sinThe = Type(sin(euler.theta())); Type cosPsi = Type(cos(euler.psi())); Type sinPsi = Type(sin(euler.psi())); dcm(0, 0) = cosThe * cosPsi; dcm(0, 1) = -cosPhi * sinPsi + sinPhi * sinThe * cosPsi; dcm(0, 2) = sinPhi * sinPsi + cosPhi * sinThe * cosPsi; dcm(1, 0) = cosThe * sinPsi; dcm(1, 1) = cosPhi * cosPsi + sinPhi * sinThe * sinPsi; dcm(1, 2) = -sinPhi * cosPsi + cosPhi * sinThe * sinPsi; dcm(2, 0) = -sinThe; dcm(2, 1) = sinPhi * cosThe; dcm(2, 2) = cosPhi * cosThe; } /** * Constructor from axis angle * * This sets the transformation matrix from frame 2 to frame 1 where the rotation * from frame 1 to frame 2 is described by a 3-2-1 intrinsic Tait-Bryan rotation sequence. * * * @param euler euler angle instance */ Dcm(const AxisAngle &aa) { Dcm &dcm = *this; dcm = Quaternion(aa); } Vector vee() const // inverse to Vector.hat() operation { const Dcm &A(*this); Vector v; v(0) = -A(1, 2); v(1) = A(0, 2); v(2) = -A(0, 1); return v; } void renormalize() { /* renormalize rows */ for (size_t row = 0; row < 3; row++) { matrix::Vector3f rvec(this->_data[row]); this->setRow(row, rvec.normalized()); } } }; typedef Dcm Dcmf; } // namespace matrix /* vim: set et fenc=utf-8 ff=unix sts=0 sw=4 ts=4 : */