matrix_rotation.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  *-----------------------------------------------------------------------*/
00013 #ifndef matrix_rotation_h
00014 #define matrix_rotation_h
00015 
00016 #include <cml/mathlib/matrix_misc.h>
00017 #include <cml/mathlib/vector_ortho.h>
00018 
00019 /* Functions related to matrix rotations in 3D and 2D. */
00020 
00021 namespace cml {
00022 
00024 // 3D rotation about world axes
00026 
00028 template < typename E, class A, class B, class L > void
00029 matrix_rotation_world_axis( matrix<E,A,B,L>& m, size_t axis, E angle)
00030 {
00031     typedef matrix<E,A,B,L> matrix_type;
00032     typedef typename matrix_type::value_type value_type;
00033 
00034     /* Checking */
00035     detail::CheckMatLinear3D(m);
00036     detail::CheckIndex3(axis);
00037 
00038     size_t i, j, k;
00039     cyclic_permutation(axis, i, j, k);
00040     
00041     value_type s = value_type(std::sin(angle));
00042     value_type c = value_type(std::cos(angle));
00043     
00044     identity_transform(m);
00045 
00046     m.set_basis_element(j,j, c);
00047     m.set_basis_element(j,k, s);
00048     m.set_basis_element(k,j,-s);
00049     m.set_basis_element(k,k, c);
00050 }
00051 
00053 template < typename E, class A, class B, class L > void
00054 matrix_rotation_world_x(matrix<E,A,B,L>& m, E angle) {
00055     matrix_rotation_world_axis(m,0,angle);
00056 }
00057 
00059 template < typename E, class A, class B, class L > void
00060 matrix_rotation_world_y(matrix<E,A,B,L>& m, E angle) {
00061     matrix_rotation_world_axis(m,1,angle);
00062 }
00063 
00065 template < typename E, class A, class B, class L > void
00066 matrix_rotation_world_z(matrix<E,A,B,L>& m, E angle) {
00067     matrix_rotation_world_axis(m,2,angle);
00068 }
00069 
00071 // 3D rotation from an axis-angle pair
00073 
00075 template < typename E, class A, class B, class L, class VecT > void
00076 matrix_rotation_axis_angle(matrix<E,A,B,L>& m, const VecT& axis, E angle)
00077 {
00078     typedef matrix<E,A,B,L> matrix_type;
00079     typedef typename matrix_type::value_type value_type;
00080 
00081     /* Checking */
00082     detail::CheckMatLinear3D(m);
00083     detail::CheckVec3(axis);
00084     
00085     identity_transform(m);
00086 
00087     value_type s = std::sin(angle);
00088     value_type c = std::cos(angle);
00089     value_type omc = value_type(1) - c;
00090 
00091     value_type xomc = axis[0] * omc;
00092     value_type yomc = axis[1] * omc;
00093     value_type zomc = axis[2] * omc;
00094     
00095     value_type xxomc = axis[0] * xomc;
00096     value_type yyomc = axis[1] * yomc;
00097     value_type zzomc = axis[2] * zomc;
00098     value_type xyomc = axis[0] * yomc;
00099     value_type yzomc = axis[1] * zomc;
00100     value_type zxomc = axis[2] * xomc;
00101 
00102     value_type xs = axis[0] * s;
00103     value_type ys = axis[1] * s;
00104     value_type zs = axis[2] * s;
00105 
00106     m.set_basis_element(0,0, xxomc + c );
00107     m.set_basis_element(0,1, xyomc + zs);
00108     m.set_basis_element(0,2, zxomc - ys);
00109     m.set_basis_element(1,0, xyomc - zs);
00110     m.set_basis_element(1,1, yyomc + c );
00111     m.set_basis_element(1,2, yzomc + xs);
00112     m.set_basis_element(2,0, zxomc + ys);
00113     m.set_basis_element(2,1, yzomc - xs);
00114     m.set_basis_element(2,2, zzomc + c );
00115 }
00116 
00118 // 3D rotation from a quaternion
00120 
00122 template < typename E, class A, class B, class L, class QuatT > void
00123 matrix_rotation_quaternion(matrix<E,A,B,L>& m, const QuatT& q)
00124 {
00125     typedef matrix<E,A,B,L> matrix_type;
00126     typedef QuatT quaternion_type;
00127     typedef typename quaternion_type::order_type order_type;
00128     typedef typename matrix_type::value_type value_type;
00129 
00130     enum {
00131         W = order_type::W,
00132         X = order_type::X,
00133         Y = order_type::Y,
00134         Z = order_type::Z
00135     };
00136     
00137     /* Checking */
00138     detail::CheckMatLinear3D(m);
00139     detail::CheckQuat(q);
00140 
00141     identity_transform(m);
00142     
00143     value_type x2 = q[X] + q[X];
00144     value_type y2 = q[Y] + q[Y];
00145     value_type z2 = q[Z] + q[Z];    
00146 
00147     value_type xx2 = q[X] * x2;
00148     value_type yy2 = q[Y] * y2;
00149     value_type zz2 = q[Z] * z2;
00150     value_type xy2 = q[X] * y2;
00151     value_type yz2 = q[Y] * z2;
00152     value_type zx2 = q[Z] * x2;
00153     value_type xw2 = q[W] * x2;
00154     value_type yw2 = q[W] * y2;
00155     value_type zw2 = q[W] * z2;
00156     
00157     m.set_basis_element(0,0, value_type(1) - yy2 - zz2);
00158     m.set_basis_element(0,1,                 xy2 + zw2);
00159     m.set_basis_element(0,2,                 zx2 - yw2);
00160     m.set_basis_element(1,0,                 xy2 - zw2);
00161     m.set_basis_element(1,1, value_type(1) - zz2 - xx2);
00162     m.set_basis_element(1,2,                 yz2 + xw2);
00163     m.set_basis_element(2,0,                 zx2 + yw2);
00164     m.set_basis_element(2,1,                 yz2 - xw2);
00165     m.set_basis_element(2,2, value_type(1) - xx2 - yy2);
00166 }
00167 
00169 // 3D rotation from Euler angles
00171 
00194 template < typename E, class A, class B, class L > void
00195 matrix_rotation_euler(matrix<E,A,B,L>& m, E angle_0, E angle_1, E angle_2,
00196     EulerOrder order)
00197 {
00198     typedef matrix<E,A,B,L> matrix_type;
00199     typedef typename matrix_type::value_type value_type;
00200 
00201     /* Checking */
00202     detail::CheckMatLinear3D(m);
00203 
00204     identity_transform(m);
00205     
00206     size_t i, j, k;
00207     bool odd, repeat;
00208     detail::unpack_euler_order(order, i, j, k, odd, repeat);
00209 
00210     if (odd) {
00211         angle_0 = -angle_0;
00212         angle_1 = -angle_1;
00213         angle_2 = -angle_2;
00214     }
00215     
00216     value_type s0 = std::sin(angle_0);
00217     value_type c0 = std::cos(angle_0);
00218     value_type s1 = std::sin(angle_1);
00219     value_type c1 = std::cos(angle_1);
00220     value_type s2 = std::sin(angle_2);
00221     value_type c2 = std::cos(angle_2);
00222     
00223     value_type s0s2 = s0 * s2;
00224     value_type s0c2 = s0 * c2;
00225     value_type c0s2 = c0 * s2;
00226     value_type c0c2 = c0 * c2;
00227 
00228     if (repeat) {
00229         m.set_basis_element(i,i, c1              );
00230         m.set_basis_element(i,j, s1 * s2         );
00231         m.set_basis_element(i,k,-s1 * c2         );
00232         m.set_basis_element(j,i, s0 * s1         );
00233         m.set_basis_element(j,j,-c1 * s0s2 + c0c2);
00234         m.set_basis_element(j,k, c1 * s0c2 + c0s2);
00235         m.set_basis_element(k,i, c0 * s1         );
00236         m.set_basis_element(k,j,-c1 * c0s2 - s0c2);
00237         m.set_basis_element(k,k, c1 * c0c2 - s0s2);
00238     } else {
00239         m.set_basis_element(i,i, c1 * c2         );
00240         m.set_basis_element(i,j, c1 * s2         );
00241         m.set_basis_element(i,k,-s1              );
00242         m.set_basis_element(j,i, s1 * s0c2 - c0s2);
00243         m.set_basis_element(j,j, s1 * s0s2 + c0c2);
00244         m.set_basis_element(j,k, s0 * c1         );
00245         m.set_basis_element(k,i, s1 * c0c2 + s0s2);
00246         m.set_basis_element(k,j, s1 * c0s2 - s0c2);
00247         m.set_basis_element(k,k, c0 * c1         );
00248     }
00249 }
00250 
00273 template < typename E, class A, class B, class L > void
00274 matrix_rotation_euler_derivatives(
00275     matrix<E,A,B,L>& m, int axis, E angle_0, E angle_1, E angle_2,
00276     EulerOrder order)
00277 {
00278     typedef matrix<E,A,B,L> matrix_type;
00279     typedef typename matrix_type::value_type value_type;
00280 
00281     /* Checking */
00282     detail::CheckMatLinear3D(m);
00283 
00284     identity_transform(m);
00285     
00286     size_t i, j, k;
00287     bool odd, repeat;
00288     detail::unpack_euler_order(order, i, j, k, odd, repeat);
00289     if(repeat) throw std::invalid_argument(
00290     "matrix_rotation_euler_derivatives does not support repeated axes");
00291 
00292     if (odd) {
00293         angle_0 = -angle_0;
00294         angle_1 = -angle_1;
00295         angle_2 = -angle_2;
00296     }
00297 
00298     value_type s0 = std::sin(angle_0);
00299     value_type c0 = std::cos(angle_0);
00300     value_type s1 = std::sin(angle_1);
00301     value_type c1 = std::cos(angle_1);
00302     value_type s2 = std::sin(angle_2);
00303     value_type c2 = std::cos(angle_2);
00304     
00305     value_type s0s2 = s0 * s2;
00306     value_type s0c2 = s0 * c2;
00307     value_type c0s2 = c0 * s2;
00308     value_type c0c2 = c0 * c2;
00309 
00310     if(axis == 0) {
00311       m.set_basis_element(i,i, 0.              );
00312       m.set_basis_element(i,j, 0.              );
00313       m.set_basis_element(i,k, 0.              );
00314       m.set_basis_element(j,i, s1 * c0*c2 + s0*s2);
00315       m.set_basis_element(j,j, s1 * c0*s2 - s0*c2);
00316       m.set_basis_element(j,k, c0 * c1         );
00317       m.set_basis_element(k,i,-s1 * s0*c2 + c0*s2);
00318       m.set_basis_element(k,j,-s1 * s0*s2 - c0*c2);
00319       m.set_basis_element(k,k,-s0 * c1         );
00320     } else if(axis == 1) {
00321       m.set_basis_element(i,i,-s1 * c2         );
00322       m.set_basis_element(i,j,-s1 * s2         );
00323       m.set_basis_element(i,k,-c1              );
00324       m.set_basis_element(j,i, c1 * s0*c2      );
00325       m.set_basis_element(j,j, c1 * s0*s2      );
00326       m.set_basis_element(j,k,-s0 * s1         );
00327       m.set_basis_element(k,i, c1 * c0*c2      );
00328       m.set_basis_element(k,j, c1 * c0*s2      );
00329       m.set_basis_element(k,k,-c0 * s1         );
00330     } else if(axis == 2) {
00331       m.set_basis_element(i,i,-c1 * s2         );
00332       m.set_basis_element(i,j, c1 * c2         );
00333       m.set_basis_element(i,k, 0.              );
00334       m.set_basis_element(j,i,-s1 * s0*s2 - c0*c2);
00335       m.set_basis_element(j,j, s1 * s0*c2 - c0*s2);
00336       m.set_basis_element(j,k, 0.              );
00337       m.set_basis_element(k,i,-s1 * c0*s2 + s0*c2);
00338       m.set_basis_element(k,j, s1 * c0*c2 + s0*s2);
00339       m.set_basis_element(k,k, 0.              );
00340     }
00341 }
00342 
00344 // 3D rotation to align with a vector, multiple vectors, or the view plane
00346 
00348 template < typename E,class A,class B,class L,class VecT_1,class VecT_2 > void
00349 matrix_rotation_align(
00350     matrix<E,A,B,L>& m,
00351     const VecT_1& align,
00352     const VecT_2& reference,
00353     bool normalize = true,
00354     AxisOrder order = axis_order_zyx)
00355 {
00356     typedef vector< E,fixed<3> > vector_type;
00357 
00358     identity_transform(m);
00359     
00360     vector_type x, y, z;
00361 
00362     orthonormal_basis(align, reference, x, y, z, normalize, order);
00363     matrix_set_basis_vectors(m, x, y, z);
00364 }
00365 
00367 template < typename E, class A, class B, class L, class VecT > void
00368 matrix_rotation_align(matrix<E,A,B,L>& m, const VecT& align,
00369     bool normalize = true, AxisOrder order = axis_order_zyx)
00370 {
00371     typedef vector< E,fixed<3> > vector_type;
00372 
00373     identity_transform(m);
00374     
00375     vector_type x, y, z;
00376 
00377     orthonormal_basis(align, x, y, z, normalize, order);
00378     matrix_set_basis_vectors(m, x, y, z);
00379 }
00380 
00382 template < typename E,class A,class B,class L,class VecT_1,class VecT_2 > void
00383 matrix_rotation_align_axial(matrix<E,A,B,L>& m, const VecT_1& align,
00384     const VecT_2& axis, bool normalize = true,
00385     AxisOrder order = axis_order_zyx)
00386 {
00387     typedef vector< E,fixed<3> > vector_type;
00388 
00389     identity_transform(m);
00390     
00391     vector_type x, y, z;
00392 
00393     orthonormal_basis_axial(align, axis, x, y, z, normalize, order);
00394     matrix_set_basis_vectors(m, x, y, z);
00395 }
00396 
00398 template < typename E, class A, class B, class L, class MatT > void
00399 matrix_rotation_align_viewplane(
00400     matrix<E,A,B,L>& m,
00401     const MatT& view_matrix,
00402     Handedness handedness,
00403     AxisOrder order = axis_order_zyx)
00404 {
00405     typedef vector< E, fixed<3> > vector_type;
00406 
00407     identity_transform(m);
00408     
00409     vector_type x, y, z;
00410 
00411     orthonormal_basis_viewplane(view_matrix, x, y, z, handedness, order);
00412     matrix_set_basis_vectors(m, x, y, z);
00413 }
00414 
00416 template < typename E, class A, class B, class L, class MatT > void
00417 matrix_rotation_align_viewplane_LH(
00418     matrix<E,A,B,L>& m,
00419     const MatT& view_matrix,
00420     AxisOrder order = axis_order_zyx)
00421 {
00422     matrix_rotation_align_viewplane(
00423         m,view_matrix,left_handed,order);
00424 }
00425 
00427 template < typename E, class A, class B, class L, class MatT > void
00428 matrix_rotation_align_viewplane_RH(
00429     matrix<E,A,B,L>& m,
00430     const MatT& view_matrix,
00431     AxisOrder order = axis_order_zyx)
00432 {
00433     matrix_rotation_align_viewplane(
00434         m,view_matrix,right_handed,order);
00435 }
00436 
00438 // 3D rotation to aim at a target
00440 
00442 template < typename E, class A, class B, class L,
00443     class VecT_1, class VecT_2, class VecT_3 > void
00444 matrix_rotation_aim_at(
00445     matrix<E,A,B,L>& m,
00446     const VecT_1& pos,
00447     const VecT_2& target,
00448     const VecT_3& reference,
00449     AxisOrder order = axis_order_zyx)
00450 {
00451     matrix_rotation_align(m, target - pos, reference, true, order);
00452 }
00453 
00455 template < typename E, class A, class B, class L,
00456     class VecT_1, class VecT_2 > void
00457 matrix_rotation_aim_at(
00458     matrix<E,A,B,L>& m,
00459     const VecT_1& pos,
00460     const VecT_2& target,
00461     AxisOrder order = axis_order_zyx)
00462 {
00463     matrix_rotation_align(m, target - pos, true, order);
00464 }
00465 
00467 template < typename E, class A, class B, class L,
00468     class VecT_1, class VecT_2, class VecT_3 > void
00469 matrix_rotation_aim_at_axial(
00470     matrix<E,A,B,L>& m,
00471     const VecT_1& pos,
00472     const VecT_2& target,
00473     const VecT_3& axis,
00474     AxisOrder order = axis_order_zyx)
00475 {
00476     matrix_rotation_align_axial(m, target - pos, axis, true, order);
00477 }
00478 
00480 // 2D rotation
00482 
00484 template < typename E, class A, class B, class L > void
00485 matrix_rotation_2D( matrix<E,A,B,L>& m, E angle)
00486 {
00487     typedef matrix<E,A,B,L> matrix_type;
00488     typedef typename matrix_type::value_type value_type;
00489 
00490     /* Checking */
00491     detail::CheckMatLinear2D(m);
00492 
00493     value_type s = value_type(std::sin(angle));
00494     value_type c = value_type(std::cos(angle));
00495     
00496     identity_transform(m);
00497 
00498     m.set_basis_element(0,0, c);
00499     m.set_basis_element(0,1, s);
00500     m.set_basis_element(1,0,-s);
00501     m.set_basis_element(1,1, c);
00502 }
00503 
00505 // 2D rotation to align with a vector
00507 
00509 template < typename E, class A, class B, class L, class VecT > void
00510 matrix_rotation_align_2D(matrix<E,A,B,L>& m, const VecT& align,
00511     bool normalize = true, AxisOrder2D order = axis_order_xy)
00512 {
00513     typedef vector< E, fixed<2> > vector_type;
00514 
00515     identity_transform(m);
00516     
00517     vector_type x, y;
00518 
00519     orthonormal_basis_2D(align, x, y, normalize, order);
00520     matrix_set_basis_vectors_2D(m, x, y);
00521 }
00522 
00524 // 3D relative rotation about world axes
00526 
00528 template < typename E, class A, class B, class L > void
00529 matrix_rotate_about_world_axis(matrix<E,A,B,L>& m, size_t axis, E angle)
00530 {
00531     typedef matrix<E,A,B,L> matrix_type;
00532     typedef typename matrix_type::value_type value_type;
00533 
00534     /* Checking */
00535     detail::CheckMatLinear3D(m);
00536     detail::CheckIndex3(axis);
00537 
00538     size_t i, j, k;
00539     cyclic_permutation(axis, i, j, k);
00540 
00541     value_type s = value_type(std::sin(angle));
00542     value_type c = value_type(std::cos(angle));
00543 
00544     value_type ij = c * m.basis_element(i,j) - s * m.basis_element(i,k);
00545     value_type jj = c * m.basis_element(j,j) - s * m.basis_element(j,k);
00546     value_type kj = c * m.basis_element(k,j) - s * m.basis_element(k,k);
00547     
00548     m.set_basis_element(i,k, s*m.basis_element(i,j) + c*m.basis_element(i,k));
00549     m.set_basis_element(j,k, s*m.basis_element(j,j) + c*m.basis_element(j,k));
00550     m.set_basis_element(k,k, s*m.basis_element(k,j) + c*m.basis_element(k,k));
00551     
00552     m.set_basis_element(i,j,ij);
00553     m.set_basis_element(j,j,jj);
00554     m.set_basis_element(k,j,kj);
00555 }
00556 
00558 template < typename E, class A, class B, class L > void
00559 matrix_rotate_about_world_x(matrix<E,A,B,L>& m, E angle) {
00560     matrix_rotate_about_world_axis(m,0,angle);
00561 }
00562 
00564 template < typename E, class A, class B, class L > void
00565 matrix_rotate_about_world_y(matrix<E,A,B,L>& m, E angle) {
00566     matrix_rotate_about_world_axis(m,1,angle);
00567 }
00568 
00570 template < typename E, class A, class B, class L > void
00571 matrix_rotate_about_world_z(matrix<E,A,B,L>& m, E angle) {
00572     matrix_rotate_about_world_axis(m,2,angle);
00573 }
00574 
00576 // 3D relative rotation about local axes
00578 
00580 template < typename E, class A, class B, class L > void
00581 matrix_rotate_about_local_axis(matrix<E,A,B,L>& m, size_t axis, E angle)
00582 {
00583     typedef matrix<E,A,B,L> matrix_type;
00584     typedef typename matrix_type::value_type value_type;
00585 
00586     /* Checking */
00587     detail::CheckMatLinear3D(m);
00588     detail::CheckIndex3(axis);
00589 
00590     size_t i, j, k;
00591     cyclic_permutation(axis, i, j, k);
00592 
00593     value_type s = value_type(std::sin(angle));
00594     value_type c = value_type(std::cos(angle));
00595 
00596     value_type j0 = c * m.basis_element(j,0) + s * m.basis_element(k,0);
00597     value_type j1 = c * m.basis_element(j,1) + s * m.basis_element(k,1);
00598     value_type j2 = c * m.basis_element(j,2) + s * m.basis_element(k,2);
00599 
00600     m.set_basis_element(k,0, c*m.basis_element(k,0) - s*m.basis_element(j,0));
00601     m.set_basis_element(k,1, c*m.basis_element(k,1) - s*m.basis_element(j,1));
00602     m.set_basis_element(k,2, c*m.basis_element(k,2) - s*m.basis_element(j,2));
00603 
00604     m.set_basis_element(j,0,j0);
00605     m.set_basis_element(j,1,j1);
00606     m.set_basis_element(j,2,j2);
00607 }
00608 
00610 template < typename E, class A, class B, class L > void
00611 matrix_rotate_about_local_x(matrix<E,A,B,L>& m, E angle) {
00612     matrix_rotate_about_local_axis(m,0,angle);
00613 }
00614 
00616 template < typename E, class A, class B, class L > void
00617 matrix_rotate_about_local_y(matrix<E,A,B,L>& m, E angle) {
00618     matrix_rotate_about_local_axis(m,1,angle);
00619 }
00620 
00622 template < typename E, class A, class B, class L > void
00623 matrix_rotate_about_local_z(matrix<E,A,B,L>& m, E angle) {
00624     matrix_rotate_about_local_axis(m,2,angle);
00625 }
00626 
00628 // 2D relative rotation
00630 
00631 template < typename E, class A, class B, class L > void
00632 matrix_rotate_2D(matrix<E,A,B,L>& m, E angle)
00633 {
00634     typedef matrix<E,A,B,L> matrix_type;
00635     typedef typename matrix_type::value_type value_type;
00636 
00637     /* Checking */
00638     detail::CheckMatLinear2D(m);
00639 
00640     value_type s = value_type(std::sin(angle));
00641     value_type c = value_type(std::cos(angle));
00642 
00643     value_type m00 = c * m.basis_element(0,0) - s * m.basis_element(0,1);
00644     value_type m10 = c * m.basis_element(1,0) - s * m.basis_element(1,1);
00645 
00646     m.set_basis_element(0,1, s*m.basis_element(0,0) + c*m.basis_element(0,1));
00647     m.set_basis_element(1,1, s*m.basis_element(1,0) + c*m.basis_element(1,1));
00648 
00649     m.set_basis_element(0,0,m00);
00650     m.set_basis_element(1,0,m10);
00651 }
00652 
00654 // Rotation from vector to vector
00656 
00662 template < class E,class A,class B,class L,class VecT_1,class VecT_2 > void
00663 matrix_rotation_vec_to_vec(
00664     matrix<E,A,B,L>& m,
00665     const VecT_1& v1,
00666     const VecT_2& v2,
00667     bool unit_length_vectors = false)
00668 {
00669     typedef quaternion< E,fixed<>,vector_first,positive_cross >
00670         quaternion_type;
00671     
00672     quaternion_type q;
00673     quaternion_rotation_vec_to_vec(q,v1,v2,unit_length_vectors);
00674     matrix_rotation_quaternion(m,q);
00675 }
00676 
00678 // Scale the angle of a rotation matrix
00680 
00682 template < typename E, class A, class B, class L > void
00683 matrix_scale_rotation_angle(matrix<E,A,B,L>& m, E t,
00684     E tolerance = epsilon<E>::placeholder())
00685 {
00686     typedef vector< E,fixed<3> > vector_type;
00687     typedef typename vector_type::value_type value_type;
00688     
00689     vector_type axis;
00690     value_type angle;
00691     matrix_to_axis_angle(m, axis, angle, tolerance);
00692     matrix_rotation_axis_angle(m, axis, angle * t);
00693 }
00694 
00696 template < typename E, class A, class B, class L > void
00697 matrix_scale_rotation_angle_2D(
00698     matrix<E,A,B,L>& m, E t, E tolerance = epsilon<E>::placeholder())
00699 {
00700     typedef vector< E,fixed<2> > vector_type;
00701     typedef typename vector_type::value_type value_type;
00702 
00703     value_type angle = matrix_to_rotation_2D(m);
00704     matrix_rotation_2D(m, angle * t);
00705 }
00706 
00708 // Support functions for uniform handling of row- and column-basis matrices
00710 
00711 /* Note: The matrix rotation slerp, difference and concatenation functions do
00712  * not use et::MatrixPromote<M1,M2>::temporary_type as the return type, even
00713  * though that is the return type of the underlying matrix multiplication.
00714  * This is because the sizes of these matrices are known at compile time (3x3
00715  * and 2x2), and using fixed<> obviates the need for resizing of intermediate
00716  * temporaries.
00717  *
00718  * Also, no size- or type-checking is done on the arguments to these
00719  * functions, as any such errors will be caught by the matrix multiplication
00720  * and assignment to the 3x3 temporary.
00721  */
00722 
00724 #define MAT_TEMP_3X3 matrix<         \
00725     typename et::ScalarPromote<      \
00726         typename MatT_1::value_type, \
00727         typename MatT_2::value_type  \
00728     >::type,                         \
00729     fixed<3,3>,                      \
00730     typename MatT_1::basis_orient,   \
00731     row_major                        \
00732 >
00733 
00735 #define MAT_TEMP_2X2 matrix<         \
00736     typename et::ScalarPromote<      \
00737         typename MatT_1::value_type, \
00738         typename MatT_2::value_type  \
00739     >::type,                         \
00740     fixed<2,2>,                      \
00741     typename MatT_1::basis_orient,   \
00742     row_major                        \
00743 >
00744 
00745 namespace detail {
00746 
00748 template < class MatT_1, class MatT_2 > MAT_TEMP_3X3
00749 matrix_concat_rotations(const MatT_1& m1, const MatT_2& m2, row_basis) {
00750     return m1*m2;
00751 }
00752 
00754 template < class MatT_1, class MatT_2 > MAT_TEMP_3X3
00755 matrix_concat_rotations(const MatT_1& m1, const MatT_2& m2, col_basis) {
00756     return m2*m1;
00757 }
00758 
00760 template < class MatT_1, class MatT_2 > MAT_TEMP_3X3
00761 matrix_concat_rotations(const MatT_1& m1, const MatT_2& m2) {
00762     return matrix_concat_rotations(m1,m2,typename MatT_1::basis_orient());
00763 }
00764 
00766 template < class MatT_1, class MatT_2 > MAT_TEMP_2X2
00767 matrix_concat_rotations_2D(const MatT_1& m1, const MatT_2& m2, row_basis) {
00768     return m1*m2;
00769 }
00770 
00772 template < class MatT_1, class MatT_2 > MAT_TEMP_2X2
00773 matrix_concat_rotations_2D(const MatT_1& m1, const MatT_2& m2, col_basis) {
00774     return m2*m1;
00775 }
00776 
00778 template < class MatT_1, class MatT_2 > MAT_TEMP_2X2
00779 matrix_concat_rotations_2D(const MatT_1& m1, const MatT_2& m2) {
00780     return matrix_concat_rotations_2D(m1,m2,typename MatT_1::basis_orient());
00781 }
00782 
00783 } // namespace detail
00784 
00786 // Matrix rotation difference
00788 
00790 template < class MatT_1, class MatT_2 > MAT_TEMP_3X3
00791 matrix_rotation_difference(const MatT_1& m1, const MatT_2& m2) {
00792     return detail::matrix_concat_rotations(transpose(m1),m2);
00793 }
00794 
00796 template < class MatT_1, class MatT_2 > MAT_TEMP_2X2
00797 matrix_rotation_difference_2D(const MatT_1& m1, const MatT_2& m2) {
00798     return detail::matrix_concat_rotations_2D(transpose(m1),m2);
00799 }
00800 
00802 // Spherical linear interpolation of rotation matrices
00804 
00805 /* @todo: It might be as fast or faster to simply convert the matrices to
00806  * quaternions, interpolate, and convert back.
00807  *
00808  * @todo: The behavior of matrix slerp is currently a little different than
00809  * for quaternions: in the matrix function, when the two matrices are close
00810  * to identical the first is returned, while in the quaternion function the
00811  * quaternions are nlerp()'d in this case.
00812  *
00813  * I still need to do the equivalent of nlerp() for matrices, in which case
00814  * these functions could be revised to pass off to nlerp() when the matrices
00815  * are nearly aligned.
00816 */
00817 
00819 template < class MatT_1, class MatT_2, typename E > MAT_TEMP_3X3
00820 matrix_slerp(const MatT_1& m1, const MatT_2& m2, E t,
00821     E tolerance = epsilon<E>::placeholder())
00822 {
00823     typedef MAT_TEMP_3X3 temporary_type;
00824 
00825     temporary_type m = matrix_rotation_difference(m1,m2);
00826     matrix_scale_rotation_angle(m,t,tolerance);
00827     return detail::matrix_concat_rotations(m1,m);
00828 }
00829 
00831 template < class MatT_1, class MatT_2, typename E > MAT_TEMP_2X2
00832 matrix_slerp_2D(const MatT_1& m1, const MatT_2& m2, E t,
00833     E tolerance = epsilon<E>::placeholder())
00834 {
00835     typedef MAT_TEMP_2X2 temporary_type;
00836 
00837     temporary_type m = matrix_rotation_difference_2D(m1,m2);
00838     matrix_scale_rotation_angle_2D(m,t,tolerance);
00839     return detail::matrix_concat_rotations_2D(m1,m);
00840 }
00841 
00842 #undef MAT_TEMP_3X3
00843 #undef MAT_TEMP_2X2
00844 
00846 // Conversions
00848 
00850 template < class MatT, typename E, class A > void
00851 matrix_to_axis_angle(
00852     const MatT& m,
00853     vector<E,A >& axis,
00854     E& angle,
00855     E tolerance = epsilon<E>::placeholder())
00856 {
00857     typedef MatT matrix_type;
00858     typedef typename matrix_type::value_type value_type;
00859 
00860     /* Checking */
00861     detail::CheckMatLinear3D(m);
00862 
00863     axis.set(
00864         m.basis_element(1,2) - m.basis_element(2,1),
00865         m.basis_element(2,0) - m.basis_element(0,2),
00866         m.basis_element(0,1) - m.basis_element(1,0)
00867     );
00868     value_type l = length(axis);
00869     value_type tmo = trace_3x3(m) - value_type(1);
00870 
00871     if (l > tolerance) {
00872         axis /= l;
00873         angle = std::atan2(l, tmo); // l=2sin(theta),tmo=2cos(theta)
00874     } else if (tmo > value_type(0)) {
00875         axis.zero();
00876         angle = value_type(0);
00877     } else {
00878         size_t largest_diagonal_element =
00879             index_of_max(
00880                 m.basis_element(0,0),
00881                 m.basis_element(1,1),
00882                 m.basis_element(2,2)
00883             );
00884         size_t i, j, k;
00885         cyclic_permutation(largest_diagonal_element, i, j, k);
00886         axis[i] =
00887             std::sqrt(
00888                 m.basis_element(i,i) -
00889                 m.basis_element(j,j) -
00890                 m.basis_element(k,k) +
00891                 value_type(1)
00892             ) * value_type(.5);
00893         value_type s = value_type(.5) / axis[i];
00894         axis[j] = m.basis_element(i,j) * s;
00895         axis[k] = m.basis_element(i,k) * s;
00896         angle = constants<value_type>::pi();
00897     }
00898 }
00899 
00901 template < class MatT, typename Real >
00902 void matrix_to_euler(
00903     const MatT& m,
00904     Real& angle_0,
00905     Real& angle_1,
00906     Real& angle_2,
00907     EulerOrder order,
00908     Real tolerance = epsilon<Real>::placeholder())
00909 {
00910     typedef MatT matrix_type;
00911     typedef typename matrix_type::value_type value_type;
00912 
00913     /* Checking */
00914     detail::CheckMatLinear3D(m);
00915 
00916     size_t i, j, k;
00917     bool odd, repeat;
00918     detail::unpack_euler_order(order, i, j, k, odd, repeat);
00919 
00920     if (repeat) {
00921         value_type s1 = length(m.basis_element(j,i),m.basis_element(k,i));
00922         value_type c1 = m.basis_element(i,i);
00923 
00924         angle_1 = std::atan2(s1, c1);
00925         if (s1 > tolerance) {
00926             angle_0 = std::atan2(m.basis_element(j,i),m.basis_element(k,i));
00927             angle_2 = std::atan2(m.basis_element(i,j),-m.basis_element(i,k));
00928         } else {
00929             angle_0 = value_type(0);
00930             angle_2 = sign(c1) *
00931                 std::atan2(-m.basis_element(k,j),m.basis_element(j,j));
00932         }
00933     } else {
00934         value_type s1 = -m.basis_element(i,k);
00935         value_type c1 = length(m.basis_element(i,i),m.basis_element(i,j));
00936 
00937         angle_1 = std::atan2(s1, c1);
00938         if (c1 > tolerance) {
00939             angle_0 = std::atan2(m.basis_element(j,k),m.basis_element(k,k));
00940             angle_2 = std::atan2(m.basis_element(i,j),m.basis_element(i,i));
00941         } else {
00942             angle_0 = value_type(0);
00943             angle_2 = -sign(s1) *
00944                 std::atan2(-m.basis_element(k,j),m.basis_element(j,j));
00945         }
00946     }
00947     
00948     if (odd) {
00949         angle_0 = -angle_0;
00950         angle_1 = -angle_1;
00951         angle_2 = -angle_2;
00952     }
00953 }
00954 
00956 template < class MatT > typename MatT::value_type
00957 matrix_to_rotation_2D(const MatT& m)
00958 {
00959     /* Checking */
00960     detail::CheckMatLinear2D(m);
00961     
00962     return std::atan2(m.basis_element(0,1),m.basis_element(0,0));
00963 }
00964 
00965 } // namespace cml
00966 
00967 #endif

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