/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* ex: set filetype=cpp softtabstop=4 shiftwidth=4 tabstop=4 cindent expandtab: */ /* $Id: vctMatrixRotation3Base.h,v 1.25 2007/04/26 19:33:58 anton Exp $ Author(s): Anton Deguet Created on: 2005-08-19 (C) Copyright 2005-2007 Johns Hopkins University (JHU), All Rights Reserved. --- begin cisst license - do not edit --- This software is provided "as is" under an open source license, with no warranty. The complete license can be found in license.txt and http://www.cisst.org/cisst/license.txt. --- end cisst license --- */ /*! \file \brief Declaration of vctMatrixRotation3Base */ #ifndef _vctMatrixRotation3Base_h #define _vctMatrixRotation3Base_h #include #include #include #include #include #include #ifndef DOXYGEN #ifndef SWIG // helper functions for subtemplated methods of a templated class template void vctMatrixRotation3BaseFromRaw(vctMatrixRotation3Base<_matrixType> & matrixRotation, const vctQuaternionRotation3Base<_quaternionType> & quaternionRotation); #ifdef CISST_COMPILER_IS_MSVC template CISST_EXPORT void vctMatrixRotation3BaseFromRaw(vctMatrixRotation3Base > & matrixRotation, const vctQuaternionRotation3Base > & quaternionRotation); template CISST_EXPORT void vctMatrixRotation3BaseFromRaw(vctMatrixRotation3Base > & matrixRotation, const vctQuaternionRotation3Base > & quaternionRotation); template CISST_EXPORT void vctMatrixRotation3BaseFromRaw(vctMatrixRotation3Base > & matrixRotation, const vctQuaternionRotation3Base > & quaternionRotation); template CISST_EXPORT void vctMatrixRotation3BaseFromRaw(vctMatrixRotation3Base > & matrixRotation, const vctQuaternionRotation3Base > & quaternionRotation); template CISST_EXPORT void vctMatrixRotation3BaseFromRaw(vctMatrixRotation3Base > & matrixRotation, const vctQuaternionRotation3Base > & quaternionRotation); template CISST_EXPORT void vctMatrixRotation3BaseFromRaw(vctMatrixRotation3Base > & matrixRotation, const vctQuaternionRotation3Base > & quaternionRotation); #endif #endif // SWIG #endif // DOXYGEN /*! \brief Define a rotation matrix for a space of dimension 3 This class is templated by the type of container used to store the rotation matrix. This class is an internal class, i.e. it is not intended for the end-user. The class which should be used by most is vctMatRot3 (eventually vctMatrixRotation3<_elementType>). The main goal of this meta rotation matrix class is to ease the interface with Python. For a native Python object, a matrix rotation can be defined based on a vctDynamicMatrix which is much easier to wrap than a vctFixedSizeMatrix. For a C++ object accessed from Python, the rotation matrix will be defined using vctMatrixRotation3Base >, referring to the C++ vctMatrixRotation3Base >. \param _containerType The type of the matrix. \sa vctFixedSizeMatrix */ template class vctMatrixRotation3Base: public _containerType { public: enum {ROWS = 3, COLS = 3}; enum {DIMENSION = 3}; typedef _containerType BaseType; typedef _containerType ContainerType; typedef vctMatrixRotation3Base ThisType; /* no need to document, inherit doxygen documentation from base class */ VCT_CONTAINER_TRAITS_TYPEDEFS(typename ContainerType::value_type); /*! Traits used for all useful types and values related to the element type. */ typedef cmnTypeTraits TypeTraits; protected: /*! Throw an exception unless this rotation is normalized. */ inline void ThrowUnlessIsNormalized(void) const throw(std::runtime_error) { if (! IsNormalized()) { cmnThrow(std::runtime_error("vctMatrixRotation3Base: This rotation is not normalized")); } } /*! Throw an exception unless the input is normalized. \param input An object with \c IsNormalized method. */ template inline void ThrowUnlessIsNormalized(const _inputType & input) const throw(std::runtime_error) { if (! input.IsNormalized()) { cmnThrow(std::runtime_error("vctMatrixRotation3Base: Input is not normalized")); } } /*! Allocate memory for the underlying container if needed. By default, this methods does nothing. For any container requiring a memory allocation, it is necessary to specialize this method. */ inline void Allocate(void) {} public: vctMatrixRotation3Base() { this->Allocate(); this->Assign(Identity()); } /*! Constructor from 9 elements. This constructor verifies that the matrix created is actually a valid rotation matrix. If the input is not normalized, an exception will be thrown (std::runtime_error). The parameters are given row first so that the code remains human readable: \code vctMatrixRotation3 matrix( 0.0, 1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0); \endcode */ inline vctMatrixRotation3Base(const ThisType & other) { this->Allocate(); this->Assign(other); } inline vctMatrixRotation3Base(const BaseType & other) { this->Allocate(); this->Assign(other); } /*! The assignment from BaseType (i.e. a 3 by 3 fixed size matrix) has to be redefined for this class (C++ restriction). This operator uses the Assign() method inherited from the BaseType. This operator (as well as the Assign method) allows to set a rotation matrix to whatever value without any further validity checking. It is recommended to use it with caution. */ inline ThisType & operator = (const BaseType & other) { return reinterpret_cast(this->Assign(other)); } inline ThisType & operator = (const ThisType & other) { return reinterpret_cast(this->Assign(other)); } /*! \name Constructors with normalization test. These constructors will check that the input is valid, i.e. normalized. If the input is not normalized, an exception (of type \c std::runtime_error) will be thrown. Each constructor uses the corresponding From() method based on the input type. \note See the cmnThrow() function if an \c abort is better than an exception for your application. */ //@{ /*! Constructor from 9 elements. The parameters are given row first so that the code remains human readable: \code vctMatrixRotation3 matrix( 0.0, 1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0); \endcode */ #ifndef SWIG // SWIG generetes a long help string for this message and the Microsoft compilers can't handle it inline vctMatrixRotation3Base(const value_type & element00, const value_type & element01, const value_type & element02, const value_type & element10, const value_type & element11, const value_type & element12, const value_type & element20, const value_type & element21, const value_type & element22) throw(std::runtime_error) { this->Allocate(); this->From(element00, element01, element02, element10, element11, element12, element20, element21, element22); } #endif /*! Constructor from 3 fixed size vectors. By default the vectors represents the columns of the matrix. If the parameter vectorsAreColumns is set to false, the vectors provided will be used to set the matrix row by row. */ template inline vctMatrixRotation3Base(const vctFixedSizeConstVectorBase& v1, const vctFixedSizeConstVectorBase& v2, const vctFixedSizeConstVectorBase& v3, bool vectorsAreColumns = true) throw(std::runtime_error) { this->Allocate(); this->From(v1, v2, v3, vectorsAreColumns); } /*! Constructor from 3 dynamic vectors. By default the vectors represents the columns of the matrix. If the parameter vectorsAreColumns is set to false, the vectors provided will be used to set the matrix row by row. */ template inline vctMatrixRotation3Base(const vctDynamicConstVectorBase<__vectorOwnerType1, value_type>& v1, const vctDynamicConstVectorBase<__vectorOwnerType2, value_type>& v2, const vctDynamicConstVectorBase<__vectorOwnerType3, value_type>& v3, bool vectorsAreColumns = true) throw(std::runtime_error) { this->Allocate(); this->From(v1, v2, v3, vectorsAreColumns); } /*! Construction from a vctAxisAngleRotation3. */ inline vctMatrixRotation3Base(const vctAxisAngleRotation3 & axisAngleRotation) throw(std::runtime_error) { this->Allocate(); this->From(axisAngleRotation); } /*! Constructor from a rotation quaternion. It is important to note that this constructor doesn't normalize the rotation quaternion but asserts that it is normalized (in debug mode only). See also the method From(quaternion). \param quaternionRotation A unit quaternion */ template inline vctMatrixRotation3Base(const vctQuaternionRotation3Base<__containerType> & quaternionRotation) throw(std::runtime_error) { this->Allocate(); this->From(quaternionRotation); } /*! Constructor from a vctRodriguezRotation3. */ template inline vctMatrixRotation3Base(const vctRodriguezRotation3Base<__containerType> & rodriguezRotation) throw(std::runtime_error) { this->Allocate(); this->From(rodriguezRotation); } //@} /*! \name Constructors without normalization test These constructors will either assume that the input is normalized or normalize the input (a copy of it, if required) based on the last parameter provided.
  • If the normalization flag is set to #VCT_DO_NOT_NORMALIZE, the input is considered already normalized and the constructor will not perform any sanity check. This can lead to numerical instabilities which have to be handled by the caller.
  • If the normalization flag is set to #VCT_NORMALIZE, the input will be normalized. This option should be used whenever it is important to obtain a result as "normalized" as possible.
