Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages | Examples

Rotation.cpp

Go to the documentation of this file.
00001 //////////////////////////////////////////////////////////////////////////////////////////////////
00002 /*! \file Rotation.cpp
00003 *  \brief Implementation of Rotation Namespace Objects.
00004 *  \brief Provides a set of functions to use Rotation matrices
00005 *         and their various representations.
00006 *  \author $Author: jayhawk_hokie $
00007 *  \version $Revision: 1.7 $
00008 *  \date    $Date: 2007/06/01 20:52:16 $
00009 *//////////////////////////////////////////////////////////////////////////////////////////////////
00010 /*  \warning Testing not complete
00011 */
00012 //////////////////////////////////////////////////////////////////////////////////////////////////
00013 
00014 #include "Rotation.h"
00015 
00016 namespace O_SESSAME {
00017 /*! \brief Default Constructor.
00018     * \brief Create a Rotation with no offset.
00019     */
00020 Rotation::Rotation() : m_RotationSense(RIGHT_HAND) { }
00021 
00022 /*! \brief Default Destructor.
00023         */   
00024 Rotation::~Rotation() { }
00025 
00026 /*! \brief Create a Rotation from a direction cosine matrix.
00027     * @param _inMatrix 3x3 matrix of Direction Cosine Matrix (DCM) values.
00028     */
00029 Rotation::Rotation(const Matrix& _inMatrix) { Set(_inMatrix); }
00030 
00031 /*! \brief Create a Rotation from a direction cosine matrix.
00032         * @param _DCM instance of Direction Cosine Matrix (DCM) class.
00033         */
00034 Rotation::Rotation(const DirectionCosineMatrix& _Matrix) { Set(_Matrix); }
00035 
00036 /*! \brief Create a Rotation from an euler angle sequence.
00037         * @param _Angles 3x1 matrix of euler angles.
00038         * @param _Sequence Euler angle rotation sequence. (ie 123, 213, 313, 321, etc).
00039         */
00040 Rotation::Rotation(const Vector& _Angles, const int& _Sequence) { Set(_Angles, _Sequence); }
00041 
00042 /*! \brief Create a Rotation from an euler angle sequence.
00043         * @param _Angle1 first angles in Euler angle set. [rad]
00044         * @param _Angle2 second angles in Euler angle set. [rad]
00045         * @param _Angle3 third angles in Euler angle set. [rad]
00046         * @param _Sequence Euler angle rotation sequence. (ie 123, 213, 313, 321, etc).
00047         */
00048 Rotation::Rotation(const Angle& _Angle1, const Angle& _Angle2, const Angle& _Angle3, const int& _Sequence) { Set(_Angle1, _Angle2, _Angle3, _Sequence); }
00049 
00050 /*! \brief Create a Rotation from a given euler axis and angle.
00051         * @param Axis 3x1 Euler Axis
00052         * @param Angle Angle rotation about axis [rad].
00053         */
00054 Rotation::Rotation(const Vector& _Axis, const Angle& _Angle) { Set(_Axis, _Angle); }
00055 
00056 /*! \brief Create a Rotation from a given set of Modified Rodriguez Parameters.
00057         * @param _MRP 3x1 MRP vector to be represented.
00058         */
00059 Rotation::Rotation(const ModifiedRodriguezParameters& _MRP) { Set(_MRP); }
00060 
00061 /*! \brief Create a Rotation from a given quaternion.
00062         * @param _quat 4x1 quaternion to be represented.
00063         */
00064 Rotation::Rotation(const Quaternion& _quat) { Set(_quat); }
00065 
00066 /*! \brief Set the Rotation from a converted DCM.
00067         * @param _inMatrix 3x3 matrix of Direction Cosine Matrix (DCM) values.
00068         */
00069 void Rotation::Set(const Matrix& _inMatrix)
00070 {/*! \todo Add testing for other types of matrix inputs */
00071     if((_inMatrix[MatrixRowsIndex].getIndexCount() == 3) && (_inMatrix[MatrixColsIndex].getIndexCount() == 3))
00072     {
00073         m_quaternion.Set(DirectionCosineMatrix(_inMatrix));
00074     }
00075     if((_inMatrix[MatrixRowsIndex].getIndexCount() == QUATERNION_SIZE) && (_inMatrix[MatrixColsIndex].getIndexCount() == 1))
00076     {
00077 //        m_quaternion.Set(_inMatrix(_,MatrixIndexBase));
00078     }
00079     return;
00080 }
00081 
00082     /*! \brief Set the Rotation from a converted DCM.
00083         * @param _DCM 3x3 matrix of Direction Cosine Matrix (DCM) values.
00084         */
00085 void Rotation::Set(const DirectionCosineMatrix& _DCM)
00086 {
00087     m_quaternion.Set(_DCM);
00088     return;
00089 }
00090 
00091     /*! \brief Set the Rotation from an euler angle sequence.
00092         * @param _Angles 3x1 matrix of euler angles.
00093         * @param _Sequence Euler angle rotation sequence. (ie 123, 213, 313, 321, etc).
00094         */
00095 void Rotation::Set(const Vector& _Angles, const int& _Sequence)
00096 {
00097     m_quaternion.Set(_Angles, _Sequence);
00098     return;
00099 }
00100 
00101     /*! \brief Create a Rotation from an euler angle sequence.
00102         * @param _Angle1 first angles in Euler angle set. [rad]
00103         * @param _Angle2 second angles in Euler angle set. [rad]
00104         * @param _Angle3 third angles in Euler angle set. [rad]
00105         * @param _Sequence Euler angle rotation sequence. (ie 123, 213, 313, 321, etc).
00106         */
00107 void Rotation::Set(const Angle& _Angle1, const Angle& _Angle2, const Angle& _Angle3, const int& _Sequence)
00108 {
00109     m_quaternion.Set(_Angle1, _Angle2, _Angle3, _Sequence);
00110     return;
00111 }
00112 
00113     /*! \brief Set the Rotation from a converted Euler Axis and Angle set.
00114         * @param _Axis 3x1 Euler Axis.
00115         * @param _Angle Angle rotation about axis [rad].
00116         */
00117 void Rotation::Set(const Vector& _Axis, const Angle& _Angle)
00118 {
00119     m_quaternion.Set(_Axis, _Angle);
00120     return;
00121 }
00122 
00123     /*! \brief Set the Rotation from a converted vector of MRP.
00124         * @param _MRP 3x1 vector of Modified Rodriguez Parameters to set the Rotation.
00125         */
00126 void Rotation::Set(const ModifiedRodriguezParameters& _MRP)
00127 {
00128     m_quaternion.Set(_MRP);
00129     return;
00130 }
00131 
00132     /*! \brief Set the Rotation from a converted quaternion.
00133         * @param _quat 4x1 quaternion to set the Rotation.
00134         */
00135 void Rotation::Set(const Quaternion& _quat)
00136 {
00137     m_quaternion(1) = _quat(1);
00138     m_quaternion(2) = _quat(2);
00139     m_quaternion(3) = _quat(3);
00140     m_quaternion(4) = _quat(4);
00141     return;
00142 }
00143 
00144 // Inspectors
00145     /*! \brief Return the Direction Cosine Matrix (DCM) form of the attitude transformation.
00146         * @return 3x3 Direction Cosine Matrix (DCM).
00147         */
00148 DirectionCosineMatrix Rotation::GetDCM() const
00149 {
00150     return DirectionCosineMatrix(m_quaternion);
00151 }
00152 
00153     /*! \brief Return the Euler angles from the rotation representation.
00154         * @param _Sequence Euler angle rotation sequence. (ie 123, 213, 313, 321, etc).
00155         * @return _Angles 3x1 matrix of euler angles.
00156         */
00157 Vector Rotation::GetEulerAngles(const int& _Sequence) const
00158 {
00159     return m_quaternion.GetEulerAngles(_Sequence);
00160 }
00161 
00162     /*! \brief Return the Euler Axis and Angle form of the attitude transformation.
00163         * @return 4-element vector of the Euler Axis and Angle [EulerAxis; EulerAngle].
00164         */
00165 Vector Rotation::GetEulerAxisAngle() const
00166 {
00167     return m_quaternion.GetEulerAxisAngle();
00168 }
00169 
00170     /*! \brief Return the Euler Axis and Angle form of the attitude transformation.
00171         * @param _EulerAxis 3x1 Euler Axis to be returned.
00172         * @param _EulerAngle Euler angle of rotation [rad].
00173         */
00174 Vector Rotation::GetEulerAxisAngle(Vector& _EulerAxis, Angle& _EulerAngle) const
00175 {
00176     return m_quaternion.GetEulerAxisAngle(_EulerAxis, _EulerAngle);
00177 }
00178 
00179     /*! \brief Return the Modified Rodriguez Parameters vector form of the attitude transformation.
00180         * @return 3x1 MRP vector.
00181         */
00182 ModifiedRodriguezParameters Rotation::GetMRP() const
00183 {
00184     return ModifiedRodriguezParameters(m_quaternion);
00185 }
00186 
00187     /*! \brief Return the quaternion form of the attitude transformation.
00188         * @return 4x1 quaternion.
00189         */
00190 Quaternion Rotation::GetQuaternion() const
00191 {
00192     return m_quaternion;
00193 }
00194 
00195     /*! \brief Return the rotation based on the specified parameterization.
00196         * \todo completely document various rotation return types
00197         * @param _type rotation parameterization type to return the rotation representation in.
00198         * @param _Sequence for Euler Angle sets, specify the desired rotation sequence.
00199         * @return the rotation represented by the specified rotation.
00200         */
00201 Vector Rotation::GetRotation(const RotationType& _type, const int& _Sequence) const
00202 {
00203     if(_type == DCM_Type)
00204     {       
00205         Matrix tempMatrix = GetDCM();
00206         Vector tempVector(DCM_SIZE * DCM_SIZE);
00207         // convert the 3x3 matrix into a 9x1 vector, by rows.
00208         for (int ii = VectorIndexBase; ii < DCM_SIZE + VectorIndexBase; ++ii)
00209         {
00210             tempVector(_(VectorIndexBase + DCM_SIZE*(ii-VectorIndexBase),VectorIndexBase + DCM_SIZE*ii-1)) = ~tempMatrix(ii, _);
00211         }
00212         return tempVector;
00213     }
00214     else if(_type == EulerAngle_Type)
00215     {
00216         return GetEulerAngles(_Sequence);
00217     }
00218     else if(_type == EulerAxisAngle_Type)
00219     {
00220         return GetEulerAxisAngle();
00221     }
00222     else if(_type == MRP_Type)
00223     {
00224         return (Vector)GetMRP();
00225     }
00226     else if(_type == Quaternion_Type)
00227     {
00228         return (Vector)GetQuaternion();
00229     }
00230     
00231     // When in doubt, return the quaternion.
00232     return (Vector)GetQuaternion();
00233 }
00234 
00235     /*! \brief Multiply the rotation matrices together to determine the successive rotation.
00236         * @return the successive rotation representation.
00237         */
00238 Rotation Rotation::operator* (const Rotation& _rot2) const
00239 {
00240     return Rotation((*this).GetDCM() * _rot2.GetDCM());
00241 }
00242     /*! \brief Multiply the rotation by the Vector for a rotation.
00243         * @return 3x1 Rotated vector.
00244         */
00245 Vector Rotation::operator* (const Vector& _vec2) const
00246 {
00247     return ((*this).GetDCM() * _vec2);
00248 }
00249     
00250     /*! \brief Take the inverse of the rotation matrix.
00251         * @return 3x3 Direction Cosine Matrix (DCM).
00252         */
00253 Rotation Rotation::operator~ () const
00254 {
00255     Rotation rotOut(~((*this).GetDCM()));
00256     return rotOut;
00257 }
00258     /*! \brief Determine the successive rotation from the summation of two rotations.
00259         * @param _rot2 Rotation to be summed with.
00260         */
00261 Rotation Rotation::operator+ (const Rotation& _rot2) const
00262 {
00263     Rotation rotOut(this->operator*(_rot2));
00264     return rotOut;
00265 }
00266     /*! \brief Determine the relative rotation from the difference of two rotations.
00267      *  @par Equation:
00268      *  \f[R^{31} = R^{32} * R^{21} \Rightarrow R^{32} = R^{31} - R^{21} = R^{32} * R^{21}^{T}/f]
00269      *  @param _rot2 Rotation to be differenced with.
00270      *  @return rotation of difference between given rotations.
00271      */
00272 Rotation Rotation::operator- (const Rotation& _rot2) const
00273 {
00274     Rotation rotOut(this->operator*(~_rot2));
00275     return rotOut;
00276 }
00277 //////////////////////////////////////////////////////////////////////////
00278 // DirectionCosineMatrix Class
00279     /*! \brief Create a DCM equal to the identity matrix [1,0,0;0,1,0;0,0,1].
00280     *  @return 3x3 Direction Cosine Matrix equal to the identity matrix. 
00281     */
00282 DirectionCosineMatrix::DirectionCosineMatrix():Matrix(DCM_SIZE, DCM_SIZE)
00283 {
00284     (*this) = eye(DCM_SIZE);
00285 }
00286     /*! \brief Create a copy of a DCM from an existing DCM.
00287     * @param _DCM 3x3 Direction Cosine Matrix to be copied.
00288     */
00289 DirectionCosineMatrix::DirectionCosineMatrix(const DirectionCosineMatrix& _DCM):Matrix(DCM_SIZE, DCM_SIZE)
00290 {
00291     Set(_DCM);
00292 }
00293     /*! \brief Create a copy of a DCM from an existing matrix of DCM values.
00294         * @param _DCM 3x3 matrix of DCM values to be copied.
00295         */
00296 DirectionCosineMatrix::DirectionCosineMatrix(const Matrix& _DCM):Matrix(DCM_SIZE, DCM_SIZE)
00297 {
00298     Set(_DCM);
00299 }
00300 
00301     /*! \brief Create a Direction Cosine Matrix (DCM) from Euler Angles.
00302         * @param _EulerAngles 3x1 matrix of Euler Angles. [rad]
00303         * @param _Sequence Euler angle rotation sequence. (ie 123, 213, 313, 321, etc).
00304         */
00305 DirectionCosineMatrix::DirectionCosineMatrix(const Vector& _EulerAngles, const int& _Sequence):Matrix(DCM_SIZE, DCM_SIZE)
00306 {       
00307     Set(_EulerAngles, _Sequence);
00308 }
00309 
00310     /*! \brief Create a Direction Cosine Matrix (DCM) from Euler Angles.
00311         * @param _Angle1 first angles in Euler angle set. [rad]
00312         * @param _Angle2 second angles in Euler angle set. [rad]
00313         * @param _Angle3 third angles in Euler angle set. [rad]
00314         * @param _Sequence Euler angle rotation sequence. (ie 123, 213, 313, 321, etc).
00315         */
00316 DirectionCosineMatrix::DirectionCosineMatrix(const Angle& _Angle1, const Angle& _Angle2, const Angle& _Angle3, const int& _Sequence):Matrix(DCM_SIZE, DCM_SIZE)
00317 {       
00318     Set(_Angle1, _Angle2, _Angle3, _Sequence);
00319 }
00320 
00321     /*! \brief Create a Direction Cosine Matrix (DCM) from an Euler Axis and rotation.
00322         * @param _EulerAxis 3x1 Euler Axis vector (\f$\hat{e}\f$).
00323         * @param _EulerAngle Angle rotation about axis (\f$\Phi\f$)[rad].
00324         */
00325 DirectionCosineMatrix::DirectionCosineMatrix(const Vector& _EulerAxis, const Angle& _EulerAngle):Matrix(DCM_SIZE, DCM_SIZE)
00326 {       
00327     Set(_EulerAxis, _EulerAngle);
00328 }
00329 
00330     /*! \brief Create a Direction Cosine Matrix (DCM) from a vector of Modified Rodriguez Parameters (MRP).
00331         * @param _MRP 3x1 MRP to be converted.
00332         */
00333 DirectionCosineMatrix::DirectionCosineMatrix(const ModifiedRodriguezParameters& _MRP):Matrix(DCM_SIZE, DCM_SIZE)
00334 {       
00335     Set(_MRP);
00336 }
00337     /*! \brief Create a Direction Cosine Matrix (DCM) from a quaternion.
00338         * @param _quat 4x1 quaternion to be converted.
00339         *  @return 3x3 Direction Cosine Matrix. 
00340         */
00341 DirectionCosineMatrix::DirectionCosineMatrix(const Quaternion& _quat):Matrix(DCM_SIZE, DCM_SIZE)
00342 {       
00343     Set(_quat);
00344 }
00345     /*! \brief Default deconstructor. 
00346     */
00347 DirectionCosineMatrix::~DirectionCosineMatrix() 
00348 {
00349 }
00350 
00351     /*! \brief Set a DCM to a copy of another DCM.
00352         * @param _DCM 3x3 DCM to be copied.
00353         */
00354 void DirectionCosineMatrix::Set(const DirectionCosineMatrix& _DCM)
00355 {
00356     for (int ii = MatrixIndexBase; ii <= _DCM[MatrixRowsIndex].getIndexBound(); ++ii)
00357         for (int jj = MatrixIndexBase; jj <= _DCM[MatrixColsIndex].getIndexBound(); ++jj)
00358             (*this)(ii,jj) = _DCM(ii,jj);
00359     Normalize();
00360     return;
00361 }
00362 
00363     /*! \brief Set a DCM to a copy of an matrix that is a DCM.
00364         * @param _DCM 3x3 Matrix of DCM values to be copied.
00365         */
00366 void DirectionCosineMatrix::Set(const Matrix& _DCM)
00367 {
00368     for (int ii = MatrixIndexBase; ii <= _DCM[MatrixRowsIndex].getIndexBound(); ++ii)
00369         for (int jj = MatrixIndexBase; jj <= _DCM[MatrixColsIndex].getIndexBound(); ++jj)
00370             (*this)(ii,jj) = _DCM(ii,jj);
00371     Normalize();
00372     return;
00373 }
00374 
00375     /*! \brief Set the DCM to the transformation of set of Euler Angles.
00376         * @param _EulerAngles 3x1 matrix of Euler Angles. [rad]
00377         * @param _Sequence Euler angle rotation sequence. (ie 123, 213, 313, 321, etc).
00378         */
00379 void DirectionCosineMatrix::Set(const Vector& _EulerAngles, const int& _Sequence)
00380 {
00381     Set(_EulerAngles(VectorIndexBase+0), _EulerAngles(VectorIndexBase+1), _EulerAngles(VectorIndexBase+2), _Sequence);
00382     return;
00383 }
00384 
00385     /*! \brief Set the DCM to the transformation of set of Euler Angles.
00386         * @param _Angle1 first angles in Euler angle set. [rad]
00387         * @param _Angle2 second angles in Euler angle set. [rad]
00388         * @param _Angle3 third angles in Euler angle set. [rad]
00389         * @param _Sequence Euler angle rotation sequence. (ie 123, 213, 313, 321, etc).
00390         */
00391 void DirectionCosineMatrix::Set(const Angle& _Angle1, const Angle& _Angle2, const Angle& _Angle3, const int& _Sequence)
00392 {
00393     switch(_Sequence)
00394     {
00395         case 121: (*this) = R1(_Angle3) * R2(_Angle2) * R1(_Angle1); break;
00396         case 131: (*this) = R1(_Angle3) * R3(_Angle2) * R1(_Angle1); break;
00397         case 132: (*this) = R2(_Angle3) * R3(_Angle2) * R1(_Angle1); break;
00398         case 123: (*this) = R3(_Angle3) * R2(_Angle2) * R1(_Angle1); break;
00399         case 212: (*this) = R2(_Angle3) * R1(_Angle2) * R2(_Angle1); break;
00400         case 321: (*this) = R1(_Angle3) * R2(_Angle2) * R3(_Angle1); break;
00401         case 232: (*this) = R2(_Angle3) * R3(_Angle2) * R2(_Angle1); break;
00402         case 231: (*this) = R1(_Angle3) * R3(_Angle2) * R2(_Angle1); break;
00403         case 213: (*this) = R3(_Angle3) * R1(_Angle2) * R2(_Angle1); break;
00404         case 313: (*this) = R3(_Angle3) * R1(_Angle2) * R3(_Angle1); break;
00405         case 323: (*this) = R3(_Angle3) * R2(_Angle2) * R3(_Angle1); break;
00406         case 312: (*this) = R2(_Angle3) * R1(_Angle2) * R3(_Angle1); break;
00407         default: (*this) = eye(DCM_SIZE);
00408     }
00409     Normalize();
00410     return;
00411 }
00412 
00413 /*! \brief Set the DCM to the transformation of an Euler Axis and Angle.
00414         * @param _EulerAxis 3x1 Euler Axis vector (\f$\hat{e}\f$).
00415         * @param _EulerAngle Angle rotation about axis (\f$\Phi\f$)[rad].
00416         *
00417         * \par Equation: (Ref Wertz, pg. 413)
00418         * \f[
00419         * \bf{R}
00420         * =
00421         * \begin{bmatrix}
00422         * e^{2}_1 \Phi + \cos{\phi} & e_1 e_2 \Phi + e_3\sin{\phi} & e_1 e_3 \Phi - e_2\sin{\phi}\\
00423         * e_2 e_1 \Phi - e_3\sin{\phi} & e^{2}_2 \Phi + \cos{\phi} & e_2 e_3 \Phi + e_1\sin{\phi}\\
00424         * e_3 e_1 \Phi + e_2\sin{\phi} & e_3 e_2 \Phi - e_1\sin{\phi} & e^{2}_3 \Phi + \cos{\phi}
00425         * \end{bmatrix}
00426         * \f]
00427         * where \f$\Phi= 1 - \cos{\phi}\f$ (Ref Hughes p.12)
00428         */
00429 void DirectionCosineMatrix::Set(const Vector& _EulerAxis, const Angle& _EulerAngle)
00430 {
00431     // Calculations done for each element to increase speed
00432     double Phi = 1 - cos(_EulerAngle);
00433     double e1 = _EulerAxis(VectorIndexBase+0);
00434     double e2 = _EulerAxis(VectorIndexBase+1);
00435     double e3 = _EulerAxis(VectorIndexBase+2);
00436     double cosPhi = cos(_EulerAngle);
00437     double sinPhi = sin(_EulerAngle);
00438     
00439     // Column 1
00440     (*this)(MatrixIndexBase+0,MatrixIndexBase+0) = e1 * e1 * Phi + cosPhi;
00441     (*this)(MatrixIndexBase+1,MatrixIndexBase+0) = e2 * e1 * Phi - e3 * sinPhi;
00442     (*this)(MatrixIndexBase+2,MatrixIndexBase+0) = e3 * e1 * Phi + e2 * sinPhi;
00443         
00444     // Column 2
00445     (*this)(MatrixIndexBase+0,MatrixIndexBase+1) = e1 * e2 * Phi + e3 * sinPhi;
00446     (*this)(MatrixIndexBase+1,MatrixIndexBase+1) = e2 * e2 * Phi + cosPhi; 
00447     (*this)(MatrixIndexBase+2,MatrixIndexBase+1) = e3 * e2 * Phi - e1 * sinPhi;
00448     
00449     // Column 3
00450     (*this)(MatrixIndexBase+0,MatrixIndexBase+2) = e1 * e3 * Phi - e2 * sinPhi;
00451     (*this)(MatrixIndexBase+1,MatrixIndexBase+2) = e2 * e3 * Phi + e1 * sinPhi;
00452     (*this)(MatrixIndexBase+2,MatrixIndexBase+2) = e3 * e3 * Phi + cosPhi;
00453     Normalize();
00454     return;
00455 }
00456 
00457 /*! \brief Set the DCM to the transformation of Modified Rodriguez Paramaters (MRP).
00458         * @param _MRP 3x1 matrix of Modified Rodriguez Parameters (MRP).
00459         * \par Equation: 
00460         * \f[
00461         * \left[\bf{R}\left(\bf{\sigma}\right)\right]
00462         * =
00463         * \frac{1}{\left(1+\sigma^2\right)^2}
00464         * \begin{bmatrix}
00465         * 4\left(\sigma^{2}_1-\sigma^{2}_2-\sigma^{2}_3\right)+\Sigma^2 & 8\sigma_1\sigma_2+4\sigma_3\Sigma & 8\sigma_1\sigma_3-4\sigma_2\Sigma\\
00466         * 8\sigma_2\sigma_1-4\sigma_3\Sigma & 4\left(-\sigma^{2}_1+\sigma^{2}_2-\sigma^{2}_3\right)+\Sigma^2 & 8\sigma_2\sigma_3+4\sigma_1\Sigma
00467         * 8\sigma_3\sigma_1+4\sigma_2\Sigma & 8\sigma_3\sigma_2-4\sigma_1\Sigma & 4\left(-\sigma^{2}_1-\sigma^{2}_2+\sigma^{2}_3\right)+\Sigma^2
00468         * \end{bmatrix}
00469         * \f]
00470         * where \f$\Sigma=1-\bf{\sigma}^T\bf{\sigma}\f$
00471         */
00472 void DirectionCosineMatrix::Set(const ModifiedRodriguezParameters& _MRP)
00473 {
00474     // Calculations done for each element to increase speed
00475     Matrix tempMatrix = (~(_MRP) * _MRP);
00476     double Sigma = 1 - tempMatrix(MatrixIndexBase,MatrixIndexBase);
00477     double sigma1 = _MRP(VectorIndexBase+0);
00478     double sigma2 = _MRP(VectorIndexBase+1);
00479     double sigma3 = _MRP(VectorIndexBase+2);
00480     
00481     // Column 1
00482     (*this)(MatrixIndexBase+0,MatrixIndexBase+0) = 4*(sigma1*sigma1 - sigma2*sigma2 - sigma3*sigma3) + Sigma*Sigma;
00483     (*this)(MatrixIndexBase+1,MatrixIndexBase+0) = 8*sigma2*sigma1 - 4*sigma3*Sigma;
00484     (*this)(MatrixIndexBase+2,MatrixIndexBase+0) = 8*sigma3*sigma1 + 4*sigma2*Sigma;
00485     
00486     // Column 2
00487     (*this)(MatrixIndexBase+0,MatrixIndexBase+1) = 8*sigma1*sigma2 + 4*sigma3*Sigma;
00488     (*this)(MatrixIndexBase+1,MatrixIndexBase+1) = 4*(-sigma1*sigma1 + sigma2*sigma2 - sigma3*sigma3) + Sigma*Sigma;
00489     (*this)(MatrixIndexBase+2,MatrixIndexBase+1) = 8*sigma3*sigma2 - 4*sigma1*Sigma;
00490     
00491     // Column 3
00492     (*this)(MatrixIndexBase+0,MatrixIndexBase+2) = 8*sigma1*sigma3 - 4*sigma2 * Sigma;
00493     (*this)(MatrixIndexBase+1,MatrixIndexBase+2) = 8*sigma2*sigma3 + 4*sigma1*Sigma;
00494     (*this)(MatrixIndexBase+2,MatrixIndexBase+2) = 4*(-sigma1*sigma1 - sigma2*sigma2 + sigma3*sigma3) + Sigma*Sigma;
00495 
00496     // Multiplying factor
00497     (*this) /= pow(1 + tempMatrix(MatrixIndexBase,MatrixIndexBase), 2);
00498     Normalize();
00499     return;
00500 }
00501 
00502 /*! \brief Set a DCM to the transformation of a quaternion.
00503         * \par Equation: 
00504         * @param _qIn 4x1 quaternion to be converted.
00505         * \par Equation: (Ref Wertz, pg. 414)
00506         * \f[
00507         * \left[\bf{R}\left(\bf{\bar{q}}\right)\right]
00508         * =
00509         * \begin{bmatrix}
00510         * 1-2(q_{2}^{2}+q_{3}^{2}) & 2\left(q_1 q_2 + q_4 q_3\right) & 2\left(q_1 q_3 - q_4 q_2\right)\\
00511         * 2\left(q_1 q_2 - q_4 q_3\right) & 1-2(q_{1}^{2}+q_{3}^{2}) & 2\left(q_2 q_3 + q_4 q_1\right)\\
00512         * 2\left(q_1 q_3 + q_4 q_2\right) & 2\left(q_2 q_3 - q_4 q_1\right) & 1-2(q_{1}^{2}+q_{2}^{2})
00513         * \end{bmatrix}
00514         * \f]
00515         */
00516 void DirectionCosineMatrix::Set(const Quaternion& _qIn)
00517 {
00518     // Calculations done for each element to increase speed
00519     double q1 = _qIn(VectorIndexBase+0);
00520     double q2 = _qIn(VectorIndexBase+1);
00521     double q3 = _qIn(VectorIndexBase+2);
00522     double q4 = _qIn(VectorIndexBase+3);
00523 
00524     // Column 1
00525     (*this)(MatrixIndexBase+0,MatrixIndexBase+0) = q4*q4 + q1*q1 - q2*q2 - q3*q3;
00526 //    (*this)(MatrixIndexBase+0,MatrixIndexBase+0) = 1 - 2 * (q2*q2 + q3*q3);
00527     (*this)(MatrixIndexBase+1,MatrixIndexBase+0) = 2 * (q1*q2 - q4*q3);
00528     (*this)(MatrixIndexBase+2,MatrixIndexBase+0) = 2 * (q1*q3 + q4*q2);
00529     
00530     // Column 2
00531     (*this)(MatrixIndexBase+0,MatrixIndexBase+1) = 2 * (q1*q2 + q4*q3);
00532     (*this)(MatrixIndexBase+1,MatrixIndexBase+1) = q4*q4 - q1*q1 + q2*q2 -q3*q3;
00533 //    (*this)(MatrixIndexBase+0,MatrixIndexBase+0) = 1 - 2 * (q1*q1 + q3*q3);
00534     (*this)(MatrixIndexBase+2,MatrixIndexBase+1) = 2 * (q2*q3 - q4*q1);
00535     
00536     // Column 3
00537     (*this)(MatrixIndexBase+0,MatrixIndexBase+2) = 2 * (q1*q3 - q4*q2);
00538     (*this)(MatrixIndexBase+1,MatrixIndexBase+2) = 2 * (q2*q3 + q4*q1);
00539 //    (*this)(MatrixIndexBase+0,MatrixIndexBase+0) = 1 - 2 * (q1*q1 + q2*q2);
00540     (*this)(MatrixIndexBase+2,MatrixIndexBase+2) = q4*q4 - q1*q1 - q2*q2 + q3*q3; 
00541     
00542     Normalize();
00543     return;
00544 }
00545 
00546     /*! 
00547         * \brief Convert a DCM to a set of Euler Angles.
00548         * @param _Sequence Euler angle rotation sequence. (ie 123, 213, 313, 321, etc).
00549         * @return (3 x 1) Euler Angles based on given rotation sequence.  The angles are returned in the order of the rotation sequence.  For a 321 sequence, the first and third angles lie within the domain of [-180,180] and the second angle lies within [-90,90].
00550         */
00551 Vector DirectionCosineMatrix::GetEulerAngles(const int& _Sequence) const
00552 
00553 {
00554     Vector eulerAngles(3);
00555 
00556     switch(_Sequence)
00557     {
00558         case 321:
00559             eulerAngles(1) = atan2( ((*this)(1,2)),((*this)(1,1)) );
00560             eulerAngles(2) = asin(-(*this)(1,3));
00561             eulerAngles(3) = atan2( ((*this)(2,3)),((*this)(3,3)) );
00562             break;              
00563         default:
00564             cout << "This angle sequence is currently not supported." << endl;
00565     }
00566         
00567     return eulerAngles;
00568 }
00569 
00570 /*! \brief Convert the DCM to an Euler Axis and Angle.
00571         * @param _EulerAxis 3x1 Euler Axis vector (\f$\hat{e}\f$).
00572         * @param _EulerAngle Angle rotation about axis (\f$\Phi\f$)[rad].
00573         * \par Equation: 
00574         * Ref Wertz, pg 413-4
00575         * \f[ \cos\Phi = \frac{1}{2}\left[tr\left(R\right)-1\right] \f]
00576         * if \f$\sin\Phi \ne 0\f$, the componnets of \f$\hat{\bf e}\f$ are given by:
00577         * \f[
00578         * e1 = (A_{23} - A_{32})/(2\sin\Phi)
00579         * e2 = (A_{31} - A_{13})/(2\sin\Phi)
00580         * e3 = (A_{12} - A_{21})/(2\sin\Phi)
00581         * \f]
00582         */
00583 void DirectionCosineMatrix::GetEulerAxisAngle(Vector& _EulerAxis, Angle& _EulerAngle) const
00584 {
00585     _EulerAngle = acos(0.5 * (trace(*this) - 1));
00586     if(sin(_EulerAngle) != 0)
00587     {
00588         _EulerAxis(VectorIndexBase + 0) = ((*this)(MatrixIndexBase+1,MatrixIndexBase+2)
00589                                            - (*this)(MatrixIndexBase+1,MatrixIndexBase+2))
00590         / (2 * sin(_EulerAngle));
00591         _EulerAxis(VectorIndexBase + 1) = ((*this)(MatrixIndexBase+2,MatrixIndexBase+0)
00592                                            - (*this)(MatrixIndexBase+0,MatrixIndexBase+2))
00593             / (2 * sin(_EulerAngle));
00594         _EulerAxis(VectorIndexBase + 2) = ((*this)(MatrixIndexBase+0,MatrixIndexBase+1)
00595                                            - (*this)(MatrixIndexBase+0,MatrixIndexBase+1))
00596             / (2 * sin(_EulerAngle));
00597     }
00598     else
00599     { // no rotation, or rotation of 180 degs, therefore arbitrary axis.
00600         _EulerAxis.setToValue(0.0);
00601         _EulerAxis(VectorIndexBase + 0) = 1;
00602     }
00603     return;
00604 }
00605 
00606 /*! \brief Convert a DCM to an MRP representation.
00607         * This conversion is performed by creating a new instance of an MRP
00608         *       from this DCM. (\sa ModifiedRodriguezParameters::Set(DirectionCosineMatrix))
00609         * @return This conversion returns a (3 x 1) converted MRP. 
00610         */
00611 ModifiedRodriguezParameters DirectionCosineMatrix::GetMRP() const
00612 {
00613     return ModifiedRodriguezParameters(*this);
00614 }
00615 
00616 /*! \brief Convert a DCM to a quaternion representation.
00617         * This conversion is performed by creating a new instance of a Quaternion
00618         *       from this DCM. (\sa Quaternion::Set(DirectionCosineMatrix))
00619         *  @return This conversion returns a (4 x 1) converted quaternion. 
00620         */
00621 Quaternion DirectionCosineMatrix::GetQuaternion() const
00622 {
00623     return Quaternion(*this);
00624 }
00625 
00626 /*! \brief Normalize the Direction Cosine Matrix.
00627         *  This member function normalizes and stores the DCM. Normalization is performed 
00628         *       by dividing each element in a column by the square-root of the sum of the squares of a column.
00629         *       \f[R_{ij}^{norm} = \frac{R_{ij}}{\sum_{k=1}^{k=3}{R_{ik}}}\f] 
00630         */
00631 void DirectionCosineMatrix::Normalize()
00632 {
00633     double total = 0;
00634     
00635     for (int ii = MatrixIndexBase; ii < MatrixIndexBase + DCM_SIZE; ++ii)
00636     {
00637         total = sqrt(pow((*this)(ii, MatrixIndexBase),2) 
00638                         + pow((*this)(ii, MatrixIndexBase+1),2) 
00639                         + pow((*this)(ii, MatrixIndexBase+2),2));
00640         for (int jj = MatrixIndexBase; jj < MatrixIndexBase + DCM_SIZE; ++jj)
00641         {
00642             (*this)(ii, jj) /= total;
00643         }
00644     }    
00645     return;
00646 }
00647 
00648     /*! \brief Determine the successive rotation from the summation of two DCMs.
00649         * @param _DCM2 DCM to be summed with.
00650         */
00651 DirectionCosineMatrix DirectionCosineMatrix::operator+ (const DirectionCosineMatrix& _DCM2) const
00652 {
00653     return DirectionCosineMatrix(Matrix::operator+(static_cast<Matrix>(_DCM2)));
00654 }
00655 
00656     /*! 
00657         * \brief Determine the relative rotation from the difference of two DCMs.
00658         * @param _DCM2 DCM to be differenced with.
00659         */
00660 DirectionCosineMatrix DirectionCosineMatrix::operator- (const DirectionCosineMatrix& _DCM2) const
00661 {
00662     return DirectionCosineMatrix(Matrix::operator-(static_cast<Matrix>(_DCM2)));
00663 }
00664 
00665 /*! \brief Determine the successive rotation of the DCMs through multiplication.
00666         * @param _DCM2 DCM to be multiplied by.
00667         */
00668 DirectionCosineMatrix DirectionCosineMatrix::operator* (DirectionCosineMatrix _DCM2) const 
00669 {
00670     return DirectionCosineMatrix(Matrix::operator*(static_cast<Matrix>(_DCM2)));
00671 }
00672 
00673     /*! \brief Determine the rotation of a vector by a DCM.
00674         * @param _DCM2 DCM to be multiplied by.
00675         */
00676 inline Vector DirectionCosineMatrix::operator* (const Vector& _vec) const 
00677 {
00678     return Matrix::operator*(_vec);
00679 }
00680 
00681     /*! \brief Determines the inverse of a DCM by taking the transpose (same operation).
00682         * @return Inverse (transpose) of DCM.
00683         */
00684 DirectionCosineMatrix DirectionCosineMatrix::operator~ () 
00685 {
00686     return DirectionCosineMatrix(Matrix::operator~());
00687 }
00688 
00689 /*! \brief Calculates the principal rotation of the angle about the 1-axis.
00690     * \relates DirectionCosineMatrix
00691     * \ingroup RotationLibrary
00692     * @param _Angle Angle of Rotation [rad].
00693     *  \par Equation:
00694     * \f[
00695     * R_1\left(\theta\right) =
00696     * \begin{bmatrix}
00697     * 1 & 0 & 0\\
00698     * 0 & \cos{\theta} & \sin{\theta}\\
00699     * 0 & -\sin{\theta} & \cos{\theta}
00700     * \end{bmatrix}
00701     * \f]
00702     */
00703 DirectionCosineMatrix R1(const Angle& _Angle)
00704 {
00705     DirectionCosineMatrix R1_Out;
00706     R1_Out(MatrixIndexBase+1, MatrixIndexBase+1) = cos(_Angle);
00707     R1_Out(MatrixIndexBase+1, MatrixIndexBase+2) = sin(_Angle);
00708     R1_Out(MatrixIndexBase+2, MatrixIndexBase+1) = -sin(_Angle);
00709     R1_Out(MatrixIndexBase+2, MatrixIndexBase+2) = cos(_Angle);
00710     return R1_Out;
00711 }
00712 
00713 /*! \brief Calculates the principal rotation of the angle about the 2-axis.
00714     * \relates DirectionCosineMatrix
00715     * \ingroup RotationLibrary
00716     * @param _Angle Angle of Rotation [rad].
00717     * \par Equation:
00718     * \f[
00719     * R_2\left(\theta\right) =
00720     * \begin{bmatrix}
00721     * \cos{\theta} & 0 & -\sin{\theta}\\
00722     * 0 & 1 & 0\\
00723     * \sin{\theta} & 0 & \cos{\theta}
00724     * \end{bmatrix}
00725     * \f]
00726     */
00727 DirectionCosineMatrix R2(const Angle& _Angle)
00728 {
00729     DirectionCosineMatrix R2_Out;
00730     R2_Out(MatrixIndexBase+0, MatrixIndexBase+0) = cos(_Angle);
00731     R2_Out(MatrixIndexBase+0, MatrixIndexBase+2) = -sin(_Angle);
00732     R2_Out(MatrixIndexBase+2, MatrixIndexBase+0) = sin(_Angle);
00733     R2_Out(MatrixIndexBase+2, MatrixIndexBase+2) = cos(_Angle);
00734     return R2_Out;
00735 }
00736 
00737 /*! \brief Calculates the principal rotation of the angle about the 3-axis.
00738     * \relates DirectionCosineMatrix
00739     * \ingroup RotationLibrary
00740     * @param _Angle Angle of Rotation [rad].
00741     * \par Equation:
00742     * \f[
00743     * R_3\left(\theta\right) =
00744     * \begin{bmatrix}
00745     * \cos{\theta} & \sin{\theta} & 0\\
00746     * -\sin{\theta} & \cos{\theta} & 0\\
00747     * 0 & 0 & 1
00748     * \end{bmatrix}
00749     * \f]
00750     */
00751 DirectionCosineMatrix R3(const Angle& _Angle)
00752 {
00753     DirectionCosineMatrix R3_Out;
00754     R3_Out(MatrixIndexBase+0, MatrixIndexBase+0) = cos(_Angle);
00755     R3_Out(MatrixIndexBase+0, MatrixIndexBase+1) = sin(_Angle);
00756     R3_Out(MatrixIndexBase+1, MatrixIndexBase+0) = -sin(_Angle);
00757     R3_Out(MatrixIndexBase+1, MatrixIndexBase+1) = cos(_Angle);
00758     return R3_Out;
00759 }
00760 
00761 //////////////////////////////////////////////////////////////////////////
00762 // ModifiedRodriguezParameters Class
00763     /*! \brief Default Constructor.
00764     * \brief Create an MRP set with intial value of [0,0,0]^T.
00765     */
00766 ModifiedRodriguezParameters::ModifiedRodriguezParameters():Vector(MRP_SIZE)
00767 {
00768     AutoSwitch();
00769 }
00770 
00771     /*! \brief Copy Constructor.
00772     * \brief Create a copy of an MRP set.
00773     */
00774 ModifiedRodriguezParameters::ModifiedRodriguezParameters(const ModifiedRodriguezParameters& _MRP):Vector(MRP_SIZE)
00775 {
00776     Set(_MRP);
00777     AutoSwitch();
00778 }
00779 
00780     /*! \brief Create an MRP set based on 3 values.
00781     * @param _s1 first MRP value.
00782     * @param _s2 second MRP value.
00783     * @param _s3 third MRP value.
00784     */
00785 ModifiedRodriguezParameters::ModifiedRodriguezParameters(const double& _s1, const double& _s2, const double& _s3):Vector(MRP_SIZE)
00786 {
00787     Set(_s1,_s2,_s3);
00788     AutoSwitch();
00789 }
00790     
00791     /*! \brief Create an MRP set from a vector 3 values.
00792         * @param _sVector 3x1 vector of MRP values.
00793         */
00794 ModifiedRodriguezParameters::ModifiedRodriguezParameters(const Vector& _sVector):Vector(MRP_SIZE)
00795 {
00796     Set(_sVector);
00797     AutoSwitch();
00798 }
00799 
00800     /*! \brief Create an MRP set converted from a Direction Cosine Matrix (DCM).
00801         * @param _DCM 3x3 Direction Cosine Matrix (DCM) to be converted.
00802         */
00803 ModifiedRodriguezParameters::ModifiedRodriguezParameters(const DirectionCosineMatrix& _DCM):Vector(MRP_SIZE)
00804 {
00805     Set(_DCM);
00806     AutoSwitch();
00807 }
00808 
00809     /*! \brief Create an MRP set from an Euler Angle sequence.
00810         * @param _Angles 3x1 matrix of euler angles. [rad]
00811         * @param _Sequence Euler angle rotation sequence. (ie 123, 213, 313, 321, etc).
00812         */
00813 ModifiedRodriguezParameters::ModifiedRodriguezParameters(const Vector& _Angles, const int& _Sequence):Vector(MRP_SIZE)
00814 {
00815     Set(_Angles, _Sequence);
00816     AutoSwitch();
00817 }
00818 
00819     /*! 
00820         * \brief Create the MRP from an Euler Axis and Angle.
00821         * @param _EulerAxis 3x1 Euler Axis vector (\f$\hat{e}\f$).
00822         * @param _EulerAngle Angle rotation about axis (\f$\Phi\f$)[rad].
00823         */
00824 ModifiedRodriguezParameters::ModifiedRodriguezParameters(const Vector& _EulerAxis, const Angle& _EulerAngle):Vector(MRP_SIZE)
00825 {
00826     Set(_EulerAxis, _EulerAngle);
00827     AutoSwitch();
00828 }
00829     
00830     /*! \brief Create an MRP set converted from a quaternion.
00831         * @param _DCM 4x1 quaternion to be converted.
00832         */
00833 ModifiedRodriguezParameters::ModifiedRodriguezParameters(const Quaternion& _qIn):Vector(MRP_SIZE)
00834 {
00835     Set(_qIn);
00836     AutoSwitch();
00837 }
00838 
00839     /*! \brief Set the MRP to the copy of an existing MRP vector
00840         * @param _MRP MRP Vector to be copied
00841         */
00842 void ModifiedRodriguezParameters::Set(const ModifiedRodriguezParameters& _MRP)
00843 {
00844     for(int ii = VectorIndexBase;ii < VectorIndexBase + MRP_SIZE; ++ii)
00845         (*this)(ii) = _MRP(ii);
00846     return;
00847 }
00848     
00849     /*! \brief Set the MRP vector based on 3 values.
00850         * @param _s1 first MRP value.
00851         * @param _s2 second MRP value.
00852         * @param _s3 third MRP value.
00853         */
00854 void ModifiedRodriguezParameters::Set(const double& _s1, const double& _s2, const double& _s3)
00855 {
00856     (*this)(VectorIndexBase+0) = _s1;
00857     (*this)(VectorIndexBase+1) = _s2;
00858     (*this)(VectorIndexBase+2) = _s3;
00859     return;
00860 }
00861 
00862     /*! \brief Set the MRP set from a vector 3 values.
00863         * @param _sVector 3x1 vector of MRP values.
00864         */
00865 void ModifiedRodriguezParameters::Set(const Vector& _sVector)
00866 {
00867     for(int ii = VectorIndexBase;ii < VectorIndexBase + MRP_SIZE; ++ii)
00868         (*this)(ii) = _sVector(ii);
00869     return;
00870 }
00871     
00872     /*! \brief Set the MRP from a converted Direction Cosine Matrix (DCM).
00873         * @param _DCM 3x3 Direction Cosine Matrix (DCM) to be converted
00874         */
00875 void ModifiedRodriguezParameters::Set(const DirectionCosineMatrix& _DCM)
00876 {
00877     Set(_DCM.GetQuaternion());
00878     return;
00879 }
00880 
00881     /*! \brief Set the MRP from the transformation of set of Euler Angles.
00882         * @param _EulerAngles 3x1 matrix of Euler Angles. [rad]
00883         * @param _Sequence Euler angle rotation sequence. (ie 123, 213, 313, 321, etc).
00884         */
00885 void ModifiedRodriguezParameters::Set(const Vector& _EulerAngles, const int& _Sequence)
00886 {
00887     /*! \todo Change implementation to calculate directly from Euler angles and not create a DCM? */
00888     Set(DirectionCosineMatrix(_EulerAngles, _Sequence));
00889     return;
00890 }
00891 
00892     /*! \brief Set the MRP from the transformation of set of Euler Angles.
00893         * @param _Angle1 first angles in Euler angle set. [rad]
00894         * @param _Angle2 second angles in Euler angle set. [rad]
00895         * @param _Angle3 third angles in Euler angle set. [rad]
00896         * @param _Sequence Euler angle rotation sequence. (ie 123, 213, 313, 321, etc).
00897         */
00898 void ModifiedRodriguezParameters::Set(const Angle& _Angle1, const Angle& _Angle2, const Angle& _Angle3, const int& _Sequence)
00899 {
00900     /*! \todo Fix Change implementation to calculate directly from Euler angles and not create a DCM? */
00901     Set(DirectionCosineMatrix(_Angle1, _Angle2, _Angle3, _Sequence));
00902     return;
00903 }
00904 
00905 
00906     /*! \brief Set the MRP from the transformation of an Euler Axis and Angle.
00907         * @param _EulerAxis 3x1 Euler Axis vector (\f$\hat{e}\f$).
00908         * @param _EulerAngle Angle rotation about axis (\f$\Phi\f$)[rad].
00909         * \par Equation: 
00910         * \f[ \bf{\sigma} = \tan{\frac{\phi}{4}}\bf{\hat{e}} \f] (Ref Schaub99)
00911         * singluar whenever \f$\phi \rightarrow \pm 360^{\circ}\f$
00912         */
00913 void ModifiedRodriguezParameters::Set(const Vector& _EulerAxis, const Angle& _EulerAngle)
00914 {
00915     (*this) = (ModifiedRodriguezParameters) (tan(0.25 * _EulerAngle) * _EulerAxis);
00916     return;
00917 }
00918 
00919     
00920     /*! \brief Set the MRPs from a converted quaternion.
00921         * @param _qIN 4x1 quaternion to be converted
00922         * \par Equation: 
00923         * \f[\sigma_i = \frac{\bf{q}_i}{1+q_4}\f] for i=1,2,3 (Ref Schaub99)
00924         *       if q4 = -1, then q = -q. (prevent singularity)
00925         */
00926 void ModifiedRodriguezParameters::Set(const Quaternion& _qIN)
00927 {
00928     double denom = (1+_qIN(VectorIndexBase+3));
00929     if(denom == 0)
00930     {
00931         denom = 2;
00932         (*this)(1) = (-_qIN(1) / denom);
00933         (*this)(2) = (-_qIN(2) / denom);
00934         (*this)(3) = (-_qIN(3) / denom);
00935     }
00936     else
00937     {
00938         (*this)(1) = (_qIN(1) / denom);
00939         (*this)(2) = (_qIN(2) / denom);
00940         (*this)(3) = (_qIN(3) / denom);
00941     }
00942     return;
00943 }
00944 
00945     /*! \brief Convert the MRP vector to a Direction Cosine Matrix (DCM).
00946         * @return 3x3 Direction Cosine Matrix.
00947         */
00948 DirectionCosineMatrix ModifiedRodriguezParameters::GetDCM() const
00949 {
00950     return DirectionCosineMatrix(*this);
00951 }
00952 
00953     /*! \brief Convert the MRP vector to a set of Euler Angles.
00954         * @param _Sequence Euler angle rotation sequence. (ie 123, 213, 313, 321, etc).
00955         * @return 3x1 vector of euler angles.
00956         */
00957 Vector ModifiedRodriguezParameters::GetEulerAngles(int _Sequence) const
00958 {
00959     /*! \todo Implement ModifiedRodriguezParameters::GetEulerAngles Function */
00960     return Vector(MRP_SIZE);
00961 }
00962 
00963     /*! \brief Convert the MRP vector to the Euler Axis and Angle set.
00964         * @param _Sequence Euler angle rotation sequence. (ie 123, 213, 313, 321, etc).
00965         * @return 3x1 vector of euler angles.
00966         */
00967 void ModifiedRodriguezParameters::GetEulerAxisAngle(Vector& _EulerAxis, Angle& _EulerAngle) const
00968 {
00969     /*! \todo Implement to directly convert and not use a temporary quaternion */
00970     Quaternion qTemp(*this);
00971     qTemp.GetEulerAxisAngle(_EulerAxis, _EulerAngle);
00972     return;
00973 }
00974     
00975     /*! \brief Convert the MRP vector to a quaternion.
00976         * @return 4x1 quaternion.
00977         */
00978 Quaternion ModifiedRodriguezParameters::GetQuaternion() const
00979 {
00980     return Quaternion(*this);
00981 }
00982     
00983     /*! \brief Switches the MRP vector to the shortest rotational distance back to the origin
00984         *       using the shadow set if the magnitude of the vector is greater than the input value S.
00985         * @param _SwitchThreshold magnitude of the MRP vector at which the set is switched. A positive scalar number.
00986         */
00987 void ModifiedRodriguezParameters::Switch(int _SwitchThreshold)
00988 {
00989     if (norm2((Vector)*this) > _SwitchThreshold)
00990         (*this) = ShadowSet();
00991     return;
00992 }
00993 
00994     /*! \brief Sets the MRP set to automatically switch between the normal set and the shadow set
00995         *       based on the shortest rotational distance to the origin.
00996         * @param _SwitchBoolean boolean value where TRUE turns on switching, and FALSE turns off switching.
00997         */
00998 void ModifiedRodriguezParameters::AutoSwitch(bool _SwitchBoolean)
00999 {
01000     m_AutoSwitch = _SwitchBoolean;
01001     return;
01002 }
01003 
01004 
01005     /*! \brief Calculates and returns the MRP shadow set.
01006         * @return MRP shadow set (3x1).
01007         * \par Equation: 
01008         * The equation for computer the MRP shadow set is:
01009         * \f[ \bf{\sigma}^{S} = - \frac{1}{|\bf{\sigma}|^2}\bf{\sigma} \f] 
01010         * (Ref Schaub99)
01011         */
01012 ModifiedRodriguezParameters ModifiedRodriguezParameters::ShadowSet() const
01013 {
01014     return (ModifiedRodriguezParameters)(-(*this)(_) / pow(norm2(*this),2));
01015 }
01016 
01017 
01018     /*! \brief Determine the successive rotation from the summation of two MRP vectors.
01019         * @param _MRP2 MRP vector to be summed with.
01020         * \par Equation: 
01021         * Summing two MRP vectors \f$\bf{\sigma'}\f$ and \f$\bf{\sigma''}\f$:
01022         * \f[
01023         * \bf{\sigma} = \frac{(1-|\bf{\sigma'}|^2)\bf{\sigma''}+(1-|\bf{\sigma''}|^2)\bf{\sigma'}-2\bf{\sigma''} \times \bf{\sigma'}}{1+|\bf{\sigma'}|^2|\bf{\sigma''}|^2-2\bf{\sigma'} \dot \bf{\sigma''}}
01024         * \f]
01025         */
01026 ModifiedRodriguezParameters ModifiedRodriguezParameters::operator+ (const ModifiedRodriguezParameters& _MRP2) const
01027 {
01028     ModifiedRodriguezParameters MRPsum;
01029     ModifiedRodriguezParameters chk;
01030     MRPsum(_) = (1-pow(norm2(*this),2)) * _MRP2
01031         + (1-pow(norm2(_MRP2),2)) * (*this)
01032               - 2*crossP(_MRP2,(*this));
01033     MRPsum(_) = MRPsum / (1 + pow(norm2(*this),2) * pow(norm2(_MRP2),2)
01034         - 2 * (const_cast<ModifiedRodriguezParameters *>(this))->dot( chk ));
01035     return MRPsum;
01036 }
01037 
01038 
01039     /*! \brief Determine the relative rotation from the difference of two MRP vectors.
01040         * @param _MRP2 MRP vector to be differenced with.
01041         * \par Equation: 
01042         * Relative MRP vector \f$\bf{\sigma''} = \bf{\sigma} - \bf{\sigma'}\f$ (Ref Schaub99):
01043         * \f[
01044         * \bf{\sigma''} = \frac{\left(1-\left|\bf{\sigma'}\right|^2\right)\bf{\sigma}-\left(1-\left|\bf{\sigma}\right|^2\right)\bf{\sigma'}+2\bf{\sigma} \times \bf{\sigma'}}{1+\left|\bf{\sigma'}\right|^2\left|\bf{\sigma}\right|^2+2\bf{\sigma'} \dot \bf{\sigma}}
01045         * \f]
01046         */
01047 ModifiedRodriguezParameters ModifiedRodriguezParameters::operator- (const ModifiedRodriguezParameters& _MRP2) const
01048 {
01049     ModifiedRodriguezParameters MRPsum;
01050     MRPsum(_) = (1-pow(norm2(_MRP2),2)) * (*this)
01051         - (1-pow(norm2(*this),2)) * _MRP2
01052         + 2*crossP((*this), _MRP2);
01053     MRPsum(_) = MRPsum / ( 1 + pow( norm2(_MRP2),2 ) * pow(norm2(*this),2) + 2 * _MRP2.dot(* ( const_cast<ModifiedRodriguezParameters *>(this) ) ) );
01054     return MRPsum;
01055 }
01056 
01057 //////////////////////////////////////////////////////////////////////////
01058 // Quaternion Class
01059     /*! \brief Create a quaternion with initial value of [0,0,0,1]^T.
01060     *  @return (double)  - (4 x 1) quaternion = [0,0,0,1]^T. 
01061     */
01062 Quaternion::Quaternion():Vector(QUATERNION_SIZE)
01063 {
01064 //    (*this).setToValue(0.0);
01065     (*this)(VectorIndexBase+3) = 1.0;   
01066 }
01067 
01068     /*! \brief Create a quaternion with initial values; will be normalized to a unit quaternion automatically.
01069     * @param _q1 first quaternion parameter
01070     * @param _q2 second quaternion parameter
01071     * @param _q3 third quaternion parameter
01072     * @param _q4 fourth quaternion parameter
01073     *  @return (double)  - (4 x 1) quaternion = [_q1,_q2,_q3,_q4]^T. 
01074     */
01075 Quaternion::Quaternion(double _q1, double _q2, double _q3, double _q4):Vector(QUATERNION_SIZE)
01076 {
01077     Set(_q1, _q2, _q3, _q4);
01078 }
01079 
01080     /*! \brief Create a quaternion with initial value of the input 4x1 matrix.
01081         * @param _qMatrix 4x1 matrix of quaternion elements.
01082         *  @return (double)  - (4 x 1) quaternion. 
01083         */
01084 /*
01085 Quaternion::Quaternion(const Matrix& _qMatrix):Vector(QUATERNION_SIZE)
01086 {
01087     Set(_qMatrix);
01088 }
01089 */
01090 
01091     /*! 
01092         * \brief Create a quaternion with initial value of the input 4x1 vector; will be normalized to a unit quaternion automatically.
01093         * @param _qMatrix 4x1 vector of quaternion elements.
01094         *  @return (double)  - (4 x 1) quaternion. 
01095         */
01096 Quaternion::Quaternion(const Vector& _qVector):Vector(QUATERNION_SIZE)
01097 {
01098     Set(_qVector);
01099 }
01100 
01101     /*! 
01102         * \brief Create a quaternion from a direction cosine matrix (DCM).
01103         * @param _DCM 3x3 Direction Cosine Matrix to be transformed.
01104         *  @return (double)  - (4 x 1) quaternion. 
01105         */
01106 Quaternion::Quaternion(const DirectionCosineMatrix& _DCM):Vector(QUATERNION_SIZE)
01107 {
01108     Set(_DCM);
01109 }
01110 
01111     /*! \brief Create a quaternion from a set of Euler Angles and Sequence.
01112         * @param _EulerAngles 3x1 matrix of Euler Angles. [rad]
01113         * @param _Sequence Euler angle rotation sequence. (ie 123, 213, 313, 321, etc).
01114         */
01115 Quaternion::Quaternion(const Vector& _EulerAngles, const int& _Sequence):Vector(QUATERNION_SIZE)
01116 {
01117     Set(_EulerAngles, _Sequence);
01118     Normalize();
01119 }
01120 
01121     /*! \brief Create a quaternion from the transformation about an Euler Axis by a set angle.
01122         * @param _EulerAxis 3x1 Euler Axis vector.
01123         * @param _EulerAngle Angle rotation about axis [rad].
01124         */
01125 Quaternion::Quaternion(const Vector& _EulerAxis, const Angle& _EulerAngle):Vector(QUATERNION_SIZE)
01126 {
01127     Set(_EulerAxis, _EulerAngle);
01128 }
01129 
01130     /*! \brief Create a Quaternion from the transformation of Modified Rodriguez Paramaters (MRP).
01131         * @param _MRP 3x1 matrix of Modified Rodriguez Parameters (MRP).
01132         */
01133 Quaternion::Quaternion(const ModifiedRodriguezParameters& _MRP):Vector(QUATERNION_SIZE)
01134 {
01135     Set(static_cast<ModifiedRodriguezParameters>(_MRP));
01136 }
01137 
01138     /*! \brief Set the quaternion to a copy of another quaternion.
01139         * @param _qIn Quaternion to be copied.
01140         */
01141 void Quaternion::Set(const Quaternion& _qIn)
01142 {
01143     (*this)(VectorIndexBase+0) = _qIn(MatrixIndexBase+0);       
01144     (*this)(VectorIndexBase+1) = _qIn(MatrixIndexBase+1);       
01145     (*this)(VectorIndexBase+2) = _qIn(MatrixIndexBase+2);       
01146     (*this)(VectorIndexBase+3) = _qIn(MatrixIndexBase+3);
01147     Normalize();
01148     return;
01149 }
01150 
01151     /*! \brief Sets the quaternion to the values specified.
01152         * @param _q1 first quaternin parameter
01153         * @param _q2 second quaternin parameter
01154         * @param _q3 third quaternin parameter
01155         * @param _q4 fourth quaternin parameter
01156         */
01157 void Quaternion::Set(double _q1, double _q2, double _q3, double _q4)
01158 {
01159     (*this)(VectorIndexBase+0) = _q1;   
01160     (*this)(VectorIndexBase+1) = _q2;   
01161     (*this)(VectorIndexBase+2) = _q3;   
01162     (*this)(VectorIndexBase+3) = _q4;   
01163     Normalize();
01164     return;
01165 }
01166 
01167     /*! \brief Sets the quaternion with the values of the input 4x1 matrix.
01168         * @param _qMatrix 4x1 matrix of quaternion elements.
01169         */
01170 /*
01171 void Quaternion::Set(const Matrix& _qMatrix)
01172 {
01173     if((_qMatrix[MatrixRowsIndex].getIndexBound() == QUATERNION_SIZE) && (_qMatrix[MatrixColsIndex].getIndexBound() == 1)) 
01174     {
01175         (*this)(VectorIndexBase+0) = _qMatrix(MatrixIndexBase+0,MatrixIndexBase);       
01176         (*this)(VectorIndexBase+1) = _qMatrix(MatrixIndexBase+1,MatrixIndexBase);       
01177         (*this)(VectorIndexBase+2) = _qMatrix(MatrixIndexBase+2,MatrixIndexBase);       
01178         (*this)(VectorIndexBase+3) = _qMatrix(MatrixIndexBase+3,MatrixIndexBase);
01179     }
01180     else
01181     {
01182         (*this) = Quaternion();
01183     }
01184     return;
01185 }*/
01186     
01187     /*! \brief Sets the quaternion with the values of the input 4x1 vector.
01188         * @param _qMatrix 4x1 vector of quaternion elements.
01189         */
01190 void Quaternion::Set(const Vector& _qVector)
01191 {
01192     (*this)(VectorIndexBase+0) = _qVector(MatrixIndexBase+0);   
01193     (*this)(VectorIndexBase+1) = _qVector(MatrixIndexBase+1);   
01194     (*this)(VectorIndexBase+2) = _qVector(MatrixIndexBase+2);   
01195     (*this)(VectorIndexBase+3) = _qVector(MatrixIndexBase+3);
01196     Normalize();
01197     return;
01198 }
01199 
01200 
01201 /*! \brief Sets the current quaternion from a converted Direction Cosine Matrix (DCM).
01202     * @param _DCM 3x3 DCM to be converted.
01203     * \par Equation:
01204     * Ref Hughes p. 18
01205     * \f[q_4 = \pm \frac{1}{2}\left(1+R_{11}+R_{22}+R_{33}\right)^{\frac{1}{2}}\f]
01206     * \f[
01207     * \bf{q} = \frac{1}{4q_4}
01208     * \begin{bmatrix}
01209     * R_{23}-R{32} \\ R_{31}-R{13} \\ R_{12}-R{21}
01210     * \end{bmatrix}\f]\f[
01211     * \bf{\bar{q}} = \begin{bmatrix} \bf{q} \\ q_4 \end{bmatrix}
01212     * \f]
01213     */
01214 /*
01215 void Quaternion::Set(const DirectionCosineMatrix& _DCM)
01216 {
01217     (*this)(VectorIndexBase+3) = 0.5 * sqrt(1 + trace(_DCM));
01218     (*this)(VectorIndexBase+0) = _DCM(MatrixIndexBase+1,MatrixIndexBase+2)
01219         - _DCM(MatrixIndexBase+2,MatrixIndexBase+1);
01220     (*this)(VectorIndexBase+1) = _DCM(MatrixIndexBase+2,MatrixIndexBase+0)
01221         - _DCM(MatrixIndexBase+0,MatrixIndexBase+2);
01222     (*this)(VectorIndexBase+2) = _DCM(MatrixIndexBase+0,MatrixIndexBase+1)
01223         - _DCM(MatrixIndexBase+1,MatrixIndexBase+0);
01224     (*this)(_(VectorIndexBase,VectorIndexBase+2)) /= (4 * (*this)(VectorIndexBase+3));
01225     Normalize();
01226     return;
01227 }
01228 */
01229 
01230 
01231 /*! 
01232     * @param _DCM 3x3 DCM to be converted
01233     * \par Equation:
01234     * Ref Schaub p. 97
01235     * \f[q_{4}^{2} = \frac{1}{4}\left(1+trace[DCM]\right)\f]
01236     * \f[q_{1}^{2} = \frac{1}{4}\left(1+2DCM_{11}-trace[DCM]\right)\f]
01237     * \f[q_{2}^{2} = \frac{1}{4}\left(1+2DCM_{22}-trace[DCM]\right)\f]
01238     * \f[q_{3}^{2} = \frac{1}{4}\left(1+2DCM_{33}-trace[DCM]\right)\f]
01239     * Take the square root of the largest \f$q_{i}^{2}\f$ and use it to find the other quaternion components.  
01240     * This \f$q_{i}\f$ is arbitrarily positive.
01241     * The other quaternion components are found using the following equations.
01242     * \f[q_4q_1 = \frac{1}{4}\left(DCM_{23} - DCM_{32}\right)\f]
01243     * \f[q_4q_2 = \frac{1}{4}\left(DCM_{31} - DCM_{13}\right)\f]
01244     * \f[q_4q_3 = \frac{1}{4}\left(DCM_{12} - DCM_{21}\right)\f]
01245     * \f[q_2q_3 = \frac{1}{4}\left(DCM_{23} + DCM_{32}\right)\f]
01246     * \f[q_3q_1 = \frac{1}{4}\left(DCM_{31} + DCM_{13}\right)\f]
01247     * \f[q_1q_2 = \frac{1}{4}\left(DCM_{12} + DCM_{21}\right)\f]
01248     */          
01249 
01250 void Quaternion::Set(const DirectionCosineMatrix& _DCM)
01251 {
01252     Vector quaternionSquared(4);
01253     double DCMtrace = trace(_DCM);
01254     double maxQuaternionSquared;
01255 
01256     quaternionSquared(4) = 0.25*(1 + DCMtrace);
01257     quaternionSquared(1) = 0.25*(1 + 2*_DCM(1,1) - DCMtrace);
01258     quaternionSquared(2) = 0.25*(1 + 2*_DCM(2,2) - DCMtrace);
01259     quaternionSquared(3) = 0.25*(1 + 2*_DCM(3,3) - DCMtrace);
01260 
01261     maxQuaternionSquared = normInf(quaternionSquared);
01262         
01263     if (maxQuaternionSquared == quaternionSquared(4))
01264     {
01265         (*this)(4) = sqrt(maxQuaternionSquared);
01266         (*this)(1) = (_DCM(2,3) - _DCM(3,2))/(4*(*this)(4));
01267         (*this)(2) = (_DCM(3,1) - _DCM(1,3))/(4*(*this)(4));
01268         (*this)(3) = (_DCM(1,2) - _DCM(2,1))/(4*(*this)(4));
01269     }
01270     else if (maxQuaternionSquared == quaternionSquared(1))
01271     {
01272         (*this)(1) = sqrt(maxQuaternionSquared);
01273         (*this)(2) = (_DCM(1,2) + _DCM(2,1))/(4*(*this)(1));
01274         (*this)(3) = (_DCM(3,1) + _DCM(1,3))/(4*(*this)(1));
01275         (*this)(4) = (_DCM(2,3) - _DCM(3,2))/(4*(*this)(1));
01276     }
01277     else if (maxQuaternionSquared == quaternionSquared(2))
01278     {
01279         (*this)(2) = sqrt(maxQuaternionSquared);
01280         (*this)(1) = (_DCM(1,2) + _DCM(2,1))/(4*(*this)(2));
01281         (*this)(3) = (_DCM(2,3) + _DCM(3,2))/(4*(*this)(2));
01282         (*this)(4) = (_DCM(3,1) - _DCM(1,3))/(4*(*this)(2));
01283     }
01284     else if (maxQuaternionSquared == quaternionSquared(3))
01285     {
01286         (*this)(3) = sqrt(maxQuaternionSquared);
01287         (*this)(1) = (_DCM(3,1) + _DCM(1,3))/(4*(*this)(3));
01288         (*this)(2) = (_DCM(2,3) + _DCM(3,2))/(4*(*this)(3));
01289         (*this)(4) = (_DCM(1,2) - _DCM(2,1))/(4*(*this)(3));
01290     }
01291 
01292     Normalize();
01293     return;
01294 }
01295 
01296     /*! \brief Set the quaternion to the transformation of set of Euler Angles.
01297         * @param _EulerAngles 3x1 matrix of Euler Angles. [rad]
01298         * @param _Sequence Euler angle rotation sequence. (ie 123, 213, 313, 321, etc).
01299         */
01300 void Quaternion::Set(const Vector& _EulerAngles, const int& _Sequence)
01301 {
01302     /*! \todo Implement Quaternion::Set(EulerAngles, Sequence) as individual calcs instead of multiple conversions */
01303     Set(DirectionCosineMatrix(_EulerAngles, _Sequence));
01304     Normalize();
01305     return;
01306 }
01307 
01308 
01309     /*! \brief Set the quaternion to the transformation about an Euler Axis by a set angle.
01310         * @param _EulerAxis 3x1 Euler Axis vector (\f$\hat{e}\f$).
01311         * @param _EulerAngle Angle rotation about axis (\f$\Phi\f$)[rad].
01312         * \par Equation: 
01313         * \f[ \bf{q}_i = \hat{e}_i \sin{\frac{\Phi}{2}} q_4 = \cos{\frac{\Phi}{2}} \f]
01314         * for i=1,2,3
01315         */
01316 void Quaternion::Set(const Vector& _EulerAxis, const Angle& _EulerAngle)
01317 {
01318     (*this)(_(VectorIndexBase+0,VectorIndexBase+2)) = _EulerAxis * sin(0.5 * _EulerAngle);              
01319     (*this)(VectorIndexBase+3) = cos(0.5 * _EulerAngle);
01320     Normalize();
01321     return;
01322 }
01323 
01324 
01325 /*! \brief Set the Quaternion to the transformation of Modified Rodriguez Paramaters (MRP).
01326     * @param _MRP 3x1 matrix of Modified Rodriguez Parameters (MRP).
01327     * \par Equation: 
01328     * \f[ \bf{q}_i = \frac{2\sigma_i}{1+\sigma^2} q_4 = \frac{1-\sigma^2}{1+\sigma^2} \f] 
01329     * for i=1,2,3 (Ref Schaub99)
01330     */
01331 void Quaternion::Set(const ModifiedRodriguezParameters& _MRP)
01332 {
01333     Matrix tempMatrix = (~_MRP) * (_MRP);
01334     double sigmaSq = tempMatrix(MatrixIndexBase,MatrixIndexBase);
01335     double denom = 1 + sigmaSq;
01336     (*this)(1) = 2 * _MRP(1) / denom;           
01337     (*this)(2) = 2 * _MRP(2) / denom;           
01338     (*this)(3) = 2 * _MRP(3) / denom;           
01339     (*this)(VectorIndexBase+3) = (1 - sigmaSq) /denom;
01340     Normalize();
01341     return;
01342 }
01343 
01344     /*! \brief Convert the quaternion to a Direction Cosine Matrix (DCM).
01345         * Uses the DirectionCosineMatrix(Quaternion) constructor.
01346         * @return 3x3 Direction Cosine Matrix.
01347         */
01348 DirectionCosineMatrix Quaternion::GetDCM() const
01349 {
01350     return DirectionCosineMatrix(*this);
01351 }
01352 
01353     /*! \brief Convert the quaternion to a set of Euler Angles.
01354         * @param _Sequence Euler angle rotation sequence. (ie 123, 213, 313, 321, etc).
01355         * @return (3 x 1) Euler Angles based on given rotation sequence (\f$\theta_i\f$)[rad] 
01356         */
01357 Vector Quaternion::GetEulerAngles(const int& _Sequence) const
01358 {
01359     Vector returnVector(EULERANGLES_SIZE);
01360     DirectionCosineMatrix Rbi;
01361  
01362     Rbi = DirectionCosineMatrix(*this);
01363     /*! \todo Implement Quaternion::GetEulerAngles function */
01364     switch(_Sequence){
01365         case 321:
01366                 returnVector(1) = atan2(Rbi(1,2),Rbi(1,1));
01367                 returnVector(2) = -asin(Rbi(1,3));
01368                 returnVector(3) = atan2(Rbi(2,3),Rbi(3,3));
01369     }
01370                 
01371     return returnVector;
01372 }
01373 
01374 
01375 /*! \brief Convert the quaternion to an Euler Axis and Angle.
01376     * @param _EulerAxis 3x1 Euler Axis vector (\f$\hat{e}\f$).
01377     * @param _EulerAngle Angle rotation about axis (\f$\Phi\f$)[rad].
01378     * @return 4-element vector [EulerAxis; EulerAngle]
01379     * \par Equation: 
01380     * \f[\Phi = 2\cos^{-1}{q_4} \hat{e}_i = \bf{q}_i\sin{\frac{\Phi}{2}}\f] 
01381     * (Ref Schaub99)
01382     */
01383 Vector Quaternion::GetEulerAxisAngle(Vector& _EulerAxis, Angle& _EulerAngle) const
01384 {
01385     Vector returnVector(EULERAXIS_SIZE + 1);
01386     _EulerAngle = 2.0 * acos((*this)(VectorIndexBase+3));
01387     _EulerAxis = (*this)(_(VectorIndexBase+0,VectorIndexBase+2)) * sin(0.5 * _EulerAngle);
01388     returnVector(_(VectorIndexBase,VectorIndexBase+EULERAXIS_SIZE-1)) = _EulerAxis;
01389     returnVector(VectorIndexBase + EULERAXIS_SIZE) = _EulerAngle;
01390     return returnVector;
01391 }
01392 
01393 
01394     /*! \brief Convert the quaternion to an Euler Axis and Angle.
01395         * @return 4-element vector [EulerAxis; EulerAngle]
01396         */
01397 Vector Quaternion::GetEulerAxisAngle() const
01398 {
01399     Vector EulerAxis(EULERAXIS_SIZE);
01400     double EulerAngle;
01401     return GetEulerAxisAngle(EulerAxis, EulerAngle);
01402 }
01403 
01404     
01405     /*! \brief Convert the quaternion to an MRP representation.
01406         * Uses the ModifiedRodriguezParameters(Quaternion) constructor.
01407         * @return (3 x 1) converted MRP. 
01408         */
01409 ModifiedRodriguezParameters Quaternion::GetMRP() const
01410 {
01411     return ModifiedRodriguezParameters(*this);
01412 }
01413 
01414 
01415     /*! \brief Normalizes a quaternion so that \f${\bf{\bar q}}^T {\bf{\bar q}}=1$\f. 
01416         */
01417 void Quaternion::Normalize()
01418 {
01419     /*! \todo Add Normalize() to Vector Class */
01420     normalize(*this);
01421     return;
01422 }
01423 
01424 /*! \brief Determine the successive rotation from the summation of two quaternions.
01425     * @param _quat2 Quaternion to be summed with.
01426     * 
01427     * \par Equation: 
01428     * successive rotations of \f$\bf{q'}\f$ and \f$\bf{q''}\f$ (Ref Schaub99)
01429     * \f[
01430     * \begin{bmatrix}
01431     * q_1 \\ q_2 \\ q_3 \\ q_4
01432     * \end{bmatrix}
01433     * =
01434     * \begin{bmatrix}
01435     * q'_1 & q'_4 & -q'_3 & q'_2\\
01436     * q'_2 & q'_3 & q'_4 & -q'_1\\
01437     * q'_3 & -q'_2 & q'_1 & q'_4\\
01438     * q'_4 & -q'_1 & -q'_2 & -q'_3
01439     * \end{bmatrix}
01440     * \begin{bmatrix}
01441     * q''_1 \\ q''_2 \\ q''_3 \\ q''_4
01442     * \end{bmatrix}
01443     * \f]
01444     */
01445 Quaternion Quaternion::operator+ (const Quaternion& _quat2) const
01446 {
01447     Matrix qSkewed(4,4);
01448     // Column 1
01449     qSkewed(_,MatrixIndexBase+0) = (*this);
01450     // Column 2
01451     qSkewed(MatrixIndexBase+0,MatrixIndexBase+1) =  (*this)(VectorIndexBase+0); 
01452     qSkewed(MatrixIndexBase+1,MatrixIndexBase+1) =  (*this)(VectorIndexBase+2);
01453     qSkewed(MatrixIndexBase+2,MatrixIndexBase+1) = -(*this)(VectorIndexBase+1);
01454     qSkewed(MatrixIndexBase+3,MatrixIndexBase+1) = -(*this)(VectorIndexBase+3);
01455     // Column 3
01456     qSkewed(MatrixIndexBase+0,MatrixIndexBase+2) = -(*this)(VectorIndexBase+1); 
01457     qSkewed(MatrixIndexBase+1,MatrixIndexBase+2) =  (*this)(VectorIndexBase+2);
01458     qSkewed(MatrixIndexBase+2,MatrixIndexBase+2) =  (*this)(VectorIndexBase+3);
01459     qSkewed(MatrixIndexBase+3,MatrixIndexBase+2) = -(*this)(VectorIndexBase+0);
01460     // Column 4
01461     qSkewed(MatrixIndexBase+0,MatrixIndexBase+3) =  (*this)(VectorIndexBase+1); 
01462     qSkewed(MatrixIndexBase+1,MatrixIndexBase+3) = -(*this)(VectorIndexBase+0);
01463     qSkewed(MatrixIndexBase+2,MatrixIndexBase+3) =  (*this)(VectorIndexBase+3);
01464     qSkewed(MatrixIndexBase+3,MatrixIndexBase+3) = -(*this)(VectorIndexBase+2);
01465 
01466     return Quaternion(qSkewed * _quat2);
01467 }
01468 
01469 /*! \brief Determine the relative rotation from the difference of two quaternions.
01470     * @param _quat2 Quaternion to be differenced with.
01471     * 
01472     * \par Equation: 
01473     * subtracting \f$\bf{q'}\f$ from \f$\bf{q''}\f$ (Ref Schaub99)
01474     * \f[
01475     * \begin{bmatrix}
01476     * q_1 \\ q_2 \\ q_3 \\ q_4
01477     * \end{bmatrix}
01478     * =
01479     * \begin{bmatrix}
01480     * -q'_4 & q'_4 & q'_3 & -q'_2\\
01481     * -q'_2 & -q'_3 & q'_4 & q'_1\\
01482     * -q'_3 & -q'_2 & -q'_1 & q'_4\\    
01483     * q'_4 & q'_1 & q'_2 & q'_3
01484     * \end{bmatrix}
01485     * \begin{bmatrix}
01486     * q''_1 \\ q''_2 \\ q''_3 \\ q''_4
01487     * \end{bmatrix}
01488     * \f]
01489     */
01490 Quaternion Quaternion::operator- (const Quaternion& _quat2) const
01491 {
01492     Matrix qSkewed(4,4);
01493     // Column 1
01494     qSkewed(MatrixIndexBase+0,MatrixIndexBase+0) = -_quat2(VectorIndexBase+0);
01495     qSkewed(MatrixIndexBase+1,MatrixIndexBase+0) = -_quat2(VectorIndexBase+1);
01496     qSkewed(MatrixIndexBase+2,MatrixIndexBase+0) = -_quat2(VectorIndexBase+2);
01497     qSkewed(MatrixIndexBase+3,MatrixIndexBase+0) =  _quat2(VectorIndexBase+3);
01498     // Column 2
01499     qSkewed(MatrixIndexBase+0,MatrixIndexBase+1) =  _quat2(VectorIndexBase+3);  
01500     qSkewed(MatrixIndexBase+1,MatrixIndexBase+1) = -_quat2(VectorIndexBase+2);
01501     qSkewed(MatrixIndexBase+2,MatrixIndexBase+1) =  _quat2(VectorIndexBase+1);
01502     qSkewed(MatrixIndexBase+3,MatrixIndexBase+1) =  _quat2(VectorIndexBase+0);
01503     // Column 3
01504     qSkewed(MatrixIndexBase+0,MatrixIndexBase+2) =  _quat2(VectorIndexBase+2);  
01505     qSkewed(MatrixIndexBase+1,MatrixIndexBase+2) =  _quat2(VectorIndexBase+3);
01506     qSkewed(MatrixIndexBase+2,MatrixIndexBase+2) = -_quat2(VectorIndexBase+0);
01507     qSkewed(MatrixIndexBase+3,MatrixIndexBase+2) =  _quat2(VectorIndexBase+1);
01508     // Column 4
01509     qSkewed(MatrixIndexBase+0,MatrixIndexBase+3) = -_quat2(VectorIndexBase+1);  
01510     qSkewed(MatrixIndexBase+1,MatrixIndexBase+3) =  _quat2(VectorIndexBase+0);
01511     qSkewed(MatrixIndexBase+2,MatrixIndexBase+3) =  _quat2(VectorIndexBase+3);
01512     qSkewed(MatrixIndexBase+3,MatrixIndexBase+3) =  _quat2(VectorIndexBase+2);
01513 
01514     return Quaternion((qSkewed) * (*this));
01515 }
01516 } // end of namespace O_SESSAME
01517 /*!***************************************************************************
01518 *       $Log: Rotation.cpp,v $
01519 *       Revision 1.7  2007/06/01 20:52:16  jayhawk_hokie
01520 *       Modified MRP subtraction.
01521 *       
01522 *       Revision 1.6  2007/05/21 17:32:55  jayhawk_hokie
01523 *       *** empty log message ***
01524 *       
01525 *       Revision 1.5  2007/04/23 21:03:48  bwilliam
01526 *       Added conversion to 321 Euler Angles for quaternion
01527 *       
01528 *       Revision 1.4  2006/07/25 20:45:35  spikeinferno
01529 *       Modified comments to DirectionCosineMatrix::GetEulerAngles
01530 *       
01531 *       Revision 1.2  2006/07/24 22:01:46  spikeinferno
01532 *       Added 321 Euler angle sequence to DirectionCosineMatrix::GetEulerAngles and modified Quaternion::Set with Stanley's Method for transforming a DCM to a quaternion
01533 *       
01534 *       Revision 1.1.1.1  2005/04/26 17:41:00  cakinli
01535 *       Adding OpenSESSAME to DSACSS distrib to capture fixed version.
01536 *       
01537 *       Revision 1.24  2003/10/18 21:37:28  rsharo
01538 *       Removed "../utils" from all qmake project paths. Prepended "utils
01539 *       /" to all #include directives for utils. Removed ".h" extensions from STL header
01540 *       s and referenced STL components from "std::" namespace.  Overall, changed to be
01541 *       more portable.
01542 *       
01543 *       Revision 1.23  2003/06/10 14:23:42  nilspace
01544 *       Changed MRP::Set(Quaternion) to not overwrite the const.
01545 *       
01546 *       Revision 1.22  2003/06/10 02:25:32  nilspace
01547 *       Fixed MRP::Set(Quaternion) since there apparently is no Vector::operator-() that returns the negative of a Vector.
01548 *       
01549 *       Revision 1.21  2003/05/27 20:01:38  nilspace
01550 *       Fixed numerous bugs with MRP conversion functions.
01551 *       
01552 *       Revision 1.20  2003/05/27 14:39:12  nilspace
01553 *       Fixed the MRP->Quaternion conversion.
01554 *       
01555 *       Revision 1.19  2003/05/22 03:03:38  nilspace
01556 *       Update documentation, and changed all angles to use Angle type.
01557 *       
01558 *       Revision 1.18  2003/05/21 22:18:05  nilspace
01559 *       Moved the documentation to the implementation file.
01560 *       
01561 *       Revision 1.17  2003/05/20 17:53:51  nilspace
01562 *       Updated comments.
01563 *       
01564 *       Revision 1.16  2003/05/13 19:45:10  nilspace
01565 *       Updated comments.
01566 *       
01567 *       Revision 1.15  2003/05/02 19:44:24  nilspace
01568 *       Modified the DCM::Set(Quaternion) function for a more efficient calculation on the diagonals.
01569 *       
01570 *       Revision 1.14  2003/04/28 14:16:26  nilspace
01571 *       Moved all function definitions out of header file into implementation file.
01572 *       
01573 *       Revision 1.13  2003/04/27 20:41:09  nilspace
01574 *       Encapsulated the rotation library into the namespace O_SESSAME.
01575 *       
01576 *       Revision 1.12  2003/04/22 21:59:58  nilspace
01577 *       Fixed Quaternion::Set(DCM) so it evaluates correctly.
01578 *       Implemented Rotation::operator-()
01579 *       
01580 *       Revision 1.11  2003/04/22 20:52:39  nilspace
01581 *       Added Normalize() call to all of the DCM::Set functions.
01582 *       
01583 *       Revision 1.10  2003/04/22 19:45:16  nilspace
01584 *       Fixed DCM::Set to correctly calculate the MRP tempMatrix (sigma^2)
01585 *       
01586 *       Revision 1.9  2003/04/22 19:36:02  nilspace
01587 *       Various bug fixes to DCM & quaternion conversions. Added DirectionCosineMatrix Normalize().
01588 *       
01589 *       Revision 1.8  2003/04/22 16:03:11  nilspace
01590 *       Updated MRP::Set(Quaternion) to correctly set.
01591 *       
01592 *       Revision 1.7  2003/04/10 17:25:51  nilspace
01593 *       changelog
01594 *       
01595 *       Revision 1.6  2003/04/08 23:02:27  nilspace
01596 *       Added Rotation Sense, or "Handedness". Defaults to RIGHT_HAND
01597 *       
01598 *       Revision 1.5  2003/03/27 20:22:26  nilspace
01599 *       Added GetRotation() function.
01600 *       Fixed Quaternion.Set(Quaternion) function.
01601 *       Added RotationType enum.
01602 *       Made sure to normalize the Quaternions for all the Set() functions.
01603 *       
01604 *       Revision 1.4  2003/03/25 02:37:36  nilspace
01605 *       Added quaternion matrix set and constructor.
01606 *       Added Rotation generalized matrix set to check for quaternion.
01607 *       
01608 *       Revision 1.3  2003/03/04 17:36:19  nilspace
01609 *       Added CVS tags for documenting uploads. Also chmod'd to not be executable.
01610 *       
01611 *       Revision 1.1  2003/02/27 18:37:26  nilspace
01612 *       Initial submission of Rotation class implementation.
01613 *       
01614 *
01615 ******************************************************************************/
01616 

Generated on Wed Sep 5 12:54:24 2007 for DSACSS Operational Code by  doxygen 1.3.9.1