00001 #ifndef OPENTISSUE_DYNAMICS_MBD_UTIL_JOINTS_MBD_BALL_JOINT_H
00002 #define OPENTISSUE_DYNAMICS_MBD_UTIL_JOINTS_MBD_BALL_JOINT_H
00003
00004
00005
00006
00007
00008
00009
00010 #include <OpenTissue/configuration.h>
00011
00012 #include <OpenTissue/dynamics/mbd/interfaces/mbd_joint_interface.h>
00013 #include <OpenTissue/dynamics/mbd/limits/mbd_reach_cone.h>
00014 #include <OpenTissue/core/math/math_constants.h>
00015
00016 #include <OpenTissue/core/math/math_is_number.h>
00017
00018 namespace OpenTissue
00019 {
00020 namespace mbd
00021 {
00022
00023 template< typename mbd_types >
00024 class BallJoint
00025 : public JointInterface<mbd_types>
00026 {
00027 public:
00028
00029 typedef typename mbd_types::math_policy math_policy;
00030 typedef typename mbd_types::math_policy::value_traits value_traits;
00031 typedef typename mbd_types::math_policy::index_type size_type;
00032 typedef typename mbd_types::math_policy::real_type real_type;
00033 typedef typename mbd_types::math_policy::vector_range vector_range;
00034 typedef typename mbd_types::math_policy::vector3_type vector3_type;
00035 typedef typename mbd_types::math_policy::matrix3x3_type matrix3x3_type;
00036 typedef typename mbd_types::math_policy::quaternion_type quaternion_type;
00037 typedef typename mbd_types::math_policy::idx_vector_range idx_vector_range;
00038 typedef typename mbd_types::math_policy::matrix_range matrix_range;
00039 typedef typename mbd_types::math_policy::vector_type vector_type;
00040 typedef ReachCone<mbd_types> reach_cone_type;
00041
00042 protected:
00043
00044 matrix3x3_type m_star_anc_A;
00045 matrix3x3_type m_star_anc_B;
00046 vector3_type m_anc_A_wcs;
00047 vector3_type m_anc_B_wcs;
00048 quaternion_type m_Q_initial;
00049 quaternion_type m_Q_initial_conj;
00050
00051 size_type m_rows;
00052 vector_type m_gamma;
00053 vector_type m_solution;
00054
00055 reach_cone_type *m_reach_cone;
00056 size_type m_reach_offset;
00057
00058 public:
00059
00060 BallJoint()
00061 : m_rows(0)
00062 , m_reach_cone(0)
00063 , m_reach_offset(0)
00064 {}
00065
00066 virtual ~BallJoint() {}
00067
00068 public:
00069
00070 void evaluate()
00071 {
00072 m_rows = 0;
00073 if(!(this->m_socketA && this->m_socketB))
00074 return;
00075
00076 m_rows = 3;
00077
00078 quaternion_type Q_a,Q_b;
00079
00080 this->m_socketA->get_body()->get_orientation(Q_a);
00081 m_star_anc_A = star( Q_a.rotate( this->m_socketA->get_anchor_local()) );
00082
00083 assert(is_number(m_star_anc_A(0,0)) || !"BallJoint::evaluate(): not a number");
00084 assert(is_number(m_star_anc_A(0,1)) || !"BallJoint::evaluate(): not a number");
00085 assert(is_number(m_star_anc_A(0,2)) || !"BallJoint::evaluate(): not a number");
00086 assert(is_number(m_star_anc_A(1,0)) || !"BallJoint::evaluate(): not a number");
00087 assert(is_number(m_star_anc_A(1,1)) || !"BallJoint::evaluate(): not a number");
00088 assert(is_number(m_star_anc_A(1,2)) || !"BallJoint::evaluate(): not a number");
00089 assert(is_number(m_star_anc_A(2,0)) || !"BallJoint::evaluate(): not a number");
00090 assert(is_number(m_star_anc_A(2,1)) || !"BallJoint::evaluate(): not a number");
00091 assert(is_number(m_star_anc_A(2,2)) || !"BallJoint::evaluate(): not a number");
00092
00093 this->m_socketB->get_body()->get_orientation(Q_b);
00094 m_star_anc_B = star( Q_b.rotate( this->m_socketB->get_anchor_local()) );
00095
00096 assert(is_number(m_star_anc_B(0,0)) || !"BallJoint::evaluate(): not a number");
00097 assert(is_number(m_star_anc_B(0,1)) || !"BallJoint::evaluate(): not a number");
00098 assert(is_number(m_star_anc_B(0,2)) || !"BallJoint::evaluate(): not a number");
00099 assert(is_number(m_star_anc_B(1,0)) || !"BallJoint::evaluate(): not a number");
00100 assert(is_number(m_star_anc_B(1,1)) || !"BallJoint::evaluate(): not a number");
00101 assert(is_number(m_star_anc_B(1,2)) || !"BallJoint::evaluate(): not a number");
00102 assert(is_number(m_star_anc_B(2,0)) || !"BallJoint::evaluate(): not a number");
00103 assert(is_number(m_star_anc_B(2,1)) || !"BallJoint::evaluate(): not a number");
00104 assert(is_number(m_star_anc_B(2,2)) || !"BallJoint::evaluate(): not a number");
00105
00106 m_anc_A_wcs = this->m_socketA->get_anchor_world();
00107 m_anc_B_wcs = this->m_socketB->get_anchor_world();
00108
00109 assert(is_number(m_anc_A_wcs(0)) || !"BallJoint::evaluate(): not a number");
00110 assert(is_number(m_anc_A_wcs(1)) || !"BallJoint::evaluate(): not a number");
00111 assert(is_number(m_anc_A_wcs(2)) || !"BallJoint::evaluate(): not a number");
00112 assert(is_number(m_anc_B_wcs(0)) || !"BallJoint::evaluate(): not a number");
00113 assert(is_number(m_anc_B_wcs(1)) || !"BallJoint::evaluate(): not a number");
00114 assert(is_number(m_anc_B_wcs(2)) || !"BallJoint::evaluate(): not a number");
00115
00116 m_reach_offset = 0;
00117 if(m_reach_cone)
00118 {
00119 quaternion_type J_a = this->m_socketA->get_joint_frame().Q();
00120 quaternion_type J_b = this->m_socketB->get_joint_frame().Q();
00121 quaternion_type Q = conj(J_a) % conj(Q_a) % Q_b % J_b;
00122
00123
00124 assert(is_number(Q.s()) || !"BallJoint::evaluate(): not a number");
00125 assert(is_number(Q.v()(0)) || !"BallJoint::evaluate(): not a number");
00126 assert(is_number(Q.v()(1)) || !"BallJoint::evaluate(): not a number");
00127 assert(is_number(Q.v()(2)) || !"BallJoint::evaluate(): not a number");
00128
00129 vector3_type s_local = Q.rotate( this->m_socketB->get_joint_axis_local() );
00130 vector3_type s_wcs = get_axis_world();
00131
00132 assert(is_number(s_wcs(0)) || !"BallJoint::evaluate(): not a number");
00133 assert(is_number(s_wcs(1)) || !"BallJoint::evaluate(): not a number");
00134 assert(is_number(s_wcs(2)) || !"BallJoint::evaluate(): not a number");
00135
00136 m_reach_cone->evaluate(Q,s_wcs,s_local);
00137 if(m_reach_cone->is_active())
00138 {
00139 m_reach_offset = m_rows;
00140 m_rows += m_reach_cone->get_number_of_jacobian_rows();
00141 }
00142 }
00143 }
00144
00145
00146 size_type get_number_of_jacobian_rows() const {return m_rows;}
00147
00148 void get_linear_jacobian_A(matrix_range & J)const
00149 {
00150 assert(J.size1()==m_rows || !"BallJoint::get_linear_jacobian_A(): incorrect dimensions");
00151 assert(J.size2()==3 || !"BallJoint::get_linear_jacobian_A(): incorrect dimensions");
00152 J(0,0) = value_traits::one(); J(0,1) = value_traits::zero(); J(0,2) = value_traits::zero();
00153 J(1,0) = value_traits::zero(); J(1,1) = value_traits::one(); J(1,2) = value_traits::zero();
00154 J(2,0) = value_traits::zero(); J(2,1) = value_traits::zero(); J(2,2) = value_traits::one();
00155 if(m_reach_offset)
00156 m_reach_cone->get_linear_jacobian_A(J,m_reach_offset);
00157 }
00158
00159 void get_linear_jacobian_B(matrix_range & J)const
00160 {
00161 assert(J.size1()==m_rows || !"BallJoint::get_linear_jacobian_B(): incorrect dimensions");
00162 assert(J.size2()==3 || !"BallJoint::get_linear_jacobian_B(): incorrect dimensions");
00163 J(0,0) = -value_traits::one(); J(0,1) = value_traits::zero(); J(0,2) = value_traits::zero();
00164 J(1,0) = value_traits::zero(); J(1,1) = -value_traits::one(); J(1,2) = value_traits::zero();
00165 J(2,0) = value_traits::zero(); J(2,1) = value_traits::zero(); J(2,2) = -value_traits::one();
00166 if(m_reach_offset)
00167 m_reach_cone->get_linear_jacobian_B(J,m_reach_offset);
00168 }
00169
00170 void get_angular_jacobian_A(matrix_range & J)const
00171 {
00172 assert(J.size1()==m_rows || !"BallJoint::get_angular_jacobian_A(): incorrect dimensions");
00173 assert(J.size2()==3 || !"BallJoint::get_angular_jacobian_A(): incorrect dimensions");
00174 J(0,0) = -m_star_anc_A(0,0); J(0,1) = -m_star_anc_A(0,1); J(0,2) = -m_star_anc_A(0,2);
00175 J(1,0) = -m_star_anc_A(1,0); J(1,1) = -m_star_anc_A(1,1); J(1,2) = -m_star_anc_A(1,2);
00176 J(2,0) = -m_star_anc_A(2,0); J(2,1) = -m_star_anc_A(2,1); J(2,2) = -m_star_anc_A(2,2);
00177 if(m_reach_offset)
00178 m_reach_cone->get_angular_jacobian_A(J,m_reach_offset);
00179 }
00180
00181 void get_angular_jacobian_B(matrix_range & J)const
00182 {
00183 assert(J.size1()==m_rows || !"BallJoint::get_angular_jacobian_B(): incorrect dimensions");
00184 assert(J.size2()==3 || !"BallJoint::get_angular_jacobian_B(): incorrect dimensions");
00185 J(0,0) = m_star_anc_B(0,0); J(0,1) = m_star_anc_B(0,1); J(0,2) = m_star_anc_B(0,2);
00186 J(1,0) = m_star_anc_B(1,0); J(1,1) = m_star_anc_B(1,1); J(1,2) = m_star_anc_B(1,2);
00187 J(2,0) = m_star_anc_B(2,0); J(2,1) = m_star_anc_B(2,1); J(2,2) = m_star_anc_B(2,2);
00188 if(m_reach_offset)
00189 m_reach_cone->get_angular_jacobian_B(J,m_reach_offset);
00190 }
00191
00192 void get_stabilization_term(vector_range & b_error)const
00193 {
00194 assert(b_error.size()==m_rows || !"BallJoint::get_stabilization_term(): incorrect dimensions");
00195 real_type k_cor = this->get_frames_per_second()*this->get_error_reduction_parameter();
00196
00197 assert(is_number(k_cor) || !"BallJoint::get_stabilization_term(): not a number");
00198
00199 b_error(0) = k_cor*(m_anc_B_wcs(0) - m_anc_A_wcs(0));
00200 b_error(1) = k_cor*(m_anc_B_wcs(1) - m_anc_A_wcs(1));
00201 b_error(2) = k_cor*(m_anc_B_wcs(2) - m_anc_A_wcs(2));
00202
00203 assert(is_number(b_error(0)) || !"BallJoint::get_stabilization_term(): not a number");
00204 assert(is_number(b_error(1)) || !"BallJoint::get_stabilization_term(): not a number");
00205 assert(is_number(b_error(2)) || !"BallJoint::get_stabilization_term(): not a number");
00206
00207 if(m_reach_offset)
00208 m_reach_cone->get_stabilization_term(b_error,m_reach_offset);
00209 }
00210
00211 void get_low_limits(vector_range & lo)const
00212 {
00213 assert(lo.size()==m_rows || !"BallJoint::get_low_limits(): incorrect dimension");
00214 lo(0) = OpenTissue::math::detail::lowest<real_type>();
00215 lo(1) = OpenTissue::math::detail::lowest<real_type>();
00216 lo(2) = OpenTissue::math::detail::lowest<real_type>();
00217
00218 assert(is_number(lo(0)) || !"BallJoint::get_low_limits(): not a number");
00219 assert(is_number(lo(1)) || !"BallJoint::get_low_limits(): not a number");
00220 assert(is_number(lo(2)) || !"BallJoint::get_low_limits(): not a number");
00221
00222 if(m_reach_offset)
00223 m_reach_cone->get_low_limits(lo,m_reach_offset);
00224 }
00225
00226 void get_high_limits(vector_range & hi)const
00227 {
00228 assert(hi.size()==m_rows || !"BallJoint::get_high_limits(): incorrect dimension");
00229 hi(0) = OpenTissue::math::detail::highest<real_type>();
00230 hi(1) = OpenTissue::math::detail::highest<real_type>();
00231 hi(2) = OpenTissue::math::detail::highest<real_type>();
00232
00233 assert(is_number(hi(0)) || !"BallJoint::get_high_limits(): not a number");
00234 assert(is_number(hi(1)) || !"BallJoint::get_high_limits(): not a number");
00235 assert(is_number(hi(2)) || !"BallJoint::get_high_limits(): not a number");
00236
00237 if(m_reach_offset)
00238 m_reach_cone->get_high_limits(hi,m_reach_offset);
00239 }
00240
00241 void get_dependency_indices(idx_vector_range & dep)const
00242 {
00243 assert(dep.size()==m_rows || !"BallJoint::get_dependency_indices(): incorrect dimension");
00244 for(size_type i=0;i<m_rows;++i)
00245 dep(i) = OpenTissue::math::detail::highest<size_type>();
00246 }
00247
00248 void get_dependency_factors(vector_range & factors)const
00249 {
00250 assert(factors.size()==m_rows || !"BallJoint::get_dependency_factors(): incorrect dimension");
00251 for(size_type i=0;i<m_rows;++i)
00252 factors(i) = value_traits::zero();
00253 }
00254
00255 void set_regularization(vector_range const & gamma)
00256 {
00257 assert(gamma.size()==m_rows || !"BallJoint::set_regularization(): incorrect dimension");
00258 math_policy::resize( m_gamma, 3);
00259 for(size_type i=0;i<3;++i)
00260 {
00261 assert(gamma(i)<=value_traits::one() || !"BallJoint::set_regularization(): gamma was greather than 1");
00262 assert(gamma(i)>=value_traits::zero() || !"BallJoint::set_regularization(): gamma was less than 0");
00263 m_gamma(i) = gamma(i);
00264 }
00265
00266 assert(is_number(gamma(0)) || !"BallJoint::set_regularization(): not a number");
00267 assert(is_number(gamma(1)) || !"BallJoint::set_regularization(): not a number");
00268 assert(is_number(gamma(2)) || !"BallJoint::set_regularization(): not a number");
00269
00270 if(m_reach_offset)
00271 m_reach_cone->set_regularization(gamma,m_reach_offset);
00272 }
00273
00274 void get_regularization(vector_range & gamma)const
00275 {
00276 assert(gamma.size()==m_rows|| !"BallJoint::get_regularization(): incorrect dimension");
00277 if(m_gamma.size()==0)
00278 {
00279 for(size_type i=0;i<3;++i)
00280 gamma(i) = value_traits::zero();
00281 }
00282 else
00283 {
00284 for(size_type i=0;i<3;++i)
00285 gamma(i) = m_gamma(i);
00286 }
00287
00288 assert(is_number(gamma(0)) || !"BallJoint::get_regularization(): not a number");
00289 assert(is_number(gamma(1)) || !"BallJoint::get_regularization(): not a number");
00290 assert(is_number(gamma(2)) || !"BallJoint::get_regularization(): not a number");
00291
00292 if(m_reach_offset)
00293 m_reach_cone->get_regularization(gamma,m_reach_offset);
00294 }
00295
00296 void set_solution(vector_range const & solution)
00297 {
00298 assert(solution.size()==m_rows || !"BallJoint::set_solution(): incorrect dimension");
00299
00300 math_policy::resize( m_solution, 5);
00301 for(size_type i=0;i<3;++i)
00302 m_solution(i) = solution(i);
00303
00304 assert(is_number(solution(0)) || !"BallJoint::set_solution(): not a number");
00305 assert(is_number(solution(1)) || !"BallJoint::set_solution(): not a number");
00306 assert(is_number(solution(2)) || !"BallJoint::set_solution(): not a number");
00307
00308 if(m_reach_offset)
00309 m_reach_cone->set_solution(solution,m_reach_offset);
00310 }
00311
00312 void get_solution(vector_range & solution)const
00313 {
00314 assert(solution.size()==m_rows || !"BallJoint::get_solution(): incorrect dimension");
00315
00316 if(m_solution.size()==0)
00317 {
00318 for(size_type i=0;i<3;++i)
00319 solution(i) = value_traits::zero();
00320 }
00321 else
00322 {
00323 for(size_type i=0;i<3;++i)
00324 solution(i) = m_solution(i);
00325 }
00326
00327 assert(is_number(solution(0)) || !"BallJoint::get_solution(): not a number");
00328 assert(is_number(solution(1)) || !"BallJoint::get_solution(): not a number");
00329 assert(is_number(solution(2)) || !"BallJoint::get_solution(): not a number");
00330
00331 if(m_reach_offset)
00332 m_reach_cone->get_solution(solution,m_reach_offset);
00333
00334 }
00335
00336 void calibration()
00337 {
00338 assert(this->m_socketA|| !"BallJoint::calibration(): socket A was null");
00339 assert(this->m_socketB|| !"BallJoint::calibration(): socket B was null");
00340
00341 quaternion_type Q_A,Q_B;
00342 this->m_socketA->get_body()->get_orientation(Q_A);
00343 this->m_socketB->get_body()->get_orientation(Q_B);
00344
00345
00346 assert(is_number(Q_A.s()) || !"BallJoint::calibration(): not a number");
00347 assert(is_number(Q_A.v()(0)) || !"BallJoint::calibration(): not a number");
00348 assert(is_number(Q_A.v()(1)) || !"BallJoint::calibration(): not a number");
00349 assert(is_number(Q_A.v()(2)) || !"BallJoint::calibration(): not a number");
00350
00351 assert(is_number(Q_B.s()) || !"BallJoint::calibration(): not a number");
00352 assert(is_number(Q_B.v()(0)) || !"BallJoint::calibration(): not a number");
00353 assert(is_number(Q_B.v()(1)) || !"BallJoint::calibration(): not a number");
00354 assert(is_number(Q_B.v()(2)) || !"BallJoint::calibration(): not a number");
00355
00356
00357
00358
00359
00360
00361
00362 m_Q_initial = conj(Q_B) % Q_A;
00363 m_Q_initial_conj = conj(m_Q_initial);
00364
00365 assert(is_number(m_Q_initial_conj.s()) || !"BallJoint::calibration(): not a number");
00366 assert(is_number(m_Q_initial_conj.v()(0)) || !"BallJoint::calibration(): not a number");
00367 assert(is_number(m_Q_initial_conj.v()(1)) || !"BallJoint::calibration(): not a number");
00368 assert(is_number(m_Q_initial_conj.v()(2)) || !"BallJoint::calibration(): not a number");
00369 }
00370
00371 vector3_type get_axis_world() const
00372 {
00373 assert(is_number(this->m_socketA->get_joint_axis_world()(0)) || !"BallJoint::get_axis_world(): not a number");
00374 assert(is_number(this->m_socketA->get_joint_axis_world()(1)) || !"BallJoint::get_axis_world(): not a number");
00375 assert(is_number(this->m_socketA->get_joint_axis_world()(2)) || !"BallJoint::get_axis_world(): not a number");
00376
00377 return this->m_socketA->get_joint_axis_world();
00378 }
00379
00380 void set_reach_cone(reach_cone_type const & cone) { m_reach_cone = const_cast<reach_cone_type*>(&cone); }
00381
00382 };
00383
00384 }
00385 }
00386
00387 #endif