00001 #ifndef OPENTISSUE_KINEMATICS_INVERSE_INVERSE_BONE_TRAITS_H
00002 #define OPENTISSUE_KINEMATICS_INVERSE_INVERSE_BONE_TRAITS_H
00003
00004
00005
00006
00007
00008
00009
00010 #include <OpenTissue/configuration.h>
00011
00012 #include <OpenTissue/core/math/math_euler_angles.h>
00013
00014 #include <cassert>
00015
00016 namespace OpenTissue
00017 {
00018 namespace kinematics
00019 {
00020 namespace inverse
00021 {
00022
00038 template<typename base_bone_traits >
00039 class BoneTraits
00040 : public base_bone_traits
00041 {
00042 public:
00043
00044 typedef typename base_bone_traits::transform_type transform_type;
00045 typedef typename base_bone_traits::vector3_type vector3_type;
00046 typedef typename base_bone_traits::math_types::real_type real_type;
00047 typedef typename base_bone_traits::math_types::value_traits value_traits;
00048
00049 typedef enum {hinge_type, slider_type, ball_type} joint_type;
00050
00051 protected:
00052
00053 joint_type m_type;
00054 real_type m_theta[6];
00055 real_type m_min_theta[6];
00056 real_type m_max_theta[6];
00057 vector3_type m_u;
00058
00059 public:
00060
00061 BoneTraits()
00062 : m_type(ball_type)
00063 , m_u( value_traits::zero(), value_traits::zero(), value_traits::one() )
00064 {
00065
00066 for(size_t i=0;i<6;++i)
00067 {
00068 m_theta[i] = value_traits::zero();
00069 m_min_theta[i] = -value_traits::pi();
00070 m_max_theta[i] = value_traits::pi();
00071 }
00072
00073
00074 }
00075
00081 joint_type const & type() const { return this->m_type; }
00082 joint_type & type() { return this->m_type; }
00083
00091 vector3_type const & u() const { return this->m_u; }
00092 vector3_type & u() { return this->m_u; }
00093
00100 real_type const & theta(size_t const & i) const
00101 {
00102 assert( i < this->active_dofs() || !"theta(): invalid index value");
00103 return m_theta[i];
00104 }
00105
00112 real_type & theta(size_t const & i)
00113 {
00114 assert( i < this->active_dofs() || !"theta(): invalid index value");
00115 return m_theta[i];
00116 }
00117
00126 size_t active_dofs() const
00127 {
00128 if(this->m_type==hinge_type)
00129 return 1;
00130 if(this->m_type==slider_type)
00131 return 1;
00132 if(this->m_type==ball_type)
00133 return 3;
00134 return 0;
00135 }
00136
00143 real_type const & min_joint_limit(size_t const & i) const
00144 {
00145 assert( i < this->active_dofs() || !"min_joint_limit(): invalid index value");
00146 return m_min_theta[i];
00147 }
00148
00155 real_type & min_joint_limit(size_t const & i)
00156 {
00157 assert( i < this->active_dofs() || !"min_joint_limit(): invalid index value");
00158 return m_min_theta[i];
00159 }
00160
00167 real_type const & max_joint_limit(size_t const & i) const
00168 {
00169 assert( i < this->active_dofs() || !"max_joint_limit(): invalid index value");
00170 return m_max_theta[i];
00171 }
00172
00179 real_type & max_joint_limit(size_t const & i)
00180 {
00181 assert( i < this->active_dofs() || !"max_joint_limit(): invalid index value");
00182 return m_max_theta[i];
00183 }
00184
00194 template<typename bone_type, typename chain_type, typename matrix_range>
00195 static void compute_jacobian( bone_type & bone, chain_type & chain, matrix_range & J )
00196 {
00197 assert(J.size1() == chain.get_goal_dimension() || !"compute_jacobian() invalid dimension");
00198 assert(J.size2() == bone.active_dofs() || !"compute_jacobian() invalid dimension");
00199
00200
00201 vector3_type p = base_bone_traits::transform_point( chain.get_end_effector()->absolute(), chain.p_local() );
00202 p = p - bone.absolute().T();
00203 vector3_type i = unit(base_bone_traits::transform_vector( chain.get_end_effector()->absolute(), chain.x_local() ));
00204 vector3_type j = unit(base_bone_traits::transform_vector( chain.get_end_effector()->absolute(), chain.y_local() ));
00205
00206 if(bone.type()==hinge_type)
00207 {
00208
00209 vector3_type u = bone.u();
00210 if(bone.parent())
00211 {
00212 u = base_bone_traits::transform_vector( bone.parent()->absolute(), bone.u() );
00213 }
00214
00215 vector3_type uXp = cross(u, p);
00216
00217 J(0,0) = uXp(0);
00218 J(1,0) = uXp(1);
00219 J(2,0) = uXp(2);
00220
00221 if(!chain.only_position() )
00222 {
00223 vector3_type uXi = cross(u, i);
00224 vector3_type uXj = cross(u, j);
00225
00226 J(3,0) = uXi(0);
00227 J(4,0) = uXi(1);
00228 J(5,0) = uXi(2);
00229
00230 J(6,0) = uXj(0);
00231 J(7,0) = uXj(1);
00232 J(8,0) = uXj(2);
00233 }
00234 }
00235 else if(bone.type()==slider_type)
00236 {
00237
00238 vector3_type u = bone.u();
00239 if(bone.parent())
00240 {
00241 u = base_bone_traits::transform_vector( bone.parent()->absolute(), bone.u() );
00242 }
00243
00244 J(0,0) = u(0);
00245 J(1,0) = u(1);
00246 J(2,0) = u(2);
00247
00248 if(!chain.only_position() )
00249 {
00250 J(3,0) = value_traits::zero();
00251 J(4,0) = value_traits::zero();
00252 J(5,0) = value_traits::zero();
00253 J(6,0) = value_traits::zero();
00254 J(7,0) = value_traits::zero();
00255 J(8,0) = value_traits::zero();
00256 }
00257 }
00258 else if(bone.type()==ball_type)
00259 {
00260 vector3_type ii = vector3_type(value_traits::one(),value_traits::zero(),value_traits::zero());
00261 vector3_type jj = vector3_type(value_traits::zero(),value_traits::one(),value_traits::zero());
00262 vector3_type kk = vector3_type(value_traits::zero(),value_traits::zero(),value_traits::one());
00263
00264
00265 real_type phi = bone.theta(0);
00266 real_type psi = bone.theta(1);
00267
00268
00269
00270 vector3_type u = kk;
00271 vector3_type v = OpenTissue::math::Rz(phi)*jj;
00272 vector3_type w = OpenTissue::math::Rz(phi)*OpenTissue::math::Ry(psi)*kk;
00273
00274
00275 if(bone.parent())
00276 {
00277 vector3_type tmp = base_bone_traits::transform_vector( bone.parent()->absolute(), u );
00278 u = unit(tmp);
00279 tmp = base_bone_traits::transform_vector( bone.parent()->absolute(), v );
00280 v = unit(tmp);
00281 tmp = base_bone_traits::transform_vector( bone.parent()->absolute(), w );
00282 w = unit(tmp);
00283 }
00284
00285 vector3_type uXp = cross(u, p);
00286 vector3_type vXp = cross(v, p);
00287 vector3_type wXp = cross(w, p);
00288
00289
00290 J(0,0) = uXp(0);
00291 J(1,0) = uXp(1);
00292 J(2,0) = uXp(2);
00293
00294
00295 J(0,1) = vXp(0);
00296 J(1,1) = vXp(1);
00297 J(2,1) = vXp(2);
00298
00299
00300 J(0,2) = wXp(0);
00301 J(1,2) = wXp(1);
00302 J(2,2) = wXp(2);
00303
00304 if( ! chain.only_position() )
00305 {
00306 vector3_type uXi = cross(u, i);
00307 vector3_type uXj = cross(u, j);
00308
00309 vector3_type vXi = cross(v, i);
00310 vector3_type vXj = cross(v, j);
00311
00312 vector3_type wXi = cross(w, i);
00313 vector3_type wXj = cross(w, j);
00314
00315 J(3,0) = uXi(0);
00316 J(4,0) = uXi(1);
00317 J(5,0) = uXi(2);
00318
00319 J(6,0) = uXj(0);
00320 J(7,0) = uXj(1);
00321 J(8,0) = uXj(2);
00322
00323 J(3,1) = vXi(0);
00324 J(4,1) = vXi(1);
00325 J(5,1) = vXi(2);
00326
00327 J(6,1) = vXj(0);
00328 J(7,1) = vXj(1);
00329 J(8,1) = vXj(2);
00330
00331 J(3,2) = wXi(0);
00332 J(4,2) = wXi(1);
00333 J(5,2) = wXi(2);
00334
00335 J(6,2) = wXj(0);
00336 J(7,2) = wXj(1);
00337 J(8,2) = wXj(2);
00338 }
00339 }
00340 else
00341 {
00342 assert(false || !"compute_jacobian(): unknown joint type");
00343 }
00344 }
00345
00368 template<typename bone_type, typename vector_range>
00369 static void set_theta(bone_type & bone, vector_range const & sub_theta)
00370 {
00371 assert(sub_theta.size() == bone.active_dofs() || !"set_theta() invalid dimension");
00372
00373 if(bone.type() == hinge_type)
00374 {
00375 bone.theta(0) = sub_theta(0);
00376 bone.relative().Q() = OpenTissue::math::Ru(bone.theta(0), bone.u() );
00377 }
00378 else if(bone.type() == slider_type)
00379 {
00380 bone.theta(0) = sub_theta(0);
00381 bone.relative().T() = bone.theta(0) * bone.u();
00382 }
00383 else if(bone.type() == ball_type)
00384 {
00385 real_type phi = (bone.theta(0) = sub_theta(0) );
00386 real_type psi = (bone.theta(1) = sub_theta(1) );
00387 real_type theta = (bone.theta(2) = sub_theta(2) );
00388
00389 bone.relative().Q() = OpenTissue::math::Rz( phi )*OpenTissue::math::Ry( psi )*OpenTissue::math::Rz(theta);
00390 }
00391 else
00392 {
00393 assert(false || !"set_theta(): unknown joint type");
00394 }
00395 }
00396
00404 template<typename bone_type, typename vector_range>
00405 static void get_theta(bone_type const & bone, vector_range & sub_theta)
00406 {
00407 assert(sub_theta.size() == bone.active_dofs() || !"get_theta() invalid dimension");
00408
00409 if(bone.type() == hinge_type)
00410 {
00411 sub_theta(0) = bone.theta(0);
00412 }
00413 else if(bone.type() == slider_type)
00414 {
00415 sub_theta(0) = bone.theta(0);
00416 }
00417 else if(bone.type() == ball_type)
00418 {
00419 sub_theta(0) = bone.theta(0);
00420 sub_theta(1) = bone.theta(1);
00421 sub_theta(2) = bone.theta(2);
00422 }
00423 else
00424 {
00425 assert(false || !"get_theta(): unknown joint type");
00426 }
00427 }
00428
00438 template<typename bone_type, typename vector_range>
00439 static void get_joint_limits(bone_type const & bone, vector_range & sub_min,vector_range & sub_max)
00440 {
00441 assert(sub_min.size() == bone.active_dofs() || !"get_joint_limits() invalid dimension");
00442 assert(sub_max.size() == bone.active_dofs() || !"get_joint_limits() invalid dimension");
00443
00444 if(bone.type() == hinge_type)
00445 {
00446 sub_min(0) = bone.min_joint_limit(0);
00447 sub_max(0) = bone.max_joint_limit(0);
00448 }
00449 else if(bone.type() == slider_type)
00450 {
00451 sub_min(0) = bone.min_joint_limit(0);
00452 sub_max(0) = bone.max_joint_limit(0);
00453 }
00454 else if(bone.type() == ball_type)
00455 {
00456 sub_min(0) = bone.min_joint_limit(0);
00457 sub_min(1) = bone.min_joint_limit(1);
00458 sub_min(2) = bone.min_joint_limit(2);
00459
00460 sub_max(0) = bone.max_joint_limit(0);
00461 sub_max(1) = bone.max_joint_limit(1);
00462 sub_max(2) = bone.max_joint_limit(2);
00463 }
00464 else
00465 {
00466 assert(false || !"get_joint_limits(): unknown joint type");
00467 }
00468 }
00469
00483 template<typename bone_type, typename vector_range>
00484 static void joint_limit_projection( bone_type const & bone, vector_range & sub_theta)
00485 {
00486 using std::max;
00487 using std::min;
00488
00489 assert(sub_theta.size() == bone.active_dofs() || !"joint_limit_projection() invalid dimension");
00490 assert(sub_theta.size() == bone.active_dofs() || !"joint_limit_projection() invalid dimension");
00491
00492 if(bone.type() == hinge_type || bone.type() == slider_type)
00493 {
00494 sub_theta(0) = max( bone.min_joint_limit(0), min(bone.max_joint_limit(0), sub_theta(0) ) );
00495 }
00496 else if(bone.type() == ball_type)
00497 {
00498 sub_theta(0) = max( bone.min_joint_limit(0), min(bone.max_joint_limit(0), sub_theta(0)) );
00499 sub_theta(1) = max( bone.min_joint_limit(1), min(bone.max_joint_limit(1), sub_theta(1)) );
00500 sub_theta(2) = max( bone.min_joint_limit(2), min(bone.max_joint_limit(2), sub_theta(2)) );
00501 }
00502 else
00503 {
00504 assert(false || !"joint_limit_projection(): unknown joint type");
00505 }
00506 }
00507
00508
00509 };
00510
00511
00512
00513
00514
00515
00528
00529 template<typename bone_type>
00530 inline void synchronize_bone(bone_type & bone)
00531 {
00532 using std::atan2;
00533
00534 typedef typename bone_type::bone_traits bone_traits;
00535 typedef typename bone_traits::transform_type transform_type;
00536 typedef typename bone_traits::real_type real_type;
00537 typedef typename bone_traits::value_traits value_traits;
00538 typedef typename bone_traits::vector3_type vector3_type;
00539 typedef typename transform_type::quaternion_type quaternion_type;
00540
00541 transform_type const & T = bone.relative();
00542
00543 if(bone.type() == bone_traits::hinge_type)
00544 {
00545 quaternion_type Q = T.Q();
00546 vector3_type u = unit( Q.v() );
00547
00548
00549
00550
00551 real_type const ct2 = Q.s();
00552 real_type const st2 = length( Q.v() );
00553 real_type const theta = value_traits::two()* atan2(st2,ct2);
00554
00555 bone.u() = u;
00556 bone.theta(0) = theta;
00557 }
00558 else if(bone.type() == bone_traits::slider_type)
00559 {
00560 vector3_type const u = unit( T.T() );
00561 real_type const theta = length( T.T() );
00562 bone.u() = u;
00563 bone.theta(0) = theta;
00564 }
00565 else if(bone.type() == bone_traits::ball_type)
00566 {
00567 real_type phi = value_traits::zero();
00568 real_type psi = value_traits::zero();
00569 real_type theta = value_traits::zero();
00570
00571 quaternion_type Q = T.Q();
00572
00573 OpenTissue::math::ZYZ_euler_angles(Q, phi, psi, theta);
00574
00575
00576 bone.theta(0) = phi;
00577 bone.theta(1) = psi;
00578 bone.theta(2) = theta;
00579 }
00580 }
00581
00582
00583 }
00584 }
00585 }
00586
00587
00588 #endif