00001 #ifndef OPENTISSUE_DYNAMICS_MBD_MBD_CONTACT_POINT_H
00002 #define OPENTISSUE_DYNAMICS_MBD_MBD_CONTACT_POINT_H
00003
00004
00005
00006
00007
00008
00009
00010 #include <OpenTissue/configuration.h>
00011
00012 #include <OpenTissue/core/math/math_is_number.h>
00013 #include <OpenTissue/core/math/math_constants.h>
00014
00015
00016 namespace OpenTissue
00017 {
00018 namespace mbd
00019 {
00020
00021 template< typename types >
00022 class ContactPoint : public types::constraint_type
00023 {
00024 public:
00025
00026 typedef typename types::math_policy math_policy;
00027 typedef typename math_policy::size_type size_type;
00028 typedef typename math_policy::real_type real_type;
00029 typedef typename math_policy::value_traits value_traits;
00030 typedef typename math_policy::vector3_type vector3_type;
00031 typedef typename math_policy::matrix3x3_type matrix3x3_type;
00032 typedef typename math_policy::quaternion_type quaternion_type;
00033 typedef typename math_policy::vector_type vector_type;
00034 typedef typename math_policy::vector_range vector_range;
00035 typedef typename math_policy::idx_vector_range idx_vector_range;
00036 typedef typename math_policy::matrix_range matrix_range;
00037
00038 typedef typename types::body_type body_type;
00039 typedef typename types::material_type material_type;
00040
00041 public:
00042
00043 bool m_use_stabilization;
00044 bool m_use_friction;
00045 bool m_use_bounce;
00046
00047 material_type * m_material;
00048
00049 vector3_type m_n;
00050 vector3_type m_p;
00051 real_type m_distance;
00052
00053 vector3_type m_rA;
00054 vector3_type m_rB;
00055 real_type m_un;
00056 size_type m_eta;
00057 std::vector<vector3_type> m_t;
00058
00059 bool m_bodies_flipped;
00060
00061
00062
00063
00064 vector_type m_solution;
00065
00066 public:
00067
00068 ContactPoint()
00069 : m_use_stabilization(true)
00070 , m_use_friction(true)
00071 , m_use_bounce(true)
00072 , m_material(0)
00073 {}
00074
00075 virtual ~ContactPoint(){}
00076
00077 public:
00078
00079 void set_use_friction (bool value) { m_use_friction = value; }
00080 void set_use_bounce (bool value) { m_use_bounce = value; }
00081 void set_use_stabilization(bool value) { m_use_stabilization = value; }
00082
00094 void init(
00095 body_type * bodyA
00096 , body_type * bodyB
00097 , vector3_type const & p
00098 , vector3_type const & n
00099 , real_type const & distance
00100 , material_type * material
00101 )
00102 {
00103 assert(bodyA || !"ContactPoint::init() body A was null");
00104 assert(bodyB || !"ContactPoint::init() body B was null");
00105
00106 assert(bodyA!=bodyB || !"ContactPoint::init() body A was the same as body B");
00107 assert(bodyA->get_index()!=bodyB->get_index() || !"ContactPoint::init() body A and B have the same index");
00108
00109 assert(is_number(p(0)) || !"ContactPoint::init() not a number encountered");
00110 assert(is_number(p(1)) || !"ContactPoint::init() not a number encountered");
00111 assert(is_number(p(2)) || !"ContactPoint::init() not a number encountered");
00112 assert(is_number(n(0)) || !"ContactPoint::init() not a number encountered");
00113 assert(is_number(n(1)) || !"ContactPoint::init() not a number encountered");
00114 assert(is_number(n(2)) || !"ContactPoint::init() not a number encountered");
00115 assert(is_number(distance) || !"ContactPoint::init() not a number encountered");
00116
00117 if(bodyA->get_index()<bodyB->get_index())
00118 {
00119 m_bodies_flipped = false;
00120 this->m_bodyA = bodyA;
00121 this->m_bodyB = bodyB;
00122 m_n = n;
00123 }
00124 else
00125 {
00126 m_bodies_flipped = true;
00127 this->m_bodyA = bodyB;
00128 this->m_bodyB = bodyA;
00129 m_n = -n;
00130 }
00131
00132 m_p = p;
00133 m_distance = distance;
00134 m_material = material;
00135
00136 vector3_type r_A_wcs;
00137 vector3_type r_B_wcs;
00138 this->m_bodyA->get_position(r_A_wcs);
00139 this->m_bodyB->get_position(r_B_wcs);
00140 m_rA = p - r_A_wcs;
00141 m_rB = p - r_B_wcs;
00142 }
00143
00147 void evaluate()
00148 {
00149 assert(this->m_bodyA || !"ContactPoint::evaluate(): body A was null");
00150 assert(this->m_bodyB || !"ContactPoint::evaluate(): body B was null");
00151 assert(m_material || !"ContactPoint::evaluate(): Material was null");
00152
00153 vector3_type u,v_a,w_a,v_b,w_b;
00154
00155 this->get_body_A()->get_velocity(v_a);
00156 this->get_body_B()->get_velocity(v_b);
00157 this->get_body_A()->get_spin(w_a);
00158 this->get_body_B()->get_spin(w_b);
00159
00160 u = mbd::compute_relative_contact_velocity(v_a,w_a,m_rA,v_b,w_b,m_rB);
00161
00162 m_un = m_n * u;
00163
00164
00165 m_eta = m_material->get_number_of_friction_directions();
00166
00167
00168 if(!m_use_friction)
00169 m_eta = 0;
00170
00171 if(m_eta>0)
00172 {
00173
00174 if(m_eta != m_t.size())
00175 m_t.resize(m_eta);
00176
00177
00178
00179
00180 vector3_type x;
00181 vector3_type y;
00182 x.clear();
00183 y.clear();
00184
00185
00186
00187
00188
00189 if( m_material->get_use_sliding_direction() )
00190 {
00191
00192
00193
00194
00195
00196
00197
00198
00199 vector3_type un = m_n * m_un;
00200 vector3_type ut = u - un;
00201 if( !is_zero(ut) )
00202 {
00203 x = unit(ut);
00204 y = unit( cross(m_n , x));
00205 }
00206 else
00207 {
00208
00209
00210 orthonormal_vectors(x,y,m_n);
00211 }
00212 }
00213 else if(m_material->get_use_prefixed_direction() )
00214 {
00215 quaternion_type Q;
00216 vector3_type v = m_material->get_prefixed_direction();
00217
00218 bool is_direction_fixed_in_A = m_material->get_prefixed_material_index() == this->get_body_A()->get_material_idx();
00219 bool is_direction_fixed_in_B = m_material->get_prefixed_material_index() == this->get_body_B()->get_material_idx();
00220 if( is_direction_fixed_in_A)
00221 {
00222 this->get_body_A()->get_orientation(Q);
00223 }
00224 else if( is_direction_fixed_in_B)
00225 {
00226 this->get_body_B()->get_orientation(Q);
00227 }
00228 else
00229 {
00230
00231
00232 Q.identity();
00233 }
00234
00235 vector3_type w = unit( Q.rotate(v) );
00236
00237 x = w - (w*m_n)*m_n;
00238 if( !is_zero(x) )
00239 {
00240 y = unit( cross(m_n , x));
00241 }
00242 else
00243 {
00244
00245
00246 orthonormal_vectors(x,y,m_n);
00247 }
00248 }
00249 else
00250 {
00251
00252 orthonormal_vectors(x,y,m_n);
00253 }
00254
00255
00256
00257
00258
00259
00260 m_t[0] = x;
00261 if(m_eta==2)
00262 {
00263 m_t[1] = y;
00264 }
00265 else if(m_eta>2)
00266 {
00267
00268 real_type angle = value_traits::pi() / m_eta;
00269 matrix3x3_type R;
00270
00271 R = Ru(angle,m_n);
00272 for(size_t i=1;i<m_eta;++i)
00273 {
00274 m_t[i] = R*m_t[i-1];
00275 }
00276 }
00277 }
00278 }
00279
00283 size_type get_number_of_jacobian_rows() const { return m_eta+1; }
00284
00288 void get_linear_jacobian_A(matrix_range & J)const
00289 {
00290 assert(this->m_bodyA || !"ContactPoint::get_linear_jacobian_A(): body A was null");
00291 assert(this->m_bodyB || !"ContactPoint::get_linear_jacobian_A(): body B was null");
00292
00293 assert(J.size1()==get_number_of_jacobian_rows() || !"ContactPoint::get_linear_jacobian_A(): incorrect dimension");
00294 assert(J.size2()==3 || !"ContactPoint::get_linear_jacobian_A(): incorrect dimension");
00295
00296 J(0,0) = -m_n(0);
00297 J(0,1) = -m_n(1);
00298 J(0,2) = -m_n(2);
00299 for(size_t i=0;i<m_eta;++i)
00300 {
00301 size_t j = i+1;
00302 J(j,0) = -m_t[i](0);
00303 J(j,1) = -m_t[i](1);
00304 J(j,2) = -m_t[i](2);
00305 }
00306 }
00307
00311 void get_linear_jacobian_B(matrix_range & J) const
00312 {
00313 assert(this->m_bodyA || !"ContactPoint::get_linear_jacobian_B(): body A was null");
00314 assert(this->m_bodyB || !"ContactPoint::get_linear_jacobian_B(): body B was null");
00315
00316 assert(J.size1()==get_number_of_jacobian_rows() || !"ContactPoint::get_linear_jacobian_B(): incorrect dimension");
00317 assert(J.size2()==3 || !"ContactPoint::get_linear_jacobian_B(): incorrect dimension");
00318
00319 J(0,0) = m_n(0);
00320 J(0,1) = m_n(1);
00321 J(0,2) = m_n(2);
00322 for(size_t i=0;i<m_eta;++i)
00323 {
00324 size_t j = i+1;
00325 J(j,0) = m_t[i](0);
00326 J(j,1) = m_t[i](1);
00327 J(j,2) = m_t[i](2);
00328 }
00329 }
00330
00334 void get_angular_jacobian_A(matrix_range & J) const
00335 {
00336 assert(this->m_bodyA || !"ContactPoint::get_angular_jacobian_A(): body A was null");
00337 assert(this->m_bodyB || !"ContactPoint::get_angular_jacobian_A(): body B was null");
00338
00339 assert(J.size1()==get_number_of_jacobian_rows() || !"ContactPoint::get_angular_jacobian_A(): incorrect dimension");
00340 assert(J.size2()==3 || !"ContactPoint::get_angular_jacobian_A(): incorrect dimension");
00341
00342 vector3_type tmp = cross(m_rA , m_n);
00343 J(0,0) = -tmp(0);
00344 J(0,1) = -tmp(1);
00345 J(0,2) = -tmp(2);
00346 for(size_t i=0;i<m_eta;++i)
00347 {
00348 size_t j = i+1;
00349 tmp = cross( m_rA , m_t[i] );
00350 J(j,0) = -tmp(0);
00351 J(j,1) = -tmp(1);
00352 J(j,2) = -tmp(2);
00353 }
00354 }
00355
00359 void get_angular_jacobian_B(matrix_range & J) const
00360 {
00361 assert(this->m_bodyA || !"ContactPoint::get_angular_jacobian_B(): body A was null");
00362 assert(this->m_bodyB || !"ContactPoint::get_angular_jacobian_B(): body B was null");
00363
00364 assert(J.size1()==get_number_of_jacobian_rows() || !"ContactPoint::get_angular_jacobian_B(): incorrect dimension");
00365 assert(J.size2()==3 || !"ContactPoint::get_angular_jacobian_B(): incorrect dimension");
00366
00367 vector3_type tmp = cross(m_rB , m_n);
00368 J(0,0) = tmp(0);
00369 J(0,1) = tmp(1);
00370 J(0,2) = tmp(2);
00371 for(size_t i=0;i<m_eta;++i)
00372 {
00373 size_t j = i+1;
00374 tmp = cross( m_rB , m_t[i] );
00375 J(j,0) = tmp(0);
00376 J(j,1) = tmp(1);
00377 J(j,2) = tmp(2);
00378 }
00379 }
00380
00384 void get_stabilization_term(vector_range & b_error) const
00385 {
00386 using std::max;
00387
00388 assert(b_error.size()==get_number_of_jacobian_rows() || !"ContactPoint::get_stabilization_term(): incorrect dimension");
00389
00390 if(!m_use_stabilization || m_distance>=0)
00391 b_error(0) = value_traits::zero();
00392 else
00393 b_error(0) = -(this->get_frames_per_second()*this->get_error_reduction_parameter()*m_distance);
00394
00395 for(size_type i = 1;i<=m_eta;++i)
00396 b_error(i) = value_traits::zero();
00397
00398 if(m_use_bounce)
00399 {
00400
00401
00402
00403
00404
00405 real_type u_n_after = - m_material->normal_restitution() * m_un;
00406 b_error(0) += max(value_traits::zero(), u_n_after);
00407 }
00408 assert(is_number(b_error(0)) || !"ContactPoint::get_stabilization_term(): not a number encountered");
00409 }
00410
00414 void get_low_limits(vector_range & lo) const
00415 {
00416 assert(m_material || !"ContactPoint::get_low_limits(): Material was null");
00417 assert(lo.size()==get_number_of_jacobian_rows() || !"ContactPoint::get_low_limits(): incorrect dimension");
00418
00419 lo(0) = value_traits::zero();
00420
00421
00422 for(size_type i = 0;i<m_eta;++i)
00423 lo(i+1) = -m_material->get_friction_coefficient(i);
00424 }
00425
00429 void get_high_limits(vector_range & hi) const
00430 {
00431 assert(m_material || !"ContactPoint::get_high_limits(): Material was null");
00432 assert(hi.size()==get_number_of_jacobian_rows() || !"ContactPoint::get_high_limits(): incorrect dimension");
00433
00434 hi(0) = OpenTissue::math::detail::highest<real_type>();
00435
00436
00437 for(size_type i = 0;i<m_eta;++i)
00438 hi(i+1) = m_material->get_friction_coefficient(i);
00439 }
00440
00445 void get_dependency_indices(idx_vector_range & dep) const
00446 {
00447 assert(this->m_bodyA || !"ContactPoint::get_dependency_indices(): body A was null");
00448 assert(this->m_bodyB || !"ContactPoint::get_dependency_indices(): body B was null");
00449
00450 assert(dep.size()==get_number_of_jacobian_rows() || !"ContactPoint::get_dependency_indices(): incorrect dimension");
00451
00452 dep(0) = OpenTissue::math::detail::highest<size_type>();
00453
00454 for(size_type i = 1;i<=m_eta;++i)
00455 dep(i) = this->get_jacobian_index();
00456 }
00457
00461 void get_dependency_factors(vector_range & factors) const
00462 {
00463 assert(m_material || !"ContactPoint::get_dependency_factors(): Material was null");
00464 assert(this->m_bodyA || !"ContactPoint::get_dependency_factors(): body A was null");
00465 assert(this->m_bodyB || !"ContactPoint::get_dependency_factors(): body B was null");
00466 assert(factors.size()==get_number_of_jacobian_rows() || !"ContactPoint::get_dependency_factors(): incorrect dimension");
00467
00468 factors(0) = value_traits::zero();
00469
00470 for(size_type i = 0;i<m_eta;++i)
00471 factors(i+1) = m_material->get_friction_coefficient(i);
00472 }
00473
00474 void set_regularization(vector_range const & gamma)
00475 {
00476 assert(false || !"ContactPoint::set_regularization(): This method should never be invoked directly, use Material::set_regularization instead");
00477 }
00478
00479 void get_regularization(vector_range & gamma) const
00480 {
00481 assert(m_material || !"ContactPoint::get_regularization(): Material was null");
00482 assert(gamma.size()==get_number_of_jacobian_rows() || !"ContactPoint::get_regularization(): incorrect dimension");
00483
00484 gamma(0) = m_material->get_normal_regularization();
00485
00486 for(size_t i=1;i<m_eta;++i)
00487 gamma(i) = value_traits::zero();
00488 }
00489
00490 void set_solution(vector_range const & solution)
00491 {
00492 assert(solution.size()==get_number_of_jacobian_rows() || !"ContactPoint::set_solution(): incorrect dimension");
00493
00494 math_policy::resize( m_solution, get_number_of_jacobian_rows());
00495 for(size_type i=0;i<get_number_of_jacobian_rows();++i)
00496 m_solution(i) = solution(i);
00497 }
00498
00499 void get_solution(vector_range & solution) const
00500 {
00501 assert(solution.size()==get_number_of_jacobian_rows() || !"ContactPoint::get_solution(): incorrect dimension");
00502
00503 if(m_solution.size()==0)
00504 {
00505 for(size_type i=0;i<get_number_of_jacobian_rows();++i)
00506 solution(i) = value_traits::zero();
00507 }
00508 else
00509 {
00510 for(size_type i=0;i<get_number_of_jacobian_rows();++i)
00511 solution(i) = m_solution(i);
00512 }
00513 }
00514
00518 void set_error_reduction_parameter(real_type const & erp)
00519 {
00520
00521
00522
00523
00524
00525
00526 }
00527
00531 real_type get_error_reduction_parameter() const
00532 {
00533
00534
00535
00536 if(this->use_erp())
00537 return m_material->get_error_reduction_parameter();
00538 return value_traits::one();
00539 }
00540
00541 };
00542
00543 }
00544 }
00545
00546 #endif