/** * @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: virtual ~Dcm() {}; typedef Matrix Vector3; /** * Standard constructor * * Initializes to identity */ Dcm() : SquareMatrix() { (*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; Type a = q(0); Type b = q(1); Type c = q(2); Type d = q(3); Type aSq = a * a; Type bSq = b * b; Type cSq = c * c; Type dSq = d * d; dcm(0, 0) = aSq + bSq - cSq - dSq; dcm(0, 1) = 2 * (b * c - a * d); dcm(0, 2) = 2 * (a * c + b * d); dcm(1, 0) = 2 * (b * c + a * d); dcm(1, 1) = aSq - bSq + cSq - dSq; dcm(1, 2) = 2 * (c * d - a * b); dcm(2, 0) = 2 * (b * d - a * c); dcm(2, 1) = 2 * (a * b + c * d); dcm(2, 2) = aSq - bSq - cSq + dSq; } /** * 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 : */