00001
00002
00003
00004
00005
00006
00007
00008
00013 #ifndef quaternion_rotation_h
00014 #define quaternion_rotation_h
00015
00016 #include <cml/mathlib/checking.h>
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 namespace cml {
00030
00032
00034
00036 template < class E, class A, class O, class C > void
00037 quaternion_rotation_world_axis(quaternion<E,A,O,C>& q, size_t axis, E angle)
00038 {
00039 typedef quaternion<E,A,O,C> quaternion_type;
00040 typedef typename quaternion_type::value_type value_type;
00041 typedef typename quaternion_type::order_type order_type;
00042
00043
00044 detail::CheckIndex3(axis);
00045
00046 q.identity();
00047
00048 const size_t W = order_type::W;
00049 const size_t I = order_type::X + axis;
00050
00051 angle *= value_type(.5);
00052 q[I] = std::sin(angle);
00053 q[W] = std::cos(angle);
00054 }
00055
00057 template < class E, class A, class O, class C > void
00058 quaternion_rotation_world_x(quaternion<E,A,O,C>& q, E angle) {
00059 quaternion_rotation_world_axis(q,0,angle);
00060 }
00061
00063 template < class E, class A, class O, class C > void
00064 quaternion_rotation_world_y(quaternion<E,A,O,C>& q, E angle) {
00065 quaternion_rotation_world_axis(q,1,angle);
00066 }
00067
00069 template < class E, class A, class O, class C > void
00070 quaternion_rotation_world_z(quaternion<E,A,O,C>& q, E angle) {
00071 quaternion_rotation_world_axis(q,2,angle);
00072 }
00073
00075
00077
00079 template < class E, class A, class O, class C, class VecT > void
00080 quaternion_rotation_axis_angle(
00081 quaternion<E,A,O,C>& q, const VecT& axis, E angle)
00082 {
00083 typedef quaternion<E,A,O,C> quaternion_type;
00084 typedef typename quaternion_type::value_type value_type;
00085 typedef typename quaternion_type::order_type order_type;
00086
00087
00088 detail::CheckVec3(axis);
00089
00090 enum {
00091 W = order_type::W,
00092 X = order_type::X,
00093 Y = order_type::Y,
00094 Z = order_type::Z
00095 };
00096
00097 angle *= value_type(.5);
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107 q[W] = std::cos(angle);
00108 value_type s = std::sin(angle);
00109 q[X] = axis[0] * s;
00110 q[Y] = axis[1] * s;
00111 q[Z] = axis[2] * s;
00112 }
00113
00115
00117
00119 template < class E, class A, class O, class C, class MatT > void
00120 quaternion_rotation_matrix(quaternion<E,A,O,C>& q, const MatT& m)
00121 {
00122 typedef quaternion<E,A,O,C> quaternion_type;
00123 typedef typename quaternion_type::value_type value_type;
00124 typedef typename quaternion_type::order_type order_type;
00125
00126
00127 detail::CheckMatLinear3D(m);
00128
00129 enum {
00130 W = order_type::W,
00131 X = order_type::X,
00132 Y = order_type::Y,
00133 Z = order_type::Z
00134 };
00135
00136 value_type tr = trace_3x3(m);
00137 if (tr >= value_type(0)) {
00138 q[W] = std::sqrt(tr + value_type(1)) * value_type(.5);
00139 value_type s = value_type(.25) / q[W];
00140 q[X] = (m.basis_element(1,2) - m.basis_element(2,1)) * s;
00141 q[Y] = (m.basis_element(2,0) - m.basis_element(0,2)) * s;
00142 q[Z] = (m.basis_element(0,1) - m.basis_element(1,0)) * s;
00143 } else {
00144 size_t largest_diagonal_element =
00145 index_of_max(
00146 m.basis_element(0,0),
00147 m.basis_element(1,1),
00148 m.basis_element(2,2)
00149 );
00150 size_t i, j, k;
00151 cyclic_permutation(largest_diagonal_element, i, j, k);
00152 const size_t I = X + i;
00153 const size_t J = X + j;
00154 const size_t K = X + k;
00155 q[I] =
00156 std::sqrt(
00157 m.basis_element(i,i) -
00158 m.basis_element(j,j) -
00159 m.basis_element(k,k) +
00160 value_type(1)
00161 ) * value_type(.5);
00162 value_type s = value_type(.25) / q[I];
00163 q[J] = (m.basis_element(i,j) + m.basis_element(j,i)) * s;
00164 q[K] = (m.basis_element(i,k) + m.basis_element(k,i)) * s;
00165 q[W] = (m.basis_element(j,k) - m.basis_element(k,j)) * s;
00166 }
00167 }
00168
00170
00172
00174 template < class E, class A, class O, class C > void
00175 quaternion_rotation_euler(
00176 quaternion<E,A,O,C>& q, E angle_0, E angle_1, E angle_2,
00177 EulerOrder order)
00178 {
00179 typedef quaternion<E,A,O,C> quaternion_type;
00180 typedef typename quaternion_type::value_type value_type;
00181 typedef typename quaternion_type::order_type order_type;
00182
00183 size_t i, j, k;
00184 bool odd, repeat;
00185 detail::unpack_euler_order(order, i, j, k, odd, repeat);
00186
00187 const size_t W = order_type::W;
00188 const size_t I = order_type::X + i;
00189 const size_t J = order_type::X + j;
00190 const size_t K = order_type::X + k;
00191
00192 if (odd) {
00193 angle_1 = -angle_1;
00194 }
00195
00196 angle_0 *= value_type(.5);
00197 angle_1 *= value_type(.5);
00198 angle_2 *= value_type(.5);
00199
00200 value_type s0 = std::sin(angle_0);
00201 value_type c0 = std::cos(angle_0);
00202 value_type s1 = std::sin(angle_1);
00203 value_type c1 = std::cos(angle_1);
00204 value_type s2 = std::sin(angle_2);
00205 value_type c2 = std::cos(angle_2);
00206
00207 value_type s0s2 = s0 * s2;
00208 value_type s0c2 = s0 * c2;
00209 value_type c0s2 = c0 * s2;
00210 value_type c0c2 = c0 * c2;
00211
00212 if (repeat) {
00213 q[I] = c1 * (c0s2 + s0c2);
00214 q[J] = s1 * (c0c2 + s0s2);
00215 q[K] = s1 * (c0s2 - s0c2);
00216 q[W] = c1 * (c0c2 - s0s2);
00217 } else {
00218 q[I] = c1 * s0c2 - s1 * c0s2;
00219 q[J] = c1 * s0s2 + s1 * c0c2;
00220 q[K] = c1 * c0s2 - s1 * s0c2;
00221 q[W] = c1 * c0c2 + s1 * s0s2;
00222 }
00223 if (odd) {
00224 q[J] = -q[J];
00225 }
00226 }
00227
00229
00231
00233 template < typename E,class A,class O,class C,class VecT_1,class VecT_2 > void
00234 quaternion_rotation_align(
00235 quaternion<E,A,O,C>& q,
00236 const VecT_1& align,
00237 const VecT_2& reference,
00238 bool normalize = true,
00239 AxisOrder order = axis_order_zyx)
00240 {
00241 typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type;
00242
00243 matrix_type m;
00244 matrix_rotation_align(m,align,reference,normalize,order);
00245 quaternion_rotation_matrix(q,m);
00246 }
00247
00249 template < typename E, class A, class O, class C, class VecT > void
00250 quaternion_rotation_align(quaternion<E,A,O,C>& q, const VecT& align,
00251 bool normalize = true, AxisOrder order = axis_order_zyx)
00252 {
00253 typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type;
00254
00255 matrix_type m;
00256 matrix_rotation_align(m,align,normalize,order);
00257 quaternion_rotation_matrix(q,m);
00258 }
00259
00261 template < typename E,class A,class O,class C,class VecT_1,class VecT_2 > void
00262 quaternion_rotation_align_axial(quaternion<E,A,O,C>& q, const VecT_1& align,
00263 const VecT_2& axis, bool normalize = true,
00264 AxisOrder order = axis_order_zyx)
00265 {
00266 typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type;
00267
00268 matrix_type m;
00269 matrix_rotation_align_axial(m,align,axis,normalize,order);
00270 quaternion_rotation_matrix(q,m);
00271 }
00272
00274 template < typename E, class A, class O, class C, class MatT > void
00275 quaternion_rotation_align_viewplane(
00276 quaternion<E,A,O,C>& q,
00277 const MatT& view_matrix,
00278 Handedness handedness,
00279 AxisOrder order = axis_order_zyx)
00280 {
00281 typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type;
00282
00283 matrix_type m;
00284 matrix_rotation_align_viewplane(m,view_matrix,handedness,order);
00285 quaternion_rotation_matrix(q,m);
00286 }
00287
00289 template < typename E, class A, class O, class C, class MatT > void
00290 quaternion_rotation_align_viewplane_LH(
00291 quaternion<E,A,O,C>& q,
00292 const MatT& view_matrix,
00293 AxisOrder order = axis_order_zyx)
00294 {
00295 typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type;
00296
00297 matrix_type m;
00298 matrix_rotation_align_viewplane_LH(m,view_matrix,order);
00299 quaternion_rotation_matrix(q,m);
00300 }
00301
00303 template < typename E, class A, class O, class C, class MatT > void
00304 quaternion_rotation_align_viewplane_RH(
00305 quaternion<E,A,O,C>& q,
00306 const MatT& view_matrix,
00307 AxisOrder order = axis_order_zyx)
00308 {
00309 typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type;
00310
00311 matrix_type m;
00312 matrix_rotation_align_viewplane_RH(m,view_matrix,order);
00313 quaternion_rotation_matrix(q,m);
00314 }
00315
00317
00319
00321 template < typename E, class A, class O, class C,
00322 class VecT_1, class VecT_2, class VecT_3 > void
00323 quaternion_rotation_aim_at(
00324 quaternion<E,A,O,C>& q,
00325 const VecT_1& pos,
00326 const VecT_2& target,
00327 const VecT_3& reference,
00328 AxisOrder order = axis_order_zyx)
00329 {
00330 typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type;
00331
00332 matrix_type m;
00333 matrix_rotation_aim_at(m,pos,target,reference,order);
00334 quaternion_rotation_matrix(q,m);
00335 }
00336
00338 template < typename E, class A, class O, class C,
00339 class VecT_1, class VecT_2 > void
00340 quaternion_rotation_aim_at(
00341 quaternion<E,A,O,C>& q,
00342 const VecT_1& pos,
00343 const VecT_2& target,
00344 AxisOrder order = axis_order_zyx)
00345 {
00346 typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type;
00347
00348 matrix_type m;
00349 matrix_rotation_aim_at(m,pos,target,order);
00350 quaternion_rotation_matrix(q,m);
00351 }
00352
00354 template < typename E, class A, class O, class C,
00355 class VecT_1, class VecT_2, class VecT_3 > void
00356 quaternion_rotation_aim_at_axial(
00357 quaternion<E,A,O,C>& q,
00358 const VecT_1& pos,
00359 const VecT_2& target,
00360 const VecT_3& axis,
00361 AxisOrder order = axis_order_zyx)
00362 {
00363 typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type;
00364
00365 matrix_type m;
00366 matrix_rotation_aim_at_axial(m,pos,target,axis,order);
00367 quaternion_rotation_matrix(q,m);
00368 }
00369
00371
00373
00374
00375 template < class E, class A, class O, class C > void
00376 quaternion_rotate_about_world_axis(quaternion<E,A,O,C>& q,size_t axis,E angle)
00377 {
00378 typedef quaternion<E,A,O,C> quaternion_type;
00379 typedef typename quaternion_type::value_type value_type;
00380 typedef typename quaternion_type::order_type order_type;
00381
00382
00383 detail::CheckIndex3(axis);
00384
00385 size_t i, j, k;
00386 cyclic_permutation(axis, i, j, k);
00387
00388 const size_t W = order_type::W;
00389 const size_t I = order_type::X + i;
00390 const size_t J = order_type::X + j;
00391 const size_t K = order_type::X + k;
00392
00393 angle *= value_type(.5);
00394 value_type s = value_type(std::sin(angle));
00395 value_type c = value_type(std::cos(angle));
00396
00397 quaternion_type result;
00398 result[I] = c * q[I] + s * q[W];
00399 result[J] = c * q[J] - s * q[K];
00400 result[K] = c * q[K] + s * q[J];
00401 result[W] = c * q[W] - s * q[I];
00402 q = result;
00403 }
00404
00405
00406 template < class E, class A, class O, class C > void
00407 quaternion_rotate_about_world_x(quaternion<E,A,O,C>& q, E angle) {
00408 quaternion_rotate_about_world_axis(q,0,angle);
00409 }
00410
00411
00412 template < class E, class A, class O, class C > void
00413 quaternion_rotate_about_world_y(quaternion<E,A,O,C>& q, E angle) {
00414 quaternion_rotate_about_world_axis(q,1,angle);
00415 }
00416
00417
00418 template < class E, class A, class O, class C > void
00419 quaternion_rotate_about_world_z(quaternion<E,A,O,C>& q, E angle) {
00420 quaternion_rotate_about_world_axis(q,2,angle);
00421 }
00422
00424
00426
00427
00428 template < class E, class A, class O, class C > void
00429 quaternion_rotate_about_local_axis(quaternion<E,A,O,C>& q,size_t axis,E angle)
00430 {
00431 typedef quaternion<E,A,O,C> quaternion_type;
00432 typedef typename quaternion_type::value_type value_type;
00433 typedef typename quaternion_type::order_type order_type;
00434
00435
00436 detail::CheckIndex3(axis);
00437
00438 size_t i, j, k;
00439 cyclic_permutation(axis, i, j, k);
00440
00441 const size_t W = order_type::W;
00442 const size_t I = order_type::X + i;
00443 const size_t J = order_type::X + j;
00444 const size_t K = order_type::X + k;
00445
00446 angle *= value_type(.5);
00447 value_type s = value_type(std::sin(angle));
00448 value_type c = value_type(std::cos(angle));
00449
00450 quaternion_type result;
00451 result[I] = c * q[I] + s * q[W];
00452 result[J] = c * q[J] + s * q[K];
00453 result[K] = c * q[K] - s * q[J];
00454 result[W] = c * q[W] - s * q[I];
00455 q = result;
00456 }
00457
00458
00459 template < class E, class A, class O, class C > void
00460 quaternion_rotate_about_local_x(quaternion<E,A,O,C>& q, E angle) {
00461 quaternion_rotate_about_local_axis(q,0,angle);
00462 }
00463
00464
00465 template < class E, class A, class O, class C > void
00466 quaternion_rotate_about_local_y(quaternion<E,A,O,C>& q, E angle) {
00467 quaternion_rotate_about_local_axis(q,1,angle);
00468 }
00469
00470
00471 template < class E, class A, class O, class C > void
00472 quaternion_rotate_about_local_z(quaternion<E,A,O,C>& q, E angle) {
00473 quaternion_rotate_about_local_axis(q,2,angle);
00474 }
00475
00477
00479
00480
00481
00483 template < class E,class A,class O,class C,class VecT_1,class VecT_2 > void
00484 quaternion_rotation_vec_to_vec(
00485 quaternion<E,A,O,C>& q,
00486 const VecT_1& v1,
00487 const VecT_2& v2,
00488 bool unit_length_vectors = false)
00489 {
00490 typedef quaternion<E,A,O,C> quaternion_type;
00491 typedef typename quaternion_type::value_type value_type;
00492 typedef vector< value_type, fixed<3> > vector_type;
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506 vector_type c = cross(v1,v2);
00507 if (unit_length_vectors) {
00508 q = quaternion_type(value_type(1) + dot(v1,v2), c.data());
00509 } else {
00510 q = quaternion_type(
00511 std::sqrt(v1.length_squared() * v2.length_squared()) + dot(v1,v2),
00512 c
00513 );
00514 }
00515 q.normalize();
00516 }
00517
00519
00521
00522 template < typename E, class A, class O, class C > void
00523 quaternion_scale_angle(quaternion<E,A,O,C>& q, E t,
00524 E tolerance = epsilon<E>::placeholder())
00525 {
00526 typedef vector< E,fixed<3> > vector_type;
00527 typedef typename vector_type::value_type value_type;
00528
00529 vector_type axis;
00530 value_type angle;
00531 quaternion_to_axis_angle(q, axis, angle, tolerance);
00532 quaternion_rotation_axis_angle(q, axis, angle * t);
00533 }
00534
00536
00538
00539 namespace detail {
00540
00542 template < class QuatT_1, class QuatT_2 >
00543 typename et::QuaternionPromote2<QuatT_1,QuatT_2>::temporary_type
00544 quaternion_rotation_difference(
00545 const QuatT_1& q1, const QuatT_2& q2, positive_cross)
00546 {
00547 return q2 * conjugate(q1);
00548 }
00549
00551 template < class QuatT_1, class QuatT_2 >
00552 typename et::QuaternionPromote2<QuatT_1,QuatT_2>::temporary_type
00553 quaternion_rotation_difference(
00554 const QuatT_1& q1, const QuatT_2& q2, negative_cross)
00555 {
00556 return conjugate(q1) * q2;
00557 }
00558
00559 }
00560
00562
00564
00566 template < class QuatT_1, class QuatT_2 >
00567 typename et::QuaternionPromote2<QuatT_1,QuatT_2>::temporary_type
00568 quaternion_rotation_difference(const QuatT_1& q1, const QuatT_2& q2) {
00569 return detail::quaternion_rotation_difference(
00570 q1, q2, typename QuatT_1::cross_type());
00571 }
00572
00574
00576
00578 template < class QuatT, typename E, class A > void
00579 quaternion_to_axis_angle(
00580 const QuatT& q,
00581 vector<E,A>& axis,
00582 E& angle,
00583 E tolerance = epsilon<E>::placeholder())
00584 {
00585 typedef QuatT quaternion_type;
00586 typedef typename quaternion_type::value_type value_type;
00587 typedef typename quaternion_type::order_type order_type;
00588
00589
00590 detail::CheckQuat(q);
00591
00592 axis = q.imaginary();
00593 value_type l = length(axis);
00594 if (l > tolerance) {
00595 axis /= l;
00596 angle = value_type(2) * std::atan2(l,q.real());
00597 } else {
00598 axis.zero();
00599 angle = value_type(0);
00600 }
00601 }
00602
00615 template < class QuatT, typename Real > void
00616 quaternion_to_euler(
00617 const QuatT& q,
00618 Real& angle_0,
00619 Real& angle_1,
00620 Real& angle_2,
00621 EulerOrder order,
00622 Real tolerance = epsilon<Real>::placeholder())
00623 {
00624 typedef QuatT quaternion_type;
00625 typedef typename quaternion_type::value_type value_type;
00626 typedef matrix< value_type,fixed<3,3>,row_basis,row_major > matrix_type;
00627
00628 matrix_type m;
00629 matrix_rotation_quaternion(m, q);
00630 matrix_to_euler(m, angle_0, angle_1, angle_2, order, tolerance);
00631 }
00632
00633 }
00634
00635 #endif