*/ //@{ /*! Constructor from 9 elements. The parameters are given row first so that the code remains human readable: \code vctMatrixRotation3 matrix( 0.0, 1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0); \endcode */ inline vctMatrixRotation3Base(const value_type & element00, const value_type & element01, const value_type & element02, const value_type & element10, const value_type & element11, const value_type & element12, const value_type & element20, const value_type & element21, const value_type & element22, bool normalizeInput) { this->Allocate(); if (normalizeInput) { this->FromNormalized(element00, element01, element02, element10, element11, element12, element20, element21, element22); } else { this->FromRaw(element00, element01, element02, element10, element11, element12, element20, element21, element22); } } /*! Constructor from 3 fixed size vectors. By default the vectors represents the columns of the matrix. If the parameter vectorsAreColumns is set to false, the vectors provided will be used to set the matrix row by row. */ template inline vctMatrixRotation3Base(const vctFixedSizeConstVectorBase& v1, const vctFixedSizeConstVectorBase& v2, const vctFixedSizeConstVectorBase& v3, bool vectorsAreColumns, bool normalizeInput) { this->Allocate(); if (normalizeInput) { this->FromNormalized(v1, v2, v3, vectorsAreColumns); } else { this->FromRaw(v1, v2, v3, vectorsAreColumns); } } /*! Constructor from 3 dynamic vectors. By default the vectors represents the columns of the matrix. If the parameter vectorsAreColumns is set to false, the vectors provided will be used to set the matrix row by row. */ template inline vctMatrixRotation3Base(const vctDynamicConstVectorBase<__vectorOwnerType1, value_type>& v1, const vctDynamicConstVectorBase<__vectorOwnerType2, value_type>& v2, const vctDynamicConstVectorBase<__vectorOwnerType3, value_type>& v3, bool vectorsAreColumns, bool normalizeInput) { this->Allocate(); if (normalizeInput) { this->FromNormalized(v1, v2, v3, vectorsAreColumns); } else { this->FromRaw(v1, v2, v3, vectorsAreColumns); } } /*! Construction from a vctAxisAngleRotation3. */ inline vctMatrixRotation3Base(const vctAxisAngleRotation3 & axisAngleRotation, bool normalizeInput) { this->Allocate(); if (normalizeInput) { this->FromNormalized(axisAngleRotation); } else { this->FromRaw(axisAngleRotation); } } /*! Constructor from a rotation quaternion. It is important to note that this constructor doesn't normalize the rotation quaternion but asserts that it is normalized (in debug mode only). See also the method From(quaternion). \param quaternionRotation A unit quaternion \param normalizeInput Normalize the input or convert as is (#VCT_NORMALIZE or #VCT_DO_NOT_NORMALIZE) */ template inline vctMatrixRotation3Base(const vctQuaternionRotation3Base<__containerType> & quaternionRotation, bool normalizeInput) { this->Allocate(); if (normalizeInput) { this->FromNormalized(quaternionRotation); } else { this->FromRaw(quaternionRotation); } } /*! Constructor from a vctRodriguezRotation3. */ template inline vctMatrixRotation3Base(const vctRodriguezRotation3Base<__containerType> & rodriguezRotation, bool normalizeInput) { this->Allocate(); if (normalizeInput) { this->FromNormalized(rodriguezRotation); } else { this->FromRaw(rodriguezRotation); } } //@} /*! Initialize this rotation matrix with a 3x3 matrix. This constructor only takes a matrix of the same element type. \note This constructor does not verify normalization. It is introduced to allow using results of matrix operations and assign them to a rotation matrix. \note The constructor is declared explicit, to force the user to be aware of the conversion being made. */ template explicit inline vctMatrixRotation3Base(const vctFixedSizeMatrixBase & matrix) { this->Allocate(); this->Assign(matrix); } /*! Const reference to the identity. In this case, the identity matrix:
      1 0 0
      0 1 0
      0 0 1
      
