00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "engine/geometry/icollisiondetector.h"
00024 #include "engine/simulation/rigidobject.h"
00025 #include "rctracker.h"
00026 #include "rigidbody.h"
00027
00028 #include <cmath>
00029 #include <limits>
00030
00031 using namespace sheep;
00032
00033 const Real HULL_THICKNESS = 0.05 / 2.0;
00034
00035 Matrix RCTracker::compute_A_matrix() {
00036 Matrix A(m_resting_contacts.size(), m_resting_contacts.size());
00037
00038 for(int i=0; i<m_resting_contacts.size(); i++)
00039 for(int j=0; j<m_resting_contacts.size(); j++) {
00040 Contact ci = m_resting_contacts[i];
00041 Contact cj = m_resting_contacts[j];
00042
00043 RigidBody *a = ci.m_a->GetBody();
00044 RigidBody *b = ci.m_b->GetBody();
00045
00046
00047
00048 if((ci.m_a!=cj.m_a)&&(ci.m_b!=cj.m_b)&&
00049 (ci.m_a!=cj.m_b)&&(ci.m_b!=cj.m_a)) {
00050 A(i,j) = 0;
00051 continue;
00052 }
00053
00054 Vector3 ria = ci.m_a->GetBody()->TransformVectorToWorld(ci.m_pa);
00055 Vector3 rib = ci.m_b->GetBody()->TransformVectorToWorld(ci.m_pb);
00056 Vector3 rja = cj.m_a->GetBody()->TransformVectorToWorld(cj.m_pa);
00057 Vector3 rjb = cj.m_b->GetBody()->TransformVectorToWorld(cj.m_pb);
00058
00059
00060
00061 Vector3 force_on_a = 0, torque_on_a = 0;
00062
00063 if(cj.m_a==ci.m_a) {
00064 force_on_a = cj.m_n;
00065 torque_on_a = rja ^ cj.m_n;
00066 }
00067 else if(cj.m_b==ci.m_a) {
00068 force_on_a = - cj.m_n;
00069 torque_on_a = rja ^ cj.m_n;
00070 }
00071
00072
00073
00074 Vector3 force_on_b = 0, torque_on_b = 0;
00075
00076 if(cj.m_a==ci.m_b) {
00077 force_on_b = cj.m_n;
00078 torque_on_b = rjb ^ cj.m_n;
00079 }
00080 else if(cj.m_b==ci.m_b) {
00081 force_on_b = - cj.m_n;
00082 torque_on_b = rjb ^ cj.m_n;
00083 }
00084
00085
00086
00087
00088 Vector3 a_part = a->IsFrozen() ? 0 : force_on_a / a->GetMass() +
00089 ((a->GetWorldInertiaTensor().Inverse() * torque_on_a) ^ ria);
00090
00091 Vector3 b_part = b->IsFrozen() ? 0 : force_on_b / b->GetMass() +
00092 ((b->GetWorldInertiaTensor().Inverse() * torque_on_b) ^ rib);
00093
00094 A(i,j) = ci.m_n * (a_part - b_part);
00095 }
00096
00097 return A;
00098 }
00099
00100 Vector RCTracker::compute_b_vector() {
00101 Vector bv(m_resting_contacts.size());
00102
00103 for(int i=0; i<m_resting_contacts.size(); i++) {
00104 Contact c = m_resting_contacts[i];
00105
00106 RigidBody *a = c.m_a->GetBody();
00107 RigidBody *b = c.m_b->GetBody();
00108
00109 Vector3 ra = a->TransformVectorToWorld(c.m_pa);
00110 Vector3 rb = b->TransformVectorToWorld(c.m_pb);
00111
00112
00113
00114
00115 Vector3 a_ext_part = a->IsFrozen() ? 0 : a->GetTotalForce() / a->GetMass() +
00116 ((a->GetWorldInertiaTensor().Inverse() * a->GetTotalTorque()) ^ ra);
00117
00118 Vector3 b_ext_part = b->IsFrozen() ? 0 : b->GetTotalForce() / b->GetMass() +
00119 ((b->GetWorldInertiaTensor().Inverse() * b->GetTotalTorque()) ^ rb);
00120
00121
00122
00123
00124 Vector3 a_vel_part = 0, b_vel_part = 0;
00125
00126 if(!a->IsFrozen()) {
00127 Vector3 a_L = a->GetWorldInertiaTensor() * a->GetAngularVelocity();
00128 a_vel_part = (a->GetAngularVelocity() ^ (a->GetAngularVelocity() ^ ra)) +
00129 ((a->GetWorldInertiaTensor().Inverse() * (a_L ^ a->GetAngularVelocity())) ^ ra);
00130 }
00131
00132 if(!b->IsFrozen()) {
00133 Vector3 b_L = b->GetWorldInertiaTensor() * b->GetAngularVelocity();
00134 b_vel_part = (b->GetAngularVelocity() ^ (b->GetAngularVelocity() ^ rb)) +
00135 ((b->GetWorldInertiaTensor().Inverse() * (b_L ^ b->GetAngularVelocity())) ^ rb);
00136 }
00137
00138
00139
00140 Real k1 = c.m_n * ((a_ext_part + a_vel_part) - (b_ext_part + b_vel_part));
00141 Real k2 = 2 * c.GetNormalDerivative() * (c.m_va - c.m_vb);
00142
00143 bv[i] = k1 + k2;
00144 }
00145
00146 return bv;
00147 }
00148
00149 Vector RCTracker::fdirection(const Matrix &A, int d) {
00150 Vector delta_f(m_resting_contacts.size(), 0);
00151
00152 delta_f[d] = 1;
00153
00154 if(C.size()<1)
00155 return delta_f;
00156
00157 int i, j, k;
00158
00159
00160
00161 Matrix A11(C.size(), C.size());
00162
00163 k = 0;
00164
00165 for(i=0; i<m_resting_contacts.size(); i++) {
00166 if(!C.Contains(i))
00167 continue;
00168
00169 for(j=0; j<m_resting_contacts.size(); j++) {
00170 if(C.Contains(j))
00171 A11[k++] = A(i,j);
00172 }
00173 }
00174
00175 assert(k==C.size()*C.size());
00176
00177
00178
00179 Vector v1(C.size());
00180
00181 k = 0;
00182
00183 for(i=0; i<m_resting_contacts.size(); i++) {
00184 if(C.Contains(i))
00185 v1[k++] = A(i,d);
00186 }
00187
00188 assert(k==C.size());
00189
00190
00191
00192 Vector x = - A11.Inverse() * v1;
00193
00194
00195
00196 k = 0;
00197
00198 for(i=0; i<m_resting_contacts.size(); i++) {
00199 if(C.Contains(i))
00200 delta_f[i] = x[k++];
00201 }
00202
00203 return delta_f;
00204 }
00205
00206
00207 void RCTracker::maxstep(const Vector &a,
00208 const Vector &f,
00209 const Vector &delta_a,
00210 const Vector &delta_f,
00211 int d, Real *s, int *j) {
00212 *s = std::numeric_limits<Real>::max();
00213 *j = -1;
00214
00215 if(delta_a[d]>0) {
00216
00217
00218
00219
00220
00221
00222 *s = - a[d] / delta_a[d];
00223 *j = d;
00224 }
00225
00226 index_set::iterator i;
00227
00228 for(i=C.begin(); i!=C.end(); i++)
00229 if(delta_f[*i]<0) {
00230 assert(fnz(delta_f[*i]));
00231
00232 Real s1 = -f[*i] / delta_f[*i];
00233
00234 if(s1 < *s) {
00235 *s = s1;
00236 *j = *i;
00237 }
00238 }
00239
00240 for(i=NC.begin(); i!=NC.end(); i++)
00241 if(delta_a[*i]<0) {
00242 assert(fnz(delta_a[*i]));
00243
00244 Real s1 = -a[*i] / delta_a[*i];
00245
00246 if(s1 < *s) {
00247 *s = s1;
00248 *j = *i;
00249 }
00250 }
00251 }
00252
00253 void RCTracker::drive_to_zero(const Matrix &A, Vector &f, Vector &a, int d) {
00254 L1:
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269 Vector delta_f = fdirection(A, d);
00270 Vector delta_a = A * delta_f;
00271
00272 Real s;
00273 int j;
00274
00275 maxstep(a, f, delta_a, delta_f, d, &s, &j);
00276
00277 assert(j!=-1);
00278
00279 f += s * delta_f;
00280 a += s * delta_a;
00281
00282 if(C.Contains(j)) {
00283
00284 C.remove(j);
00285 NC.push_back(j);
00286 goto L1;
00287 }
00288 else if(NC.Contains(j)) {
00289
00290 NC.remove(j);
00291 C.push_back(j);
00292 goto L1;
00293 }
00294 else {
00295
00296 C.push_back(j);
00297 }
00298 }
00299
00300 Vector RCTracker::compute_forces(const Matrix &A, const Vector &b) {
00301 Vector f(m_resting_contacts.size(), 0);
00302
00303 Vector a = b;
00304
00305 C.clear();
00306 NC.clear();
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322 int d = 0;
00323
00324 const Real EPSILON = 1e-6;
00325
00326 while(d<a.GetDimension()) {
00327 if(a[d] < -EPSILON) {
00328
00329 drive_to_zero(A, f, a, d);
00330
00331 d = 0;
00332 }
00333 else d++;
00334 }
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348 return f;
00349 }
00350
00351 bool RCTracker::is_inactivated_rc::operator()(Contact &c) const {
00352 c.Update();
00353
00354
00355
00356
00357
00358
00359
00360 return c.m_inactivated ;
00361 }
00362
00363 void RCTracker::remove_inactivated_rc() {
00364 m_resting_contacts.erase(
00365 std::remove_if(m_resting_contacts.begin(), m_resting_contacts.end(), is_inactivated_rc()),
00366 m_resting_contacts.end());
00367 }
00368
00369 void RCTracker::ResolveAll() {
00370
00371 remove_inactivated_rc();
00372
00373 if(m_resting_contacts.size()==0)
00374 return;
00375
00376
00377
00378
00379 Vector f = compute_forces(compute_A_matrix(), compute_b_vector());
00380
00381
00382
00383 Vector v(m_resting_contacts.size());
00384 int i;
00385
00386 for(i=0; i<m_resting_contacts.size(); i++) {
00387 Contact c = m_resting_contacts[i];
00388 c.Update();
00389 v[i] = c.m_n * (c.m_va - c.m_vb);
00390 }
00391
00392
00393
00394
00395 for(i=0; i<m_resting_contacts.size(); i++) {
00396
00397
00398 Contact c = m_resting_contacts[i];
00399
00400 RigidBody *a = c.m_a->GetBody();
00401 RigidBody *b = c.m_b->GetBody();
00402
00403
00404
00405 a->ApplyForce(f[i] * c.m_n, c.m_pa);
00406 b->ApplyForce(-f[i] * c.m_n, c.m_pb);
00407 }
00408
00409
00410
00411 for(i=0; i<m_resting_contacts.size(); i++) {
00412 Contact c = m_resting_contacts[i];
00413 c.Update();
00414 c.CancelNormalVelocity();
00415 v[i] = c.m_n * (c.m_va - c.m_vb);
00416 }
00417
00418
00419 }