quaternion.h

Go to the documentation of this file.
00001 /* -*- C++ -*- ------------------------------------------------------------
00002  
00003 Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
00004 
00005 The Configurable Math Library (CML) is distributed under the terms of the
00006 Boost Software License, v1.0 (see cml/LICENSE for details).
00007 
00008  *-----------------------------------------------------------------------*/
00020 #ifndef quaternion_h
00021 #define quaternion_h
00022 
00023 #include <cml/mathlib/epsilon.h>
00024 #include <cml/quaternion/quaternion_expr.h>
00025 #include <cml/quaternion/quaternion_dot.h>
00026 #include <cml/util.h>
00027 
00028 /* This is used below to create a more meaningful compile-time error when
00029  * the quaternion class is not created with a fixed-size 4-vector:
00030  */
00031 struct quaternion_requires_fixed_size_array_type_error;
00032 
00033 namespace cml {
00034 
00040 template<
00041     typename Element,
00042     class ArrayType,
00043     class Order,
00044     class Cross
00045 >
00046 class quaternion
00047 {
00048     /* The ArrayType must be fixed<> or external<>: */
00049     CML_STATIC_REQUIRE_M(
00050             (same_type< ArrayType, fixed<> >::is_true
00051              || same_type< ArrayType, external<> >::is_true),
00052             quaternion_requires_fixed_size_array_type_error);
00053 
00054   public:
00055 
00056     /* Shorthand for the array type generator: */
00057     typedef ArrayType storage_type;
00058     typedef typename ArrayType::template rebind<4>::other generator_type;
00059 
00060     /* Vector representing the quaternion.  Use the rebinding template to
00061      * set the vector size:
00062      */
00063     typedef vector<Element, generator_type> vector_type;
00064 
00065     /* Vector temporary type: */
00066     typedef typename vector_type::temporary_type vector_temporary;
00067 
00068     /* Quaternion order: */
00069     typedef Order order_type;
00070 
00071     /* Quaternion multiplication order: */
00072     typedef Cross cross_type;
00073 
00074     /* Scalar type representing the scalar part: */
00075     typedef typename vector_type::value_type value_type;
00076     typedef typename vector_type::reference reference;
00077     typedef typename vector_type::const_reference const_reference;
00078     /* XXX Need to verify that this is a true scalar type. */
00079 
00080     /* The quaternion type: */
00081     typedef quaternion<Element,storage_type,order_type,cross_type>
00082         quaternion_type;
00083 
00084     /* For integration into the expression template code: */
00085     typedef quaternion_type expr_type;
00086 
00087     /* For integration into the expression template code: */
00088     typedef quaternion<
00089         Element, typename vector_temporary::storage_type,
00090         order_type, cross_type> temporary_type;
00091 
00092     /* For integration into the expression templates code: */
00093     typedef quaternion_type& expr_reference;
00094     typedef const quaternion_type& expr_const_reference;
00095 
00096     /* For matching by storage type: */
00097     typedef typename vector_type::memory_tag memory_tag;
00098 
00099     /* For matching by size type: */
00100     typedef typename vector_type::size_tag size_tag;
00101 
00102     /* Get the imaginary part type: */
00103     typedef typename vector_temporary::subvector_type imaginary_type;
00104 
00105     /* For matching by result-type: */
00106     typedef cml::et::quaternion_result_tag result_tag;
00107 
00108     /* For matching by assignability: */
00109     typedef cml::et::assignable_tag assignable_tag;
00110 
00111 
00112   public:
00113 
00115     enum { array_size = 4 };
00116 
00118     enum {
00119         W = order_type::W,
00120         X = order_type::X,
00121         Y = order_type::Y,
00122         Z = order_type::Z
00123     };
00124 
00125 
00126   public:
00127 
00129     value_type real() const { return m_q[W]; }
00130 
00132     imaginary_type imaginary() const {
00133         /*
00134         imaginary_type v;
00135         v[0] = m_q[X]; v[1] = m_q[Y]; v[2] = m_q[Z];
00136         return v;
00137         */
00138         return imaginary_type(m_q[X], m_q[Y], m_q[Z]);
00139     }
00140 
00142     const vector_type& as_vector() const {
00143         return m_q;
00144     }
00145 
00147     value_type norm() const {
00148         return length_squared();
00149     }
00150 
00152     value_type length_squared() const {
00153         return cml::dot(*this,*this);
00154     }
00155 
00157     value_type length() const {
00158         return std::sqrt(length_squared());
00159     }
00160 
00165     quaternion_type& normalize() {
00166         return (*this /= length());
00167     }
00168 
00170     quaternion_type& conjugate() {
00171         return (*this) = cml::conjugate(*this);
00172     }
00173 
00175     quaternion_type& inverse() {
00176         return (*this) = cml::inverse(*this);
00177     }
00178 
00180     quaternion_type& identity() {
00181         m_q[W] = value_type(1);
00182         m_q[X] = value_type(0);
00183         m_q[Y] = value_type(0);
00184         m_q[Z] = value_type(0);
00185         return *this;
00186     }
00187     
00189     temporary_type log(
00190         value_type tolerance = epsilon<value_type>::placeholder()) const
00191     {
00192         value_type a = acos_safe(real());
00193         value_type s = std::sin(a);
00194         
00195         if (s > tolerance) {
00196             return temporary_type(value_type(0), imaginary() * (a / s));
00197         } else {
00198             return temporary_type(value_type(0), imaginary());
00199         }
00200     }
00201     
00206     temporary_type exp(
00207         value_type tolerance = epsilon<value_type>::placeholder()) const
00208     {
00209         imaginary_type v = imaginary();
00210         value_type a = cml::length(v);
00211         
00212         if (a > tolerance) {
00213             return temporary_type(std::cos(a), v * (std::sin(a) / a));
00214         } else {
00215             return temporary_type(std::cos(a), v);
00216         }
00217     }
00218 
00219 
00221     const_reference operator[](size_t i) const { return m_q[i]; }
00222 
00224     reference operator[](size_t i) { return m_q[i]; }
00225 
00230     void random(value_type min, value_type max) {
00231         for (size_t i = 0; i < 4; ++i) {
00232             m_q[i] = random_real(min,max);
00233         }
00234     }
00235 
00236   public:
00237 
00243     quaternion() {}
00244 
00246     quaternion(Element* const array) : m_q(array) {}
00247 
00249     quaternion(const quaternion_type& q) : m_q(q.m_q) {}
00250 
00252     template<typename E, class AT> quaternion(
00253             const quaternion<E,AT,order_type,cross_type>& q)
00254         : m_q(q.as_vector()) {}
00255 
00257     template<typename XprT> quaternion(QUATXPR_ARG_TYPE e) {
00258         typedef typename XprT::order_type arg_order;
00259         m_q[W] = e[arg_order::W];
00260         m_q[X] = e[arg_order::X];
00261         m_q[Y] = e[arg_order::Y];
00262         m_q[Z] = e[arg_order::Z];
00263     }
00264 
00265 
00266 
00272     quaternion(const vector_type& v) : m_q(v) {}
00273 
00282     quaternion(const value_type v[4]) : m_q(v) {}
00283 
00290     quaternion(
00291             const value_type& a, const value_type& b,
00292             const value_type& c, const value_type& d)
00293     {
00294       /* Call the overloaded assignment function: */
00295       assign(a, b, c, d, Order());
00296     }
00297 
00304     quaternion(const value_type& s, const imaginary_type& v) {
00305         m_q[W] = s; m_q[X] = v[0]; m_q[Y] = v[1]; m_q[Z] = v[2];
00306     }
00307 
00314     quaternion(const imaginary_type& v, const value_type& s) {
00315         m_q[W] = s; m_q[X] = v[0]; m_q[Y] = v[1]; m_q[Z] = v[2];
00316     }
00317 
00324     quaternion(const value_type v[3], const value_type& s) {
00325         m_q[W] = s; m_q[X] = v[0]; m_q[Y] = v[1]; m_q[Z] = v[2];
00326     }
00327 
00334     quaternion(const value_type& s, const value_type v[3]) {
00335         m_q[W] = s; m_q[X] = v[0]; m_q[Y] = v[1]; m_q[Z] = v[2];
00336     }
00337 
00338 
00339 
00341     template<typename XprT>
00342         quaternion(VECXPR_ARG_TYPE e) : m_q(e) {}
00343 
00348     template<typename XprT>
00349         quaternion(const value_type& s, VECXPR_ARG_TYPE e) {
00350             m_q[W] = s; m_q[X] = e[0]; m_q[Y] = e[1]; m_q[Z] = e[2];
00351         }
00352         
00353     // @todo: Are we missing:
00354     
00355     // quaternion(VECXPR_ARG_TYPE e, const value_type& s) {}
00356     
00357     // Or is that covered elsewhere?
00358 
00364 #define CML_QUAT_ASSIGN_FROM_QUAT(_op_)                                 \
00365     template<typename E, class AT> const quaternion_type&               \
00366     operator _op_ (const quaternion<E,AT,order_type,cross_type>& q) {   \
00367         m_q[W] _op_ q[W];                                               \
00368         m_q[X] _op_ q[X];                                               \
00369         m_q[Y] _op_ q[Y];                                               \
00370         m_q[Z] _op_ q[Z];                                               \
00371         return *this;                                                   \
00372     }
00373 
00378 #define CML_QUAT_ASSIGN_FROM_QUATXPR(_op_)                              \
00379     template<typename XprT> quaternion_type&                            \
00380     operator _op_ (QUATXPR_ARG_TYPE e) {                                \
00381         typedef typename XprT::order_type arg_order;                    \
00382         m_q[W] _op_ e[arg_order::W];                                    \
00383         m_q[X] _op_ e[arg_order::X];                                    \
00384         m_q[Y] _op_ e[arg_order::Y];                                    \
00385         m_q[Z] _op_ e[arg_order::Z];                                    \
00386         return *this;                                                   \
00387     }
00388 
00393 #define CML_QUAT_ASSIGN_FROM_SCALAR(_op_,_op_name_)               \
00394     quaternion_type& operator _op_ (const value_type& s) {        \
00395         typedef _op_name_ <value_type,value_type> OpT;            \
00396         OpT().apply(m_q[W],s);                                    \
00397         OpT().apply(m_q[X],s);                                    \
00398         OpT().apply(m_q[Y],s);                                    \
00399         OpT().apply(m_q[Z],s);                                    \
00400         return *this;                                             \
00401     }
00402 
00403     CML_QUAT_ASSIGN_FROM_QUAT(=)
00404     CML_QUAT_ASSIGN_FROM_QUAT(+=)
00405     CML_QUAT_ASSIGN_FROM_QUAT(-=)
00406 
00407     CML_QUAT_ASSIGN_FROM_QUATXPR(=)
00408     CML_QUAT_ASSIGN_FROM_QUATXPR(+=)
00409     CML_QUAT_ASSIGN_FROM_QUATXPR(-=)
00410 
00411     CML_QUAT_ASSIGN_FROM_SCALAR(*=, cml::et::OpMulAssign)
00412     CML_QUAT_ASSIGN_FROM_SCALAR(/=, cml::et::OpDivAssign)
00413 
00414 #undef CML_QUAT_ASSIGN_FROM_QUAT
00415 #undef CML_QUAT_ASSIGN_FROM_QUATXPR
00416 #undef CML_QUAT_ASSIGN_FROM_SCALAR
00417 
00429     quaternion_type& operator*=(const quaternion_type& q) {
00430         return (*this = *this * q);
00431     }
00432 
00444     template<typename XprT> quaternion_type& operator*=(QUATXPR_ARG_TYPE e) {
00445         return (*this = *this * e);
00446     }
00447 
00449     typename vector_type::pointer data() { return m_q.data(); }
00450 
00452     const typename vector_type::pointer data() const { return m_q.data(); }
00453 
00454 
00455     /* NOTE: Quaternion division no longer supported, but I'm leaving the
00456        code here for reference (Jesse) */
00457 
00458     #if 0
00459 
00474     quaternion_type& operator/=(const quaternion_type& q) {
00475         return (*this = *this * cml::inverse(q));
00476     }
00477 
00493     template<typename XprT> quaternion_type& operator/=(QUATXPR_ARG_TYPE e) {
00494         return (*this = *this * cml::inverse(e));
00495     }
00496     #endif
00497 
00498 
00499   protected:
00500 
00502     void assign(const value_type& a, const value_type& b,
00503     const value_type& c, const value_type& d, scalar_first)
00504     {
00505       m_q[W] = a; m_q[X] = b; m_q[Y] = c; m_q[Z] = d;
00506     }
00507 
00509     void assign(const value_type& a, const value_type& b,
00510     const value_type& c, const value_type& d, vector_first)
00511     {
00512       m_q[X] = a; m_q[Y] = b; m_q[Z] = c; m_q[W] = d;
00513     }
00514 
00515 
00516   protected:
00517 
00518     vector_type                 m_q;
00519 };
00520 
00521 } // namespace cml
00522 
00523 #endif
00524 
00525 // -------------------------------------------------------------------------
00526 // vim:ft=cpp

Generated on Sat Jul 18 19:35:28 2009 for CML 1.0 by  doxygen 1.5.9