*/ static CISST_EXPORT const ThisType & Identity(); /*! \name Conversion from normalized input. These methods will check that the input is normalized. If the input is not normalized, an exception (\c std::runtime_error) will be thrown using cmnThrow(). \note Since all exceptions are thrown using cmnThrow(), it is possible to configure these methods to use \c abort() if the normalization requirements are not met (see cmnThrow()). */ //@{ /*! Conversion from 9 elements. */ inline ThisType & From(const value_type & element00, const value_type & element01, const value_type & element02, const value_type & element10, const value_type & element11, const value_type & element12, const value_type & element20, const value_type & element21, const value_type & element22) throw(std::runtime_error) { this->FromRaw(element00, element01, element02, element10, element11, element12, element20, element21, element22); this->ThrowUnlessIsNormalized(); return *this; } /*! Conversion from 3 fixed size vectors. By default the vectors represents the columns of the matrix. If the parameter vectorsAreColumns is set to false, the vectors provided will be used to set the matrix row by row. */ template inline ThisType & From(const vctFixedSizeConstVectorBase& v1, const vctFixedSizeConstVectorBase& v2, const vctFixedSizeConstVectorBase& v3, bool vectorsAreColumns = true) throw(std::runtime_error) { this->FromRaw(v1, v2, v3, vectorsAreColumns); this->ThrowUnlessIsNormalized(); return *this; } /*! Conversion from 3 dynamic vectors. By default the vectors represents the columns of the matrix. If the parameter vectorsAreColumns is set to false, the vectors provided will be used to set the matrix row by row. */ template inline ThisType & From(const vctDynamicConstVectorBase<__vectorOwnerType1, value_type>& v1, const vctDynamicConstVectorBase<__vectorOwnerType2, value_type>& v2, const vctDynamicConstVectorBase<__vectorOwnerType3, value_type>& v3, bool vectorsAreColumns = true) throw (std::runtime_error) { this->FromRaw(v1, v2, v3, vectorsAreColumns); this->ThrowUnlessIsNormalized(); return *this; } /*! Conversion from an axis/angle rotation. */ inline ThisType & From(const vctAxisAngleRotation3 & axisAngleRotation) throw(std::runtime_error) { this->ThrowUnlessIsNormalized(axisAngleRotation); return this->FromRaw(axisAngleRotation); } /*! Conversion from a rotation quaternion. */ template inline ThisType & From(const vctQuaternionRotation3Base<__containerType> & quaternionRotation) throw(std::runtime_error) { this->ThrowUnlessIsNormalized(quaternionRotation); return this->FromRaw(quaternionRotation); } /*! Conversion from a Rodriguez rotation. */ template inline ThisType & From(const vctRodriguezRotation3Base<__containerType> & rodriguezRotation) throw(std::runtime_error) { this->ThrowUnlessIsNormalized(rodriguezRotation); return this->FromRaw(rodriguezRotation); } //@} /*! \name Conversion and normalization. These method will accept any input and attempt to either normalize the input and then convert or convert and then normalize the quaternion itself.
The order depends on the type of input. */ //@{ /*! Conversion from 9 elements. */ inline ThisType & FromNormalized(const value_type & element00, const value_type & element01, const value_type & element02, const value_type & element10, const value_type & element11, const value_type & element12, const value_type & element20, const value_type & element21, const value_type & element22) { this->FromRaw(element00, element01, element02, element10, element11, element12, element20, element21, element22); this->NormalizedSelf(); return *this; } /*! Conversion from 3 fixed size vectors. By default the vectors represents the columns of the matrix. If the parameter vectorsAreColumns is set to false, the vectors provided will be used to set the matrix row by row. */ template inline ThisType & FromNormalized(const vctFixedSizeConstVectorBase& v1, const vctFixedSizeConstVectorBase& v2, const vctFixedSizeConstVectorBase& v3, bool vectorsAreColumns = true) throw(std::runtime_error) { this->FromRaw(v1, v2, v3, vectorsAreColumns); this->NormalizedSelf(); return *this; } /*! Conversion from 3 dynamic vectors. By default the vectors represents the columns of the matrix. If the parameter vectorsAreColumns is set to false, the vectors provided will be used to set the matrix row by row. */ template inline ThisType & FromNormalized(const vctDynamicConstVectorBase<__vectorOwnerType1, value_type>& v1, const vctDynamicConstVectorBase<__vectorOwnerType2, value_type>& v2, const vctDynamicConstVectorBase<__vectorOwnerType3, value_type>& v3, bool vectorsAreColumns = true) { this->FromRaw(v1, v2, v3, vectorsAreColumns); this->NormalizedSelf(); return *this; } /*! Conversion from an axis/angle rotation. */ inline ThisType & FromNormalized(const vctAxisAngleRotation3 & axisAngleRotation) { return this->FromRaw(axisAngleRotation.Normalized()); } /*! Conversion from a rotation quaternion. \param quaternionRotation A rotation quaternion */ template inline ThisType & FromNormalized(const vctQuaternionRotation3Base<__containerType> & quaternionRotation) { return this->FromRaw(quaternionRotation.Normalized()); } /*! Conversion from a Rodriguez rotation. */ template inline ThisType & FromNormalized(const vctRodriguezRotation3Base<__containerType> & rodriguezRotation) { return this->FromRaw(rodriguezRotation.Normalized()); } //@} /*! \name Conversion. These method don't check if the input is normalized nor try to normalize the results. They should be used with caution since the resulting rotation (in this case a quaternion) might not be normalized. */ //@{ /*! Conversion from 9 elements. */ inline ThisType & FromRaw(const value_type & element00, const value_type & element01, const value_type & element02, const value_type & element10, const value_type & element11, const value_type & element12, const value_type & element20, const value_type & element21, const value_type & element22) { this->Assign(element00, element01, element02, element10, element11, element12, element20, element21, element22); return *this; } /*! Conversion from 3 fixed size vectors. By default the vectors represents the columns of the matrix. If the parameter vectorsAreColumns is set to false, the vectors provided will be used to set the matrix row by row. */ template inline ThisType & FromRaw(const vctFixedSizeConstVectorBase& v1, const vctFixedSizeConstVectorBase& v2, const vctFixedSizeConstVectorBase& v3, bool vectorsAreColumns = true) { if (vectorsAreColumns) { this->Column(0).Assign(v1); this->Column(1).Assign(v2); this->Column(2).Assign(v3); } else { this->Row(0).Assign(v1); this->Row(1).Assign(v2); this->Row(2).Assign(v3); } return *this; } /*! Conversion from 3 dynamic vectors. By default the vectors represents the columns of the matrix. If the parameter vectorsAreColumns is set to false, the vectors provided will be used to set the matrix row by row. */ template inline ThisType & FromRaw(const vctDynamicConstVectorBase<__vectorOwnerType1, value_type>& v1, const vctDynamicConstVectorBase<__vectorOwnerType2, value_type>& v2, const vctDynamicConstVectorBase<__vectorOwnerType3, value_type>& v3, bool vectorsAreColumns = true) throw (std::runtime_error) { CMN_ASSERT(v1.size() == DIMENSION); CMN_ASSERT(v2.size() == DIMENSION); CMN_ASSERT(v3.size() == DIMENSION); if (vectorsAreColumns) { this->Column(0).Assign(v1); this->Column(1).Assign(v2); this->Column(2).Assign(v3); } else { this->Row(0).Assign(v1); this->Row(1).Assign(v2); this->Row(2).Assign(v3); } return *this; } /*! Conversion from an axis/angle rotation */ CISST_EXPORT ThisType & FromRaw(const vctAxisAngleRotation3 & axisAngleRotation); /*! Conversion from a quaternion rotation. */ template inline ThisType & FromRaw(const vctQuaternionRotation3Base<__containerType> & quaternionRotation) { vctMatrixRotation3BaseFromRaw(*this, quaternionRotation); return *this; } /*! Conversion from a Rodriguez rotation. */ template inline ThisType & FromRaw(const vctRodriguezRotation3Base<__containerType> & rodriguezRotation) { return this->FromRaw(vctAxisAngleRotation3(rodriguezRotation, VCT_DO_NOT_NORMALIZE)); } /*! A complementary form of assigning one matrix rotation to another. The method is provided mostly for generic programming interfaces and for testing various operations on rotations */ inline ThisType & FromRaw(const ThisType & otherRotation) { return reinterpret_cast(this->Assign(otherRotation)); } /*! Assign a 3x3 matrix to this rotation matrix. This method does not substitute the Assign() method. Assign() may perform type conversion, while From() only takes a matrix of the same element type. \note This method does not verify normalization. It is introduced to allow using results of matrix operations and assign them to a rotation matrix. */ template inline ThisType & FromRaw(const vctFixedSizeMatrixBase & matrix) { this->Assign(matrix); return *this; } //@} /*! Normalizes this matrix. This method converts the matrix to a quaternion, normalizes it and convert back to a matrix. */ CISST_EXPORT ThisType & NormalizedSelf(void); /*! Sets this rotation matrix as the normalized version of another one. \param otherMatrix Matrix used to compute the normalized matrix. */ inline ThisType & NormalizedOf(ThisType & otherMatrix) { CMN_ASSERT(otherMatrix.Pointer() != this->Pointer()); *this = otherMatrix; this->NormalizedSelf(); return *this; } /*! Returns the normalized version of this rotation. This method returns a copy of the normalized rotation and does not modify this rotation. See also NormalizedSelf(). */ inline ThisType Normalized(void) const { ThisType result(*this); result.NormalizedSelf(); return result; } /*! Test if this matrix is normalized. This methods checks that all the columns are normalized (within a margin of tolerance) and then checks that the three vectors are orthogonal to each other. \param tolerance Tolerance for the norm and scalar product tests. */ inline bool IsNormalized(value_type tolerance = TypeTraits::Tolerance()) const { NormType columnNorm; columnNorm = this->Column(0).Norm(); if (vctUnaryOperations::AbsValue::Operate(columnNorm - 1) > tolerance) return false; columnNorm = this->Column(1).Norm(); if (vctUnaryOperations::AbsValue::Operate(columnNorm - 1) > tolerance) return false; columnNorm = this->Column(2).Norm(); if (vctUnaryOperations::AbsValue::Operate(columnNorm - 1) > tolerance) return false; value_type columnDot; columnDot = vctDotProduct(this->Column(0), this->Column(1)); if (vctUnaryOperations::AbsValue::Operate(columnDot) > tolerance) return false; columnDot = vctDotProduct(this->Column(0), this->Column(2)); if (vctUnaryOperations::AbsValue::Operate(columnDot) > tolerance) return false; columnDot = vctDotProduct(this->Column(1), this->Column(2)); if (vctUnaryOperations::AbsValue::Operate(columnDot) > tolerance) return false; return true; } /*! Inverse this rotation matrix. This methods assumes that the matrix is normalized and sets this matrix as its transposed. */ inline ThisType & InverseSelf(void) { // could use the transpose operator but this seems more efficient value_type tmp; tmp = this->Element(0, 1); this->Element(0, 1) = this->Element(1, 0); this->Element(1, 0) = tmp; tmp = this->Element(0, 2); this->Element(0, 2) = this->Element(2, 0); this->Element(2, 0) = tmp; tmp = this->Element(1, 2); this->Element(1, 2) = this->Element(2, 1); this->Element(2, 1) = tmp; return *this; } /*! Set this rotation as the inverse of another one. See also InverseSelf(). */ inline ThisType & InverseOf(const ThisType & otherRotation) { CMN_ASSERT(otherRotation.Pointer() != this->Pointer()); this->TransposeOf(otherRotation); return *this; } /*! Create and return by copy the inverse of this matrix. This method is not the most efficient since it requires a copy. See also InverseSelf(). */ inline ThisType Inverse(void) const { ThisType result; result.InverseOf(*this); return result; } /*! Apply the rotation to a vector of fixed size 3. The result is stored into a vector of size 3 provided by the caller and passed by reference. \param input The input vector \param output The output vector */ template inline void ApplyTo(const vctFixedSizeConstVectorBase & input, vctFixedSizeVectorBase & output) const { CMN_ASSERT(input.Pointer() != output.Pointer()); output.ProductOf(*this, input); } /*! Apply the rotation to a vector of fixed size 3. The result is returned by copy. This interface might be more convenient for some but one should note that it is less efficient since it requires a copy. \param input The input vector \return The output vector */ template inline vctFixedSizeVector ApplyTo(const vctFixedSizeConstVectorBase & input) const { vctFixedSizeVector result; this->ApplyTo(input, result); return result; } /*! Apply the rotation to another rotation. The result is returned by copy. This interface might be more convenient for some but one should note that it is less efficient since it requires a copy. \param input The input rotation \return The output rotation */ inline ThisType ApplyTo(const ThisType & input) const { CMN_ASSERT(input.Pointer() != this->Pointer()); ThisType result; this->ApplyTo(input, result); return result; } /*! Apply the rotation to a dynamic vector. The result is stored into another dynamic vector passed by reference by the caller. It is assumed that both are of size 3. */ template inline void ApplyTo(const vctDynamicConstVectorBase<__vectorOwnerType1, value_type> & input, vctDynamicVectorBase<__vectorOwnerType2, value_type> & output) const throw(std::runtime_error) { CMN_ASSERT(input.Pointer() != output.Pointer()); CMN_ASSERT(input.size() == DIMENSION); CMN_ASSERT(output.size() == DIMENSION); output[0] = this->Element(0, 0) * input[0] + this->Element(0, 1) * input[1] + this->Element(0, 2) * input[2]; output[1] = this->Element(1, 0) * input[0] + this->Element(1, 1) * input[1] + this->Element(1, 2) * input[2]; output[2] = this->Element(2, 0) * input[0] + this->Element(2, 1) * input[1] + this->Element(2, 2) * input[2]; } template inline void ApplyTo(const vctDynamicConstVectorBase<__vectorOwnerType, value_type> & input, vctFixedSizeVectorBase & output) const throw(std::runtime_error) { CMN_ASSERT(input.Pointer() != output.Pointer()); CMN_ASSERT(input.size() == DIMENSION); output[0] = this->Element(0, 0) * input[0] + this->Element(0, 1) * input[1] + this->Element(0, 2) * input[2]; output[1] = this->Element(1, 0) * input[0] + this->Element(1, 1) * input[1] + this->Element(1, 2) * input[2]; output[2] = this->Element(2, 0) * input[0] + this->Element(2, 1) * input[1] + this->Element(2, 2) * input[2]; } /*! Apply the rotation to a dynamic vector of length 3. The result is returned by value. */ template inline vctFixedSizeVector ApplyTo(const vctDynamicConstVectorBase<__vectorOwnerType, value_type> & input) const { vctFixedSizeVector result; this->ApplyTo(input, result); return result; } /*! Apply the inverse of the rotation to a vector of fixed size 3. The result is stored into a vector of size 3 provided by the caller and passed by reference. \param input The input vector \param output The output vector */ template inline void ApplyInverseTo(const vctFixedSizeConstVectorBase & input, vctFixedSizeVectorBase & output) const { CMN_ASSERT(input.Pointer() != output.Pointer()); output.ProductOf(this->TransposeRef(), input); } /*! Apply the the inverse of the rotation to a vector of fixed size 3. The result is returned by copy. This interface might be more convenient for some but one should note that it is less efficient since it requires a copy. \param input The input vector \return The output vector */ template inline vctFixedSizeVector ApplyInverseTo(const vctFixedSizeConstVectorBase & input) const { vctFixedSizeVector result; this->ApplyInverseTo(input, result); return result; } /*! Apply the inverse rotation to a dynamic vector of length 3. The result is returned by value. */ template inline vctFixedSizeVector ApplyInverseTo(const vctDynamicConstVectorBase<__vectorOwnerType, value_type> & input) const { vctFixedSizeVector result; this->ApplyInverseTo(input, result); return result; } /*! Apply the inverse of the rotation to another rotation. The result is stored into a vctMatrixRotation3Base (ThisType) provided by the caller and passed by reference. \param input The input rotation \param output The output rotation */ inline void ApplyInverseTo(const ThisType & input, ThisType & output) const { CMN_ASSERT(input.Pointer() != output.Pointer()); output.ProductOf(this->TransposeRef(), input); } /*! Apply the inverse of the rotation to another rotation. The result is returned by copy. This interface might be more convenient for some but one should note that it is less efficient since it requires a copy. \param input The input rotation \return The output rotation */ inline ThisType ApplyInverseTo(const ThisType & input) const { CMN_ASSERT(input.Pointer() != this->Pointer()); ThisType result; this->ApplyInverseTo(input, result); return result; } /*! Apply the the inverse of the rotation to a dynamic vector. The result is stored into another dynamic vector passed by reference by the caller. It is assumed that both are of size 3. */ template inline void ApplyInverseTo(const vctDynamicConstVectorBase<__vectorOwnerType1, value_type> & input, vctDynamicVectorBase<__vectorOwnerType2, value_type> & output) const { CMN_ASSERT(input.Pointer() != output.Pointer()); CMN_ASSERT(input.size() == DIMENSION); CMN_ASSERT(output.size() == DIMENSION); output[0] = this->Element(0, 0) * input[0] + this->Element(1, 0) * input[1] + this->Element(2, 0) * input[2]; output[1] = this->Element(0, 1) * input[0] + this->Element(1, 1) * input[1] + this->Element(2, 1) * input[2]; output[2] = this->Element(0, 2) * input[0] + this->Element(1, 2) * input[1] + this->Element(2, 2) * input[2]; } /*! Apply the the inverse of the rotation to a dynamic vector. The result is stored into a fixed-size vector passed by reference by the caller. It is assumed that both are of size 3. */ template inline void ApplyInverseTo(const vctDynamicConstVectorBase<__vectorOwnerType, value_type> & input, vctFixedSizeVectorBase & output) const { CMN_ASSERT(input.Pointer() != output.Pointer()); CMN_ASSERT(input.size() == DIMENSION); output[0] = this->Element(0, 0) * input[0] + this->Element(1, 0) * input[1] + this->Element(2, 0) * input[2]; output[1] = this->Element(0, 1) * input[0] + this->Element(1, 1) * input[1] + this->Element(2, 1) * input[2]; output[2] = this->Element(0, 2) * input[0] + this->Element(1, 2) * input[1] + this->Element(2, 2) * input[2]; } /*! Apply this rotation to a fixed-size matrix with 3 rows. The result is stored in another fixed-size matrix */ template inline void ApplyTo(const vctFixedSizeConstMatrixBase & input, vctFixedSizeMatrixBase & output) const { CMN_ASSERT(input.Pointer() != output.Pointer()); output.ProductOf(*this, input); } /*! Apply this rotation to a dynamic matrix with 3 rows. The result is stored in another dynamic matrix. */ template inline void ApplyTo(const vctDynamicConstMatrixBase<__matrixOwnerType1, value_type> & input, vctDynamicMatrixBase<__matrixOwnerType2, value_type> & output) const { CMN_ASSERT((input.rows() == DIMENSION) && (output.rows() == DIMENSION) && (input.cols() == output.cols())); CMN_ASSERT(input.Pointer() != output.Pointer()); vctDynamicConstMatrixRef myRef(*this); output.ProductOf(myRef, input); } /*! Apply the inverse rotation to a fixed-size matrix with 3 rows. The result is stored in another fixed-size matrix */ template inline void ApplyInverseTo(const vctFixedSizeConstMatrixBase & input, vctFixedSizeMatrixBase & output) const { CMN_ASSERT(input.Pointer() != output.Pointer()); output.ProductOf(this->TransposeRef(), input); } /*! Apply this rotation to a dynamic matrix with 3 rows. The result is stored in another dynamic matrix. */ template inline void ApplyInverseTo(const vctDynamicConstMatrixBase<__matrixOwnerType1, value_type> & input, vctDynamicMatrixBase<__matrixOwnerType2, value_type> & output) const { CMN_ASSERT((input.rows() == DIMENSION) && (output.rows() == DIMENSION) && (input.cols() == output.cols())); CMN_ASSERT(input.Pointer() != output.Pointer()); vctDynamicConstMatrixRef myInvRef(this->TransposeRef()); output.ProductOf(myInvRef, input); } /*! Multiply two rotation matrices and return the result as a rotation matrix. \return (*this) * other \note this function overrides and shadows the operator * defined for basic matrix type. The latter returns a vctFixedSizeMatrix, while this version returns a specialized rotation matrix. */ ThisType operator * (const ThisType & input) const { return this->ApplyTo(input); } /*! Override the * operator defined in the matrix base for matrix * vector. This prevents compiler confusion between the overloaded RotMat*RotMat and the base-class Mat*Vec */ template inline vctFixedSizeVector operator * (const vctFixedSizeConstVectorBase & input) const { return this->ApplyTo(input); } /*! Return true if this rotation is effectively equivalent to the other rotation, up to the given tolerance. For a rotation matrix, this method is strictly the same as AlmostEqual. \sa AlmostEqual */ inline bool AlmostEquivalent(const ThisType & other, value_type tolerance = TypeTraits::Tolerance()) const { return this->AlmostEqual(other, tolerance); } /*! \name Deprecated methods */ //@{ /*! Convert from a unit vector and an angle. It is important to note that this method doesn't normalize the axis vector but asserts that it is normalized (in debug mode only). \param axis A unit vector of size 3. \param angle The angle in radian \deprecated This method is deprecated. Use From(vctAxisAngleRotation3) instead. */ template inline CISST_DEPRECATED const ThisType & From(const vctFixedSizeConstVectorBase & axis, const value_type & angle) { return From(vctAxisAngleRotation3(axis, angle)); } template inline CISST_DEPRECATED const ThisType & From(const vctFixedSizeConstVectorBase & rodriguezRotation) { const NormType axisLength = rodriguezRotation.Norm(); const value_type axisTolerance = cmnTypeTraits::Tolerance(); const AngleType angle = (fabs(axisLength) < axisTolerance) ? 0.0 : axisLength; const vctFixedSizeVector defaultAxis(value_type(1), value_type(0), value_type(0)); const vctFixedSizeVector axis( (angle == 0.0) ? defaultAxis : (rodriguezRotation / (value_type) axisLength) ); return this->From(axis, angle); } template inline CISST_DEPRECATED void GetAxisAngle(vctFixedSizeVectorBase & axis, value_type & angle) { angle = value_type(acos((this->Element(0, 0) + this->Element(1, 1) + this->Element(2, 2) - 1.0) / 2.0)); value_type den = value_type(sqrt((this->Element(2, 1) - this->Element(1, 2)) * (this->Element(2, 1) - this->Element(1, 2)) + (this->Element(0, 2) - this->Element(2, 0)) * (this->Element(0, 2) - this->Element(2, 0)) + (this->Element(1, 0) - this->Element(0, 1)) * (this->Element(1, 0) - this->Element(0, 1)))); axis.X() = (this->Element(2, 1) - this->Element(1, 2)) / den; axis.Y() = (this->Element(0, 2) - this->Element(2, 0)) / den; axis.Z() = (this->Element(1, 0) - this->Element(0, 1)) / den; } //@} }; /* Specialization of Allocate for a dynamic matrix */ template<> inline void vctMatrixRotation3Base >::Allocate(void) { this->SetSize(ROWS, COLS); } template<> inline void vctMatrixRotation3Base >::Allocate(void) { this->SetSize(ROWS, COLS); } #endif // _vctMatrixRotation3Base_h // **************************************************************************** // Change History // **************************************************************************** // // $Log: vctMatrixRotation3Base.h,v $ // Revision 1.25 2007/04/26 19:33:58 anton // All files in libraries: Applied new license text, separate copyright and // updated dates, added standard header where missing. // // Revision 1.24 2007/03/08 21:10:05 anton // vctMatrixRotation3Base.h: Added explicit export for template function // for Windows DLLs. Commented out ctor from 9 elements for SWIG as it // generates a string to long to handle for MS VC++. // // Revision 1.23 2007/02/27 15:52:46 anton // cisstVector transformations: Cleanup code related to template instantiation // for transformation based on dynamic containers and added support for floats. // // Revision 1.22 2007/02/07 16:09:03 anton // vctMatrixRotation3Base: Removed code for ApplyTo(ThisType) since it // is replaced by ApplyTo(vctFixedSizeMatrix). Added missing "const" // on ApplyInverseTo(vctFixedSizeMatrix). See [2250] and #248. // // Revision 1.21 2007/02/06 17:24:58 anton // vctMatrixRotation3Base: Minor typos, added const for ApplyTo(fixed size matrix) // and commented out ApplyTo(ThisType) since conflicting with ApplyTo() for // fixed size matrix. See #248 and [2247]. Tests passed with gcc. // // Revision 1.20 2007/02/05 23:41:22 ofri // vctMatrixRotation3Base : Rotation noww applicable to fixed-size and dynamic // size matrices. Also, reorganized some code related to rotation application to // vectors. // // Revision 1.19 2007/01/26 21:23:22 anton // cisstVector: Updated vctMatrixRotation3 code to reflect new design (i.e. avoid // derived class and use typedef instead, see ticket #263. // // Revision 1.18 2007/01/23 20:59:27 anton // cisstVector: Updated transformations classes so that non const methods // returning a reference on "this" return a non const reference. This follows // ticket #259. // // Revision 1.17 2006/11/20 20:33:20 anton // Licensing: Applied new license to cisstCommon, cisstVector, cisstNumerical, // cisstInteractive, cisstImage and cisstOSAbstraction. // // Revision 1.16 2006/09/26 21:47:47 anton // cisstVector and cisstNumerical: Use #ifdef CISST_COMPILER_IS_MSVC instead // of #if (CISST_COMPILER == CISST_XYZ) for XYZ in Visual Studio 7~2000, 7.1~2003 // and 8~2005. // // Revision 1.15 2006/01/20 04:46:36 anton // cisstVector: Added methods AlmostEquivalent for all transformations as well // as some missing Equal (and ==). See ticket #204. // // Revision 1.14 2006/01/18 19:10:20 anton // vctMatrixRotation3Base.h: Fixed bug #203 in FromNormalized(). // // Revision 1.13 2006/01/03 03:38:58 anton // cisstVector Doxygen: Used \code \endcode instead of
 
