File indexing completed on 2025-01-18 09:51:08
0001 #ifndef BOOST_QVM_QUAT_OPERATIONS
0002 #define BOOST_QVM_QUAT_OPERATIONS
0003
0004
0005
0006
0007
0008
0009 #include <boost/qvm/detail/quat_assign.hpp>
0010 #include <boost/qvm/deduce_quat.hpp>
0011 #include <boost/qvm/mat_traits.hpp>
0012 #include <boost/qvm/scalar_traits.hpp>
0013 #include <boost/qvm/math.hpp>
0014 #include <boost/qvm/assert.hpp>
0015 #include <boost/qvm/error.hpp>
0016 #include <boost/qvm/throw_exception.hpp>
0017 #include <boost/qvm/to_string.hpp>
0018
0019 namespace boost { namespace qvm {
0020
0021 namespace
0022 qvm_detail
0023 {
0024 BOOST_QVM_INLINE_CRITICAL
0025 void const *
0026 get_valid_ptr_quat_operations()
0027 {
0028 static int const obj=0;
0029 return &obj;
0030 }
0031 }
0032
0033
0034
0035 namespace
0036 msvc_parse_bug_workaround
0037 {
0038 template <class A,class B>
0039 struct
0040 quats
0041 {
0042 static bool const value=is_quat<A>::value && is_quat<B>::value;
0043 };
0044 }
0045
0046
0047 template <class A>
0048 inline
0049 typename enable_if_c<
0050 is_quat<A>::value,
0051 std::string>::type
0052 to_string( A const & a )
0053 {
0054 using namespace qvm_to_string_detail;
0055 return '('+
0056 to_string(quat_traits<A>::template read_element<0>(a))+','+
0057 to_string(quat_traits<A>::template read_element<1>(a))+','+
0058 to_string(quat_traits<A>::template read_element<2>(a))+','+
0059 to_string(quat_traits<A>::template read_element<3>(a))+')';
0060 }
0061
0062
0063
0064 template <class A,class B,class Cmp>
0065 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0066 typename enable_if_c<
0067 is_quat<A>::value && is_quat<B>::value,
0068 bool>::type
0069 cmp( A const & a, B const & b, Cmp f )
0070 {
0071 typedef typename quat_traits<A>::scalar_type T;
0072 typedef typename quat_traits<B>::scalar_type U;
0073 T q1[4] =
0074 {
0075 quat_traits<A>::template read_element<0>(a),
0076 quat_traits<A>::template read_element<1>(a),
0077 quat_traits<A>::template read_element<2>(a),
0078 quat_traits<A>::template read_element<3>(a)
0079 };
0080 U q2[4] =
0081 {
0082 quat_traits<B>::template read_element<0>(b),
0083 quat_traits<B>::template read_element<1>(b),
0084 quat_traits<B>::template read_element<2>(b),
0085 quat_traits<B>::template read_element<3>(b)
0086 };
0087 int i=0;
0088 for( ; i!=4; ++i )
0089 if( !f(q1[i],q2[i]) )
0090 break;
0091 if( i==4 )
0092 return true;
0093 for( i=0; i!=4; ++i )
0094 if( !f(q1[i],-q2[i]) )
0095 return false;
0096 return true;
0097 }
0098
0099
0100
0101 template <class R,class A>
0102 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
0103 typename enable_if_c<
0104 is_quat<R>::value && is_quat<A>::value,
0105 R>::type
0106 convert_to( A const & a )
0107 {
0108 R r;
0109 write_quat_element<0>(r,quat_traits<A>::template read_element<0>(a));
0110 write_quat_element<1>(r,quat_traits<A>::template read_element<1>(a));
0111 write_quat_element<2>(r,quat_traits<A>::template read_element<2>(a));
0112 write_quat_element<3>(r,quat_traits<A>::template read_element<3>(a));
0113 return r;
0114 }
0115
0116 template <class R,class A>
0117 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0118 typename enable_if_c<
0119 is_quat<R>::value && is_mat<A>::value &&
0120 mat_traits<A>::rows==3 && mat_traits<A>::cols==3,
0121 R>::type
0122 convert_to( A const & a )
0123 {
0124 typedef typename mat_traits<A>::scalar_type T;
0125 T const mat[3][3] =
0126 {
0127 { mat_traits<A>::template read_element<0,0>(a), mat_traits<A>::template read_element<0,1>(a), mat_traits<A>::template read_element<0,2>(a) },
0128 { mat_traits<A>::template read_element<1,0>(a), mat_traits<A>::template read_element<1,1>(a), mat_traits<A>::template read_element<1,2>(a) },
0129 { mat_traits<A>::template read_element<2,0>(a), mat_traits<A>::template read_element<2,1>(a), mat_traits<A>::template read_element<2,2>(a) }
0130 };
0131 R r;
0132 if( mat[0][0]+mat[1][1]+mat[2][2] > scalar_traits<T>::value(0) )
0133 {
0134 T t = mat[0][0] + mat[1][1] + mat[2][2] + scalar_traits<T>::value(1);
0135 T s = (scalar_traits<T>::value(1)/sqrt(t))/2;
0136 write_quat_element<0>(r,s*t);
0137 write_quat_element<1>(r,(mat[2][1]-mat[1][2])*s);
0138 write_quat_element<2>(r,(mat[0][2]-mat[2][0])*s);
0139 write_quat_element<3>(r,(mat[1][0]-mat[0][1])*s);
0140 }
0141 else if( mat[0][0]>mat[1][1] && mat[0][0]>mat[2][2] )
0142 {
0143 T t = mat[0][0] - mat[1][1] - mat[2][2] + scalar_traits<T>::value(1);
0144 T s = (scalar_traits<T>::value(1)/sqrt(t))/2;
0145 write_quat_element<0>(r,(mat[2][1]-mat[1][2])*s);
0146 write_quat_element<1>(r,s*t);
0147 write_quat_element<2>(r,(mat[1][0]+mat[0][1])*s);
0148 write_quat_element<3>(r,(mat[0][2]+mat[2][0])*s);
0149 }
0150 else if( mat[1][1]>mat[2][2] )
0151 {
0152 T t = - mat[0][0] + mat[1][1] - mat[2][2] + scalar_traits<T>::value(1);
0153 T s = (scalar_traits<T>::value(1)/sqrt(t))/2;
0154 write_quat_element<0>(r,(mat[0][2]-mat[2][0])*s);
0155 write_quat_element<1>(r,(mat[1][0]+mat[0][1])*s);
0156 write_quat_element<2>(r,s*t);
0157 write_quat_element<3>(r,(mat[2][1]+mat[1][2])*s);
0158 }
0159 else
0160 {
0161 T t = - mat[0][0] - mat[1][1] + mat[2][2] + scalar_traits<T>::value(1);
0162 T s = (scalar_traits<T>::value(1)/sqrt(t))/2;
0163 write_quat_element<0>(r,(mat[1][0]-mat[0][1])*s);
0164 write_quat_element<1>(r,(mat[0][2]+mat[2][0])*s);
0165 write_quat_element<2>(r,(mat[2][1]+mat[1][2])*s);
0166 write_quat_element<3>(r,s*t);
0167 }
0168 return r;
0169 }
0170
0171
0172
0173 template <class A>
0174 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0175 typename lazy_enable_if_c<
0176 is_quat<A>::value,
0177 deduce_quat<A> >::type
0178 conjugate( A const & a )
0179 {
0180 typedef typename deduce_quat<A>::type R;
0181 R r;
0182 write_quat_element<0>(r,quat_traits<A>::template read_element<0>(a));
0183 write_quat_element<1>(r,-quat_traits<A>::template read_element<1>(a));
0184 write_quat_element<2>(r,-quat_traits<A>::template read_element<2>(a));
0185 write_quat_element<3>(r,-quat_traits<A>::template read_element<3>(a));
0186 return r;
0187 }
0188
0189
0190
0191 namespace
0192 qvm_detail
0193 {
0194 template <class T>
0195 class
0196 identity_quat_
0197 {
0198 identity_quat_( identity_quat_ const & );
0199 identity_quat_ & operator=( identity_quat_ const & );
0200 ~identity_quat_();
0201
0202 public:
0203
0204 template <class R
0205 #if __cplusplus >= 201103L
0206 , class = typename enable_if<is_quat<R> >::type
0207 #endif
0208 >
0209 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
0210 operator R() const
0211 {
0212 R r;
0213 assign(r,*this);
0214 return r;
0215 }
0216 };
0217 }
0218
0219 template <class T>
0220 struct
0221 quat_traits< qvm_detail::identity_quat_<T> >
0222 {
0223 typedef qvm_detail::identity_quat_<T> this_quaternion;
0224 typedef T scalar_type;
0225
0226 template <int I>
0227 static
0228 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
0229 scalar_type
0230 read_element( this_quaternion const & )
0231 {
0232 BOOST_QVM_STATIC_ASSERT(I>=0);
0233 BOOST_QVM_STATIC_ASSERT(I<4);
0234 return scalar_traits<T>::value(I==0);
0235 }
0236
0237 static
0238 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
0239 scalar_type
0240 read_element_idx( int i, this_quaternion const & )
0241 {
0242 BOOST_QVM_ASSERT(i>=0);
0243 BOOST_QVM_ASSERT(i<4);
0244 return scalar_traits<T>::value(i==0);
0245 }
0246 };
0247
0248 template <class T>
0249 struct
0250 deduce_quat< qvm_detail::identity_quat_<T> >
0251 {
0252 typedef quat<T> type;
0253 };
0254
0255 template <class T>
0256 struct
0257 deduce_quat2< qvm_detail::identity_quat_<T>, qvm_detail::identity_quat_<T> >
0258 {
0259 typedef quat<T> type;
0260 };
0261
0262 template <class T>
0263 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
0264 qvm_detail::identity_quat_<T> const &
0265 identity_quat()
0266 {
0267 return *(qvm_detail::identity_quat_<T> const *)qvm_detail::get_valid_ptr_quat_operations();
0268 }
0269
0270 template <class A>
0271 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0272 typename enable_if_c<
0273 is_quat<A>::value,
0274 void>::type
0275 set_identity( A & a )
0276 {
0277 typedef typename quat_traits<A>::scalar_type T;
0278 T const zero=scalar_traits<T>::value(0);
0279 T const one=scalar_traits<T>::value(1);
0280 write_quat_element<0>(a,one);
0281 write_quat_element<1>(a,zero);
0282 write_quat_element<2>(a,zero);
0283 write_quat_element<3>(a,zero);
0284 }
0285
0286
0287
0288 namespace
0289 qvm_detail
0290 {
0291 template <class OriginalType,class Scalar>
0292 class
0293 quaternion_scalar_cast_
0294 {
0295 quaternion_scalar_cast_( quaternion_scalar_cast_ const & );
0296 quaternion_scalar_cast_ & operator=( quaternion_scalar_cast_ const & );
0297 ~quaternion_scalar_cast_();
0298
0299 public:
0300
0301 template <class T>
0302 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
0303 quaternion_scalar_cast_ &
0304 operator=( T const & x )
0305 {
0306 assign(*this,x);
0307 return *this;
0308 }
0309
0310 template <class R
0311 #if __cplusplus >= 201103L
0312 , class = typename enable_if<is_quat<R> >::type
0313 #endif
0314 >
0315 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
0316 operator R() const
0317 {
0318 R r;
0319 assign(r,*this);
0320 return r;
0321 }
0322 };
0323
0324 template <bool> struct scalar_cast_quaternion_filter { };
0325 template <> struct scalar_cast_quaternion_filter<true> { typedef int type; };
0326 }
0327
0328 template <class OriginalType,class Scalar>
0329 struct
0330 quat_traits< qvm_detail::quaternion_scalar_cast_<OriginalType,Scalar> >
0331 {
0332 typedef Scalar scalar_type;
0333 typedef qvm_detail::quaternion_scalar_cast_<OriginalType,Scalar> this_quaternion;
0334
0335 template <int I>
0336 static
0337 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
0338 scalar_type
0339 read_element( this_quaternion const & x )
0340 {
0341 BOOST_QVM_STATIC_ASSERT(I>=0);
0342 BOOST_QVM_STATIC_ASSERT(I<4);
0343 return scalar_type(quat_traits<OriginalType>::template read_element<I>(reinterpret_cast<OriginalType const &>(x)));
0344 }
0345
0346 static
0347 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
0348 scalar_type
0349 read_element_idx( int i, this_quaternion const & x )
0350 {
0351 BOOST_QVM_ASSERT(i>=0);
0352 BOOST_QVM_ASSERT(i<4);
0353 return scalar_type(quat_traits<OriginalType>::read_element_idx(i,reinterpret_cast<OriginalType const &>(x)));
0354 }
0355 };
0356
0357 template <class Scalar,class T>
0358 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
0359 qvm_detail::quaternion_scalar_cast_<T,Scalar> const &
0360 scalar_cast( T const & x, typename qvm_detail::scalar_cast_quaternion_filter<is_quat<T>::value>::type=0 )
0361 {
0362 return reinterpret_cast<qvm_detail::quaternion_scalar_cast_<T,Scalar> const &>(x);
0363 }
0364
0365
0366
0367 template <class A,class B>
0368 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0369 typename enable_if_c<
0370 is_quat<A>::value && is_scalar<B>::value,
0371 A &>::type
0372 operator/=( A & a, B b )
0373 {
0374 write_quat_element<0>(a,quat_traits<A>::template read_element<0>(a)/b);
0375 write_quat_element<1>(a,quat_traits<A>::template read_element<1>(a)/b);
0376 write_quat_element<2>(a,quat_traits<A>::template read_element<2>(a)/b);
0377 write_quat_element<3>(a,quat_traits<A>::template read_element<3>(a)/b);
0378 return a;
0379 }
0380
0381 template <class A,class B>
0382 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0383 typename lazy_enable_if_c<
0384 is_quat<A>::value && is_scalar<B>::value,
0385 deduce_quat2<A,B> >::type
0386 operator/( A const & a, B b )
0387 {
0388 typedef typename deduce_quat2<A,B>::type R;
0389 R r;
0390 write_quat_element<0>(r,quat_traits<A>::template read_element<0>(a)/b);
0391 write_quat_element<1>(r,quat_traits<A>::template read_element<1>(a)/b);
0392 write_quat_element<2>(r,quat_traits<A>::template read_element<2>(a)/b);
0393 write_quat_element<3>(r,quat_traits<A>::template read_element<3>(a)/b);
0394 return r;
0395 }
0396
0397 template <class A,class B>
0398 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0399 typename lazy_enable_if_c<
0400 is_quat<A>::value && is_quat<B>::value,
0401 deduce_scalar<typename quat_traits<A>::scalar_type,typename quat_traits<B>::scalar_type> >::type
0402 dot( A const & a, B const & b )
0403 {
0404 typedef typename quat_traits<A>::scalar_type Ta;
0405 typedef typename quat_traits<B>::scalar_type Tb;
0406 typedef typename deduce_scalar<Ta,Tb>::type Tr;
0407 Ta const a0=quat_traits<A>::template read_element<0>(a);
0408 Ta const a1=quat_traits<A>::template read_element<1>(a);
0409 Ta const a2=quat_traits<A>::template read_element<2>(a);
0410 Ta const a3=quat_traits<A>::template read_element<3>(a);
0411 Tb const b0=quat_traits<B>::template read_element<0>(b);
0412 Tb const b1=quat_traits<B>::template read_element<1>(b);
0413 Tb const b2=quat_traits<B>::template read_element<2>(b);
0414 Tb const b3=quat_traits<B>::template read_element<3>(b);
0415 Tr const dp=a0*b0+a1*b1+a2*b2+a3*b3;
0416 return dp;
0417 }
0418
0419 template <class A,class B>
0420 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0421 typename enable_if_c<
0422 is_quat<A>::value && is_quat<B>::value,
0423 bool>::type
0424 operator==( A const & a, B const & b )
0425 {
0426 return
0427 quat_traits<A>::template read_element<0>(a)==quat_traits<B>::template read_element<0>(b) &&
0428 quat_traits<A>::template read_element<1>(a)==quat_traits<B>::template read_element<1>(b) &&
0429 quat_traits<A>::template read_element<2>(a)==quat_traits<B>::template read_element<2>(b) &&
0430 quat_traits<A>::template read_element<3>(a)==quat_traits<B>::template read_element<3>(b);
0431 }
0432
0433 template <class A>
0434 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0435 typename lazy_enable_if_c<
0436 is_quat<A>::value,
0437 deduce_quat<A> >::type
0438 inverse( A const & a )
0439 {
0440 typedef typename deduce_quat<A>::type R;
0441 typedef typename quat_traits<A>::scalar_type TA;
0442 TA aa = quat_traits<A>::template read_element<0>(a);
0443 TA ab = quat_traits<A>::template read_element<1>(a);
0444 TA ac = quat_traits<A>::template read_element<2>(a);
0445 TA ad = quat_traits<A>::template read_element<3>(a);
0446 TA m2 = ab*ab + ac*ac + ad*ad + aa*aa;
0447 if( m2==scalar_traits<TA>::value(0) )
0448 BOOST_QVM_THROW_EXCEPTION(zero_magnitude_error());
0449 TA rm=scalar_traits<TA>::value(1)/m2;
0450 R r;
0451 write_quat_element<0>(r,aa*rm);
0452 write_quat_element<1>(r,-ab*rm);
0453 write_quat_element<2>(r,-ac*rm);
0454 write_quat_element<3>(r,-ad*rm);
0455 return r;
0456 }
0457
0458 template <class A>
0459 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0460 typename enable_if_c<
0461 is_quat<A>::value,
0462 typename quat_traits<A>::scalar_type>::type
0463 mag_sqr( A const & a )
0464 {
0465 typedef typename quat_traits<A>::scalar_type T;
0466 T x=quat_traits<A>::template read_element<0>(a);
0467 T y=quat_traits<A>::template read_element<1>(a);
0468 T z=quat_traits<A>::template read_element<2>(a);
0469 T w=quat_traits<A>::template read_element<3>(a);
0470 return x*x+y*y+z*z+w*w;
0471 }
0472
0473 template <class A>
0474 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0475 typename enable_if_c<
0476 is_quat<A>::value,
0477 typename quat_traits<A>::scalar_type>::type
0478 mag( A const & a )
0479 {
0480 typedef typename quat_traits<A>::scalar_type T;
0481 T x=quat_traits<A>::template read_element<0>(a);
0482 T y=quat_traits<A>::template read_element<1>(a);
0483 T z=quat_traits<A>::template read_element<2>(a);
0484 T w=quat_traits<A>::template read_element<3>(a);
0485 return sqrt(x*x+y*y+z*z+w*w);
0486 }
0487
0488 template <class A,class B>
0489 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0490 typename enable_if<
0491 msvc_parse_bug_workaround::quats<A,B>,
0492 A &>::type
0493 operator-=( A & a, B const & b )
0494 {
0495 write_quat_element<0>(a,quat_traits<A>::template read_element<0>(a)-quat_traits<B>::template read_element<0>(b));
0496 write_quat_element<1>(a,quat_traits<A>::template read_element<1>(a)-quat_traits<B>::template read_element<1>(b));
0497 write_quat_element<2>(a,quat_traits<A>::template read_element<2>(a)-quat_traits<B>::template read_element<2>(b));
0498 write_quat_element<3>(a,quat_traits<A>::template read_element<3>(a)-quat_traits<B>::template read_element<3>(b));
0499 return a;
0500 }
0501
0502 template <class A,class B>
0503 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0504 typename lazy_enable_if_c<
0505 is_quat<A>::value && is_quat<B>::value,
0506 deduce_quat2<A,B> >::type
0507 operator-( A const & a, B const & b )
0508 {
0509 typedef typename deduce_quat2<A,B>::type R;
0510 R r;
0511 write_quat_element<0>(r,quat_traits<A>::template read_element<0>(a)-quat_traits<B>::template read_element<0>(b));
0512 write_quat_element<1>(r,quat_traits<A>::template read_element<1>(a)-quat_traits<B>::template read_element<1>(b));
0513 write_quat_element<2>(r,quat_traits<A>::template read_element<2>(a)-quat_traits<B>::template read_element<2>(b));
0514 write_quat_element<3>(r,quat_traits<A>::template read_element<3>(a)-quat_traits<B>::template read_element<3>(b));
0515 return r;
0516 }
0517
0518 template <class A>
0519 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0520 typename lazy_enable_if_c<
0521 is_quat<A>::value,
0522 deduce_quat<A> >::type
0523 operator-( A const & a )
0524 {
0525 typedef typename deduce_quat<A>::type R;
0526 R r;
0527 write_quat_element<0>(r,-quat_traits<A>::template read_element<0>(a));
0528 write_quat_element<1>(r,-quat_traits<A>::template read_element<1>(a));
0529 write_quat_element<2>(r,-quat_traits<A>::template read_element<2>(a));
0530 write_quat_element<3>(r,-quat_traits<A>::template read_element<3>(a));
0531 return r;
0532 }
0533
0534 template <class A,class B>
0535 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0536 typename enable_if<
0537 msvc_parse_bug_workaround::quats<A,B>,
0538 A &>::type
0539 operator*=( A & a, B const & b )
0540 {
0541 typedef typename quat_traits<A>::scalar_type TA;
0542 typedef typename quat_traits<B>::scalar_type TB;
0543 TA const aa=quat_traits<A>::template read_element<0>(a);
0544 TA const ab=quat_traits<A>::template read_element<1>(a);
0545 TA const ac=quat_traits<A>::template read_element<2>(a);
0546 TA const ad=quat_traits<A>::template read_element<3>(a);
0547 TB const ba=quat_traits<B>::template read_element<0>(b);
0548 TB const bb=quat_traits<B>::template read_element<1>(b);
0549 TB const bc=quat_traits<B>::template read_element<2>(b);
0550 TB const bd=quat_traits<B>::template read_element<3>(b);
0551 write_quat_element<0>(a,aa*ba - ab*bb - ac*bc - ad*bd);
0552 write_quat_element<1>(a,aa*bb + ab*ba + ac*bd - ad*bc);
0553 write_quat_element<2>(a,aa*bc + ac*ba + ad*bb - ab*bd);
0554 write_quat_element<3>(a,aa*bd + ad*ba + ab*bc - ac*bb);
0555 return a;
0556 }
0557
0558 template <class A,class B>
0559 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0560 typename enable_if_c<
0561 is_quat<A>::value && is_scalar<B>::value,
0562 A &>::type
0563 operator*=( A & a, B b )
0564 {
0565 write_quat_element<0>(a, quat_traits<A>::template read_element<0>(a)*b);
0566 write_quat_element<1>(a, quat_traits<A>::template read_element<1>(a)*b);
0567 write_quat_element<2>(a, quat_traits<A>::template read_element<2>(a)*b);
0568 write_quat_element<3>(a, quat_traits<A>::template read_element<3>(a)*b);
0569 return a;
0570 }
0571
0572 template <class A,class B>
0573 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0574 typename lazy_enable_if_c<
0575 is_quat<A>::value && is_quat<B>::value,
0576 deduce_quat2<A,B> >::type
0577 operator*( A const & a, B const & b )
0578 {
0579 typedef typename deduce_quat2<A,B>::type R;
0580 typedef typename quat_traits<A>::scalar_type TA;
0581 typedef typename quat_traits<B>::scalar_type TB;
0582 TA const aa=quat_traits<A>::template read_element<0>(a);
0583 TA const ab=quat_traits<A>::template read_element<1>(a);
0584 TA const ac=quat_traits<A>::template read_element<2>(a);
0585 TA const ad=quat_traits<A>::template read_element<3>(a);
0586 TB const ba=quat_traits<B>::template read_element<0>(b);
0587 TB const bb=quat_traits<B>::template read_element<1>(b);
0588 TB const bc=quat_traits<B>::template read_element<2>(b);
0589 TB const bd=quat_traits<B>::template read_element<3>(b);
0590 R r;
0591 write_quat_element<0>(r,aa*ba - ab*bb - ac*bc - ad*bd);
0592 write_quat_element<1>(r,aa*bb + ab*ba + ac*bd - ad*bc);
0593 write_quat_element<2>(r,aa*bc + ac*ba + ad*bb - ab*bd);
0594 write_quat_element<3>(r,aa*bd + ad*ba + ab*bc - ac*bb);
0595 return r;
0596 }
0597
0598 template <class A,class B>
0599 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0600 typename lazy_enable_if_c2<
0601 is_quat<A>::value && is_scalar<B>::value,
0602 deduce_quat2<A,B> >::type
0603 operator*( A const & a, B b )
0604 {
0605 typedef typename deduce_quat2<A,B>::type R;
0606 R r;
0607 write_quat_element<0>(r,quat_traits<A>::template read_element<0>(a)*b);
0608 write_quat_element<1>(r,quat_traits<A>::template read_element<1>(a)*b);
0609 write_quat_element<2>(r,quat_traits<A>::template read_element<2>(a)*b);
0610 write_quat_element<3>(r,quat_traits<A>::template read_element<3>(a)*b);
0611 return r;
0612 }
0613
0614 template <class A,class B>
0615 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0616 typename enable_if_c<
0617 is_quat<A>::value && is_quat<B>::value,
0618 bool>::type
0619 operator!=( A const & a, B const & b )
0620 {
0621 return
0622 quat_traits<A>::template read_element<0>(a)!=quat_traits<B>::template read_element<0>(b) ||
0623 quat_traits<A>::template read_element<1>(a)!=quat_traits<B>::template read_element<1>(b) ||
0624 quat_traits<A>::template read_element<2>(a)!=quat_traits<B>::template read_element<2>(b) ||
0625 quat_traits<A>::template read_element<3>(a)!=quat_traits<B>::template read_element<3>(b);
0626 }
0627
0628 template <class A>
0629 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0630 typename lazy_enable_if_c<
0631 is_quat<A>::value,
0632 deduce_quat<A> >::type
0633 normalized( A const & a )
0634 {
0635 typedef typename quat_traits<A>::scalar_type T;
0636 T const a0=quat_traits<A>::template read_element<0>(a);
0637 T const a1=quat_traits<A>::template read_element<1>(a);
0638 T const a2=quat_traits<A>::template read_element<2>(a);
0639 T const a3=quat_traits<A>::template read_element<3>(a);
0640 T const m2=a0*a0+a1*a1+a2*a2+a3*a3;
0641 if( m2==scalar_traits<typename quat_traits<A>::scalar_type>::value(0) )
0642 BOOST_QVM_THROW_EXCEPTION(zero_magnitude_error());
0643 T const rm=scalar_traits<T>::value(1)/sqrt(m2);
0644 typedef typename deduce_quat<A>::type R;
0645 R r;
0646 write_quat_element<0>(r,a0*rm);
0647 write_quat_element<1>(r,a1*rm);
0648 write_quat_element<2>(r,a2*rm);
0649 write_quat_element<3>(r,a3*rm);
0650 return r;
0651 }
0652
0653 template <class A>
0654 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0655 typename enable_if_c<
0656 is_quat<A>::value,
0657 void>::type
0658 normalize( A & a )
0659 {
0660 typedef typename quat_traits<A>::scalar_type T;
0661 T const a0=quat_traits<A>::template read_element<0>(a);
0662 T const a1=quat_traits<A>::template read_element<1>(a);
0663 T const a2=quat_traits<A>::template read_element<2>(a);
0664 T const a3=quat_traits<A>::template read_element<3>(a);
0665 T const m2=a0*a0+a1*a1+a2*a2+a3*a3;
0666 if( m2==scalar_traits<typename quat_traits<A>::scalar_type>::value(0) )
0667 BOOST_QVM_THROW_EXCEPTION(zero_magnitude_error());
0668 T const rm=scalar_traits<T>::value(1)/sqrt(m2);
0669 write_quat_element<0>(a,quat_traits<A>::template read_element<0>(a)*rm);
0670 write_quat_element<1>(a,quat_traits<A>::template read_element<1>(a)*rm);
0671 write_quat_element<2>(a,quat_traits<A>::template read_element<2>(a)*rm);
0672 write_quat_element<3>(a,quat_traits<A>::template read_element<3>(a)*rm);
0673 }
0674
0675 template <class A,class B>
0676 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0677 typename enable_if<
0678 msvc_parse_bug_workaround::quats<A,B>,
0679 A &>::type
0680 operator+=( A & a, B const & b )
0681 {
0682 write_quat_element<0>(a,quat_traits<A>::template read_element<0>(a)+quat_traits<B>::template read_element<0>(b));
0683 write_quat_element<1>(a,quat_traits<A>::template read_element<1>(a)+quat_traits<B>::template read_element<1>(b));
0684 write_quat_element<2>(a,quat_traits<A>::template read_element<2>(a)+quat_traits<B>::template read_element<2>(b));
0685 write_quat_element<3>(a,quat_traits<A>::template read_element<3>(a)+quat_traits<B>::template read_element<3>(b));
0686 return a;
0687 }
0688
0689 template <class A,class B>
0690 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0691 typename lazy_enable_if_c<
0692 is_quat<A>::value && is_quat<B>::value,
0693 deduce_quat2<A,B> >::type
0694 operator+( A const & a, B const & b )
0695 {
0696 typedef typename deduce_quat2<A,B>::type R;
0697 R r;
0698 write_quat_element<0>(r,quat_traits<A>::template read_element<0>(a)+quat_traits<B>::template read_element<0>(b));
0699 write_quat_element<1>(r,quat_traits<A>::template read_element<1>(a)+quat_traits<B>::template read_element<1>(b));
0700 write_quat_element<2>(r,quat_traits<A>::template read_element<2>(a)+quat_traits<B>::template read_element<2>(b));
0701 write_quat_element<3>(r,quat_traits<A>::template read_element<3>(a)+quat_traits<B>::template read_element<3>(b));
0702 return r;
0703 }
0704
0705 template <class A,class B,class C>
0706 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0707 typename lazy_enable_if_c<
0708 is_quat<A>::value && is_quat<B>::value && is_scalar<C>::value,
0709 deduce_quat2<A,B> >::type
0710 slerp360( A const & a, B const & b, C t )
0711 {
0712 typedef typename deduce_quat2<A,B>::type R;
0713 typedef typename quat_traits<R>::scalar_type TR;
0714 TR const one = scalar_traits<TR>::value(1);
0715 TR const threshold = one - one / scalar_traits<TR>::value(2000);
0716 TR const dp = dot(a,b);
0717 TR const abs_dp = abs(dp);
0718 if( abs_dp > threshold )
0719 return a*(one-t) + b*t;
0720 TR const th = acos(dp);
0721 TR const invsinth = one / sin(th);
0722 return a * (sin(th * (one-t)) * invsinth) + b * (sin(th * t) * invsinth);
0723 }
0724
0725 template <class A,class B,class C>
0726 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0727 typename lazy_enable_if_c<
0728 is_quat<A>::value && is_quat<B>::value && is_scalar<C>::value,
0729 deduce_quat2<A,B> >::type
0730 slerp180( A const & a, B const & b, C t )
0731 {
0732 typedef typename deduce_quat2<A,B>::type R;
0733 typedef typename quat_traits<R>::scalar_type TR;
0734 TR const one = scalar_traits<TR>::value(1);
0735 TR const threshold = one - one / scalar_traits<TR>::value(2000);
0736 TR const dp = dot(a,b);
0737 TR const abs_dp = abs(dp);
0738 if( abs_dp > threshold )
0739 return a*(one-t)*sign(dp) + b*t;
0740 TR const th = acos(abs_dp);
0741 TR const invsinth = one / sin(th);
0742 return a * (sin(th * (one-t)) * invsinth * sign(dp)) + b * (sin(th * t) * invsinth);
0743 }
0744
0745 template <class A,class B,class C>
0746 BOOST_QVM_DEPRECATED("please use slerp180 or slerp360")
0747 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0748 typename lazy_enable_if_c<
0749 is_quat<A>::value && is_quat<B>::value && is_scalar<C>::value,
0750 deduce_quat2<A,B> >::type
0751 slerp( A const & a, B const & b, C t )
0752 {
0753 return slerp360(a, b, t);
0754 }
0755
0756
0757
0758 namespace
0759 qvm_detail
0760 {
0761 template <class T>
0762 class
0763 qref_
0764 {
0765 qref_( qref_ const & );
0766 qref_ & operator=( qref_ const & );
0767 ~qref_();
0768
0769 public:
0770
0771 template <class R>
0772 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
0773 qref_ &
0774 operator=( R const & x )
0775 {
0776 assign(*this,x);
0777 return *this;
0778 }
0779
0780 template <class R
0781 #if __cplusplus >= 201103L
0782 , class = typename enable_if<is_quat<R> >::type
0783 #endif
0784 >
0785 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
0786 operator R() const
0787 {
0788 R r;
0789 assign(r,*this);
0790 return r;
0791 }
0792 };
0793
0794 template <class Q,bool WriteElementRef=quat_write_element_ref<Q>::value>
0795 struct qref_write_traits;
0796
0797 template <class Q>
0798 struct
0799 qref_write_traits<Q,true>
0800 {
0801 typedef typename quat_traits<Q>::scalar_type scalar_type;
0802 typedef qvm_detail::qref_<Q> this_quaternion;
0803
0804 template <int I>
0805 static
0806 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
0807 scalar_type &
0808 write_element( this_quaternion & x )
0809 {
0810 BOOST_QVM_STATIC_ASSERT(I>=0);
0811 BOOST_QVM_STATIC_ASSERT(I<4);
0812 return quat_traits<Q>::template write_element<I>(reinterpret_cast<Q &>(x));
0813 }
0814 };
0815
0816 template <class Q>
0817 struct
0818 qref_write_traits<Q,false>
0819 {
0820 typedef typename quat_traits<Q>::scalar_type scalar_type;
0821 typedef qvm_detail::qref_<Q> this_quaternion;
0822
0823 template <int I>
0824 static
0825 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
0826 void
0827 write_element( this_quaternion & x, scalar_type s )
0828 {
0829 BOOST_QVM_STATIC_ASSERT(I>=0);
0830 BOOST_QVM_STATIC_ASSERT(I<4);
0831 quat_traits<Q>::template write_element<I>(reinterpret_cast<Q &>(x), s);
0832 }
0833 };
0834 }
0835
0836 template <class Q>
0837 struct quat_traits;
0838
0839 template <class Q>
0840 struct
0841 quat_traits< qvm_detail::qref_<Q> >:
0842 qvm_detail::qref_write_traits<Q>
0843 {
0844 typedef typename quat_traits<Q>::scalar_type scalar_type;
0845 typedef qvm_detail::qref_<Q> this_quaternion;
0846
0847 template <int I>
0848 static
0849 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
0850 scalar_type
0851 read_element( this_quaternion const & x )
0852 {
0853 BOOST_QVM_STATIC_ASSERT(I>=0);
0854 BOOST_QVM_STATIC_ASSERT(I<4);
0855 return quat_traits<Q>::template read_element<I>(reinterpret_cast<Q const &>(x));
0856 }
0857 };
0858
0859 template <class Q>
0860 struct
0861 deduce_quat< qvm_detail::qref_<Q> >
0862 {
0863 typedef quat<typename quat_traits<Q>::scalar_type> type;
0864 };
0865
0866 template <class Q>
0867 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
0868 typename enable_if_c<
0869 is_quat<Q>::value,
0870 qvm_detail::qref_<Q> const &>::type
0871 qref( Q const & a )
0872 {
0873 return reinterpret_cast<qvm_detail::qref_<Q> const &>(a);
0874 }
0875
0876 template <class Q>
0877 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
0878 typename enable_if_c<
0879 is_quat<Q>::value,
0880 qvm_detail::qref_<Q> &>::type
0881 qref( Q & a )
0882 {
0883 return reinterpret_cast<qvm_detail::qref_<Q> &>(a);
0884 }
0885
0886
0887
0888 namespace
0889 qvm_detail
0890 {
0891 template <class T>
0892 class
0893 zero_q_
0894 {
0895 zero_q_( zero_q_ const & );
0896 zero_q_ & operator=( zero_q_ const & );
0897 ~zero_q_();
0898
0899 public:
0900
0901 template <class R
0902 #if __cplusplus >= 201103L
0903 , class = typename enable_if<is_quat<R> >::type
0904 #endif
0905 >
0906 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
0907 operator R() const
0908 {
0909 R r;
0910 assign(r,*this);
0911 return r;
0912 }
0913 };
0914 }
0915
0916 template <class T>
0917 struct
0918 quat_traits< qvm_detail::zero_q_<T> >
0919 {
0920 typedef qvm_detail::zero_q_<T> this_quaternion;
0921 typedef T scalar_type;
0922
0923 template <int I>
0924 static
0925 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
0926 scalar_type
0927 read_element( this_quaternion const & )
0928 {
0929 BOOST_QVM_STATIC_ASSERT(I>=0);
0930 BOOST_QVM_STATIC_ASSERT(I<4);
0931 return scalar_traits<scalar_type>::value(0);
0932 }
0933
0934 static
0935 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
0936 scalar_type
0937 read_element_idx( int i, this_quaternion const & )
0938 {
0939 BOOST_QVM_ASSERT(i>=0);
0940 BOOST_QVM_ASSERT(i<4);
0941 return scalar_traits<scalar_type>::value(0);
0942 }
0943 };
0944
0945 template <class T>
0946 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
0947 qvm_detail::zero_q_<T> const &
0948 zero_quat()
0949 {
0950 return *(qvm_detail::zero_q_<T> const *)qvm_detail::get_valid_ptr_quat_operations();
0951 }
0952
0953 template <class A>
0954 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
0955 typename enable_if_c<
0956 is_quat<A>::value,
0957 void>::type
0958 set_zero( A & a )
0959 {
0960 typedef typename quat_traits<A>::scalar_type T;
0961 T const zero=scalar_traits<T>::value(0);
0962 write_quat_element<0>(a,zero);
0963 write_quat_element<1>(a,zero);
0964 write_quat_element<2>(a,zero);
0965 write_quat_element<3>(a,zero);
0966 }
0967
0968
0969
0970 namespace
0971 qvm_detail
0972 {
0973 template <class V>
0974 struct
0975 rot_quat_
0976 {
0977 typedef typename vec_traits<V>::scalar_type scalar_type;
0978 scalar_type a[4];
0979
0980 template <class Angle>
0981 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE
0982 rot_quat_( V const & axis, Angle angle )
0983 {
0984 scalar_type const x=vec_traits<V>::template read_element<0>(axis);
0985 scalar_type const y=vec_traits<V>::template read_element<1>(axis);
0986 scalar_type const z=vec_traits<V>::template read_element<2>(axis);
0987 scalar_type const m2=x*x+y*y+z*z;
0988 if( m2==scalar_traits<scalar_type>::value(0) )
0989 BOOST_QVM_THROW_EXCEPTION(zero_magnitude_error());
0990 scalar_type const rm=scalar_traits<scalar_type>::value(1)/sqrt(m2);
0991 angle/=2;
0992 scalar_type const s=sin(angle);
0993 a[0] = cos(angle);
0994 a[1] = rm*x*s;
0995 a[2] = rm*y*s;
0996 a[3] = rm*z*s;
0997 }
0998
0999 template <class R
1000 #if __cplusplus >= 201103L
1001 , class = typename enable_if<is_quat<R> >::type
1002 #endif
1003 >
1004 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
1005 operator R() const
1006 {
1007 R r;
1008 assign(r,*this);
1009 return r;
1010 }
1011 };
1012 }
1013
1014 template <class V>
1015 struct
1016 quat_traits< qvm_detail::rot_quat_<V> >
1017 {
1018 typedef qvm_detail::rot_quat_<V> this_quaternion;
1019 typedef typename this_quaternion::scalar_type scalar_type;
1020
1021 template <int I>
1022 static
1023 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
1024 scalar_type
1025 read_element( this_quaternion const & x )
1026 {
1027 BOOST_QVM_STATIC_ASSERT(I>=0);
1028 BOOST_QVM_STATIC_ASSERT(I<4);
1029 return x.a[I];
1030 }
1031 };
1032
1033 template <class V>
1034 struct
1035 deduce_quat< qvm_detail::rot_quat_<V> >
1036 {
1037 typedef quat<typename vec_traits<V>::scalar_type> type;
1038 };
1039
1040 template <class A,class Angle>
1041 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE
1042 typename enable_if_c<
1043 is_vec<A>::value && vec_traits<A>::dim==3,
1044 qvm_detail::rot_quat_<A> >::type
1045 rot_quat( A const & axis, Angle angle )
1046 {
1047 return qvm_detail::rot_quat_<A>(axis,angle);
1048 }
1049
1050 template <class A,class B,class Angle>
1051 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
1052 typename enable_if_c<
1053 is_quat<A>::value &&
1054 is_vec<B>::value && vec_traits<B>::dim==3,
1055 void>::type
1056 set_rot( A & a, B const & axis, Angle angle )
1057 {
1058 assign(a,rot_quat(axis,angle));
1059 }
1060
1061 template <class A,class B,class Angle>
1062 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
1063 typename enable_if_c<
1064 is_quat<A>::value &&
1065 is_vec<B>::value && vec_traits<B>::dim==3,
1066 void>::type
1067 rotate( A & a, B const & axis, Angle angle )
1068 {
1069 a *= rot_quat(axis,angle);
1070 }
1071
1072
1073
1074 namespace
1075 qvm_detail
1076 {
1077 template <class T>
1078 struct
1079 rotx_quat_
1080 {
1081 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
1082 rotx_quat_()
1083 {
1084 }
1085
1086 template <class R
1087 #if __cplusplus >= 201103L
1088 , class = typename enable_if<is_quat<R> >::type
1089 #endif
1090 >
1091 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
1092 operator R() const
1093 {
1094 R r;
1095 assign(r,*this);
1096 return r;
1097 }
1098
1099 private:
1100
1101 rotx_quat_( rotx_quat_ const & );
1102 rotx_quat_ & operator=( rotx_quat_ const & );
1103 ~rotx_quat_();
1104 };
1105
1106 template <int I>
1107 struct
1108 rotx_q_get
1109 {
1110 template <class T>
1111 static
1112 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
1113 T
1114 get( T const & )
1115 {
1116 return scalar_traits<T>::value(0);
1117 }
1118 };
1119
1120 template <>
1121 struct
1122 rotx_q_get<1>
1123 {
1124 template <class T>
1125 static
1126 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
1127 T
1128 get( T const & angle )
1129 {
1130 return sin(angle/2);
1131 }
1132 };
1133
1134 template <>
1135 struct
1136 rotx_q_get<0>
1137 {
1138 template <class T>
1139 static
1140 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
1141 T
1142 get( T const & angle )
1143 {
1144 return cos(angle/2);
1145 }
1146 };
1147 }
1148
1149 template <class Angle>
1150 struct
1151 quat_traits< qvm_detail::rotx_quat_<Angle> >
1152 {
1153 typedef qvm_detail::rotx_quat_<Angle> this_quaternion;
1154 typedef Angle scalar_type;
1155
1156 template <int I>
1157 static
1158 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
1159 scalar_type
1160 read_element( this_quaternion const & x )
1161 {
1162 BOOST_QVM_STATIC_ASSERT(I>=0);
1163 BOOST_QVM_STATIC_ASSERT(I<4);
1164 return qvm_detail::rotx_q_get<I>::get(reinterpret_cast<Angle const &>(x));
1165 }
1166 };
1167
1168 template <class Angle>
1169 struct
1170 deduce_quat< qvm_detail::rotx_quat_<Angle> >
1171 {
1172 typedef quat<Angle> type;
1173 };
1174
1175 template <class Angle>
1176 struct
1177 deduce_quat2< qvm_detail::rotx_quat_<Angle>, qvm_detail::rotx_quat_<Angle> >
1178 {
1179 typedef quat<Angle> type;
1180 };
1181
1182 template <class Angle>
1183 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
1184 qvm_detail::rotx_quat_<Angle> const &
1185 rotx_quat( Angle const & angle )
1186 {
1187 return reinterpret_cast<qvm_detail::rotx_quat_<Angle> const &>(angle);
1188 }
1189
1190 template <class A,class Angle>
1191 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
1192 typename enable_if_c<
1193 is_quat<A>::value,
1194 void>::type
1195 set_rotx( A & a, Angle angle )
1196 {
1197 assign(a,rotx_quat(angle));
1198 }
1199
1200 template <class A,class Angle>
1201 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
1202 typename enable_if_c<
1203 is_quat<A>::value,
1204 void>::type
1205 rotate_x( A & a, Angle angle )
1206 {
1207 a *= rotx_quat(angle);
1208 }
1209
1210
1211
1212 namespace
1213 qvm_detail
1214 {
1215 template <class T>
1216 struct
1217 roty_quat_
1218 {
1219 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
1220 roty_quat_()
1221 {
1222 }
1223
1224 template <class R
1225 #if __cplusplus >= 201103L
1226 , class = typename enable_if<is_quat<R> >::type
1227 #endif
1228 >
1229 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
1230 operator R() const
1231 {
1232 R r;
1233 assign(r,*this);
1234 return r;
1235 }
1236
1237 private:
1238
1239 roty_quat_( roty_quat_ const & );
1240 roty_quat_ & operator=( roty_quat_ const & );
1241 ~roty_quat_();
1242 };
1243
1244 template <int I>
1245 struct
1246 roty_q_get
1247 {
1248 template <class T>
1249 static
1250 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
1251 T
1252 get( T const & )
1253 {
1254 return scalar_traits<T>::value(0);
1255 }
1256 };
1257
1258 template <>
1259 struct
1260 roty_q_get<2>
1261 {
1262 template <class T>
1263 static
1264 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
1265 T
1266 get( T const & angle )
1267 {
1268 return sin(angle/2);
1269 }
1270 };
1271
1272 template <>
1273 struct
1274 roty_q_get<0>
1275 {
1276 template <class T>
1277 static
1278 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
1279 T
1280 get( T const & angle )
1281 {
1282 return cos(angle/2);
1283 }
1284 };
1285 }
1286
1287 template <class Angle>
1288 struct
1289 quat_traits< qvm_detail::roty_quat_<Angle> >
1290 {
1291 typedef qvm_detail::roty_quat_<Angle> this_quaternion;
1292 typedef Angle scalar_type;
1293
1294 template <int I>
1295 static
1296 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
1297 scalar_type
1298 read_element( this_quaternion const & x )
1299 {
1300 BOOST_QVM_STATIC_ASSERT(I>=0);
1301 BOOST_QVM_STATIC_ASSERT(I<4);
1302 return qvm_detail::roty_q_get<I>::get(reinterpret_cast<Angle const &>(x));
1303 }
1304 };
1305
1306 template <class Angle>
1307 struct
1308 deduce_quat< qvm_detail::roty_quat_<Angle> >
1309 {
1310 typedef quat<Angle> type;
1311 };
1312
1313 template <class Angle>
1314 struct
1315 deduce_quat2< qvm_detail::roty_quat_<Angle>, qvm_detail::roty_quat_<Angle> >
1316 {
1317 typedef quat<Angle> type;
1318 };
1319
1320 template <class Angle>
1321 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
1322 qvm_detail::roty_quat_<Angle> const &
1323 roty_quat( Angle const & angle )
1324 {
1325 return reinterpret_cast<qvm_detail::roty_quat_<Angle> const &>(angle);
1326 }
1327
1328 template <class A,class Angle>
1329 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
1330 typename enable_if_c<
1331 is_quat<A>::value,
1332 void>::type
1333 set_roty( A & a, Angle angle )
1334 {
1335 assign(a,roty_quat(angle));
1336 }
1337
1338 template <class A,class Angle>
1339 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
1340 typename enable_if_c<
1341 is_quat<A>::value,
1342 void>::type
1343 rotate_y( A & a, Angle angle )
1344 {
1345 a *= roty_quat(angle);
1346 }
1347
1348
1349
1350 namespace
1351 qvm_detail
1352 {
1353 template <class T>
1354 struct
1355 rotz_quat_
1356 {
1357 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
1358 rotz_quat_()
1359 {
1360 }
1361
1362 template <class R
1363 #if __cplusplus >= 201103L
1364 , class = typename enable_if<is_quat<R> >::type
1365 #endif
1366 >
1367 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
1368 operator R() const
1369 {
1370 R r;
1371 assign(r,*this);
1372 return r;
1373 }
1374
1375 private:
1376
1377 rotz_quat_( rotz_quat_ const & );
1378 rotz_quat_ & operator=( rotz_quat_ const & );
1379 ~rotz_quat_();
1380 };
1381
1382 template <int I>
1383 struct
1384 rotz_q_get
1385 {
1386 template <class T>
1387 static
1388 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
1389 T
1390 get( T const & )
1391 {
1392 return scalar_traits<T>::value(0);
1393 }
1394 };
1395
1396 template <>
1397 struct
1398 rotz_q_get<3>
1399 {
1400 template <class T>
1401 static
1402 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
1403 T
1404 get( T const & angle )
1405 {
1406 return sin(angle/2);
1407 }
1408 };
1409
1410 template <>
1411 struct
1412 rotz_q_get<0>
1413 {
1414 template <class T>
1415 static
1416 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
1417 T
1418 get( T const & angle )
1419 {
1420 return cos(angle/2);
1421 }
1422 };
1423 }
1424
1425 template <class Angle>
1426 struct
1427 quat_traits< qvm_detail::rotz_quat_<Angle> >
1428 {
1429 typedef qvm_detail::rotz_quat_<Angle> this_quaternion;
1430 typedef Angle scalar_type;
1431
1432 template <int I>
1433 static
1434 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
1435 scalar_type
1436 read_element( this_quaternion const & x )
1437 {
1438 BOOST_QVM_STATIC_ASSERT(I>=0);
1439 BOOST_QVM_STATIC_ASSERT(I<4);
1440 return qvm_detail::rotz_q_get<I>::get(reinterpret_cast<Angle const &>(x));
1441 }
1442 };
1443
1444 template <class Angle>
1445 struct
1446 deduce_quat< qvm_detail::rotz_quat_<Angle> >
1447 {
1448 typedef quat<Angle> type;
1449 };
1450
1451 template <class Angle>
1452 struct
1453 deduce_quat2< qvm_detail::rotz_quat_<Angle>, qvm_detail::rotz_quat_<Angle> >
1454 {
1455 typedef quat<Angle> type;
1456 };
1457
1458 template <class Angle>
1459 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
1460 qvm_detail::rotz_quat_<Angle> const &
1461 rotz_quat( Angle const & angle )
1462 {
1463 return reinterpret_cast<qvm_detail::rotz_quat_<Angle> const &>(angle);
1464 }
1465
1466 template <class A,class Angle>
1467 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
1468 typename enable_if_c<
1469 is_quat<A>::value,
1470 void>::type
1471 set_rotz( A & a, Angle angle )
1472 {
1473 assign(a,rotz_quat(angle));
1474 }
1475
1476 template <class A,class Angle>
1477 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
1478 typename enable_if_c<
1479 is_quat<A>::value,
1480 void>::type
1481 rotate_z( A & a, Angle angle )
1482 {
1483 a *= rotz_quat(angle);
1484 }
1485
1486 template <class A,class B>
1487 BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
1488 typename enable_if_c<
1489 is_quat<A>::value && is_vec<B>::value && vec_traits<B>::dim==3,
1490 typename quat_traits<A>::scalar_type>::type
1491 axis_angle( A const & a, B & b )
1492 {
1493 typedef typename quat_traits<A>::scalar_type T;
1494 T a0=quat_traits<A>::template read_element<0>(a);
1495 T a1=quat_traits<A>::template read_element<1>(a);
1496 T a2=quat_traits<A>::template read_element<2>(a);
1497 T a3=quat_traits<A>::template read_element<3>(a);
1498 if( a0>1 )
1499 {
1500 T const m2=a0*a0+a1*a1+a2*a2+a3*a3;
1501 if( m2==scalar_traits<T>::value(0) )
1502 BOOST_QVM_THROW_EXCEPTION(zero_magnitude_error());
1503 T const s=sqrt(m2);
1504 a0/=s;
1505 a1/=s;
1506 a2/=s;
1507 a3/=s;
1508 }
1509 if( T s=sqrt(1-a0*a0) )
1510 {
1511 write_vec_element<0>(b, a1/s);
1512 write_vec_element<1>(b, a2/s);
1513 write_vec_element<2>(b, a3/s);
1514 }
1515 else
1516 {
1517 typedef typename vec_traits<B>::scalar_type U;
1518 write_vec_element<0>(b, scalar_traits<U>::value(1));
1519 write_vec_element<1>(b, scalar_traits<U>::value(0));
1520 write_vec_element<2>(b, scalar_traits<U>::value(0));
1521 }
1522 return scalar_traits<T>::value(2) * qvm::acos(a0);
1523 }
1524
1525
1526
1527 namespace
1528 sfinae
1529 {
1530 using ::boost::qvm::assign;
1531 using ::boost::qvm::cmp;
1532 using ::boost::qvm::convert_to;
1533 using ::boost::qvm::conjugate;
1534 using ::boost::qvm::set_identity;
1535 using ::boost::qvm::set_zero;
1536 using ::boost::qvm::scalar_cast;
1537 using ::boost::qvm::operator/=;
1538 using ::boost::qvm::operator/;
1539 using ::boost::qvm::dot;
1540 using ::boost::qvm::operator==;
1541 using ::boost::qvm::inverse;
1542 using ::boost::qvm::mag_sqr;
1543 using ::boost::qvm::mag;
1544 using ::boost::qvm::slerp360;
1545 using ::boost::qvm::slerp180;
1546 using ::boost::qvm::slerp;
1547 using ::boost::qvm::operator-=;
1548 using ::boost::qvm::operator-;
1549 using ::boost::qvm::operator*=;
1550 using ::boost::qvm::operator*;
1551 using ::boost::qvm::operator!=;
1552 using ::boost::qvm::normalized;
1553 using ::boost::qvm::normalize;
1554 using ::boost::qvm::operator+=;
1555 using ::boost::qvm::operator+;
1556 using ::boost::qvm::qref;
1557 using ::boost::qvm::rot_quat;
1558 using ::boost::qvm::set_rot;
1559 using ::boost::qvm::rotate;
1560 using ::boost::qvm::rotx_quat;
1561 using ::boost::qvm::set_rotx;
1562 using ::boost::qvm::rotate_x;
1563 using ::boost::qvm::roty_quat;
1564 using ::boost::qvm::set_roty;
1565 using ::boost::qvm::rotate_y;
1566 using ::boost::qvm::rotz_quat;
1567 using ::boost::qvm::set_rotz;
1568 using ::boost::qvm::rotate_z;
1569 }
1570
1571 } }
1572
1573 #endif