, added // some missing
, added links to VCT_NORMALIZE. // // Revision 1.12 2005/12/01 21:56:43 anton // vctMatrixRotation3Base.h: Typos in documentation. // // Revision 1.11 2005/11/17 18:43:52 anton // cisstVector transformations: Ongoing work re. ticket #110. // // Revision 1.10 2005/11/15 03:29:25 anton // vctMatrixRotation3Base.h: In FromRaw(vctRodriguez), used correct ctor for // temporary vctAxisAngle. // // Revision 1.9 2005/10/10 01:13:13 anton // vctMatrixRotation3Base: Instantiations didn't match declaration (throw) // // Revision 1.8 2005/10/10 00:53:39 anton // vctMatrixRotation3Base: Specialize the ctor from 9 elements based on the // containerType. This allows to use this ctor in Identity() and create a true // static variable (see #179). // // Revision 1.7 2005/10/08 20:18:58 anton // vctMatRot3Base and vctQuatRot3Base: Use assert, not throw, if size of dynamic // vector if not 3 (see #180). Updated vctQuatRot3Base to operate on dynamic // vectors. // // Revision 1.6 2005/10/07 09:31:26 anton // vctMatrixRotation3Base: Added a couple of ApplyTo(), throw exception if dynamic // vectors don't have size = 3, CMN_ASSERT to verify that the input is different // from the output (see #108) // // Revision 1.5 2005/10/07 03:32:35 anton // vctMatrixRotation3: Major update to implement ticket #110 re. initial // conditions for conversion methods (i.e. normalization of input). // // Revision 1.4 2005/10/06 16:56:37 anton // Doxygen: Corrected errors and some warnings detected by Doxygen 1.4.3. // // Revision 1.3 2005/09/26 15:41:47 anton // cisst: Added modelines for emacs and vi. // // Revision 1.2 2005/09/24 00:01:04 anton // cisstVector: Use cmnThrow for all exceptions. // // Revision 1.1 2005/09/01 06:18:08 anton // cisstVector transformations: Added a level of abstraction for all classes // derived from fixed size containers (vctQuaternion, vctQuaternionRotation3, // vctMatrixRotation3, vctRodriguezRotation3). These classes are now derived // from vctXyzBase<_containerType>. This will ease the SWIG wrapping. // // // ****************************************************************************