00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "joints.h"
00024 #include "common/math/build_basis.h"
00025 #include "common/math/catmullromcurve3.h"
00026 #include "common/math/itl_bicgstab.h"
00027
00028 #include <algorithm>
00029 #include <iostream>
00030
00031 using namespace sheep;
00032
00033 Joint::Joint(int dimension, int body_count) :
00034 m_dimension(dimension),
00035 m_body_count(body_count)
00036 {
00037 assert(m_dimension > 0);
00038 assert(m_body_count > 0);
00039
00040 m_bodies = new RigidBody *[m_body_count];
00041
00042 m_j = new Matrix *[m_body_count];
00043
00044 for(int i = 0; i < m_body_count; i++)
00045 m_j[i] = new Matrix(m_dimension, 6);
00046
00047 m_zero = new Matrix(m_dimension, 6);
00048 *m_zero = 0;
00049
00050 m_c = new Vector(m_dimension);
00051 }
00052
00053 Joint::~Joint() {
00054 delete m_c;
00055
00056 delete m_zero;
00057
00058 for(int i = 0; i < m_body_count; i++)
00059 delete m_j[i];
00060
00061 delete [] m_j;
00062
00063 delete [] m_bodies;
00064 }
00065
00066 SphericalJoint::SphericalJoint(RigidBody *body0, const Vector3 &anchor0,
00067 RigidBody *body1, const Vector3 &anchor1) :
00068 Joint(3, 2)
00069 {
00070 assert(body0 && body1);
00071
00072 m_bodies[0] = body0;
00073 m_bodies[1] = body1;
00074
00075 m_anchor0 = anchor0;
00076 m_anchor1 = anchor1;
00077 }
00078
00079 void SphericalJoint::Update() {
00080 Vector3 a = m_bodies[0]->TransformVectorToWorld(m_anchor0);
00081 Vector3 b = m_bodies[1]->TransformVectorToWorld(m_anchor1);
00082
00083
00084 (*m_j[0])(0, 0) = (*m_j[0])(1, 1) = (*m_j[0])(2, 2) = 1;
00085 (*m_j[0])(0, 1) = (*m_j[0])(1, 0) = 0;
00086 (*m_j[0])(0, 2) = (*m_j[0])(2, 0) = 0;
00087 (*m_j[0])(1, 2) = (*m_j[0])(2, 1) = 0;
00088
00089
00090 (*m_j[0])(0, 3) = 0;
00091 (*m_j[0])(0, 4) = a.m_z;
00092 (*m_j[0])(0, 5) = -a.m_y;
00093 (*m_j[0])(1, 3) = -a.m_z;
00094 (*m_j[0])(1, 4) = 0;
00095 (*m_j[0])(1, 5) = a.m_x;
00096 (*m_j[0])(2, 3) = a.m_y;
00097 (*m_j[0])(2, 4) = -a.m_x;
00098 (*m_j[0])(2, 5) = 0;
00099
00100
00101 (*m_j[1])(0, 0) = (*m_j[1])(1, 1) = (*m_j[1])(2, 2) = -1;
00102 (*m_j[1])(0, 1) = (*m_j[1])(1, 0) = 0;
00103 (*m_j[1])(0, 2) = (*m_j[1])(2, 0) = 0;
00104 (*m_j[1])(1, 2) = (*m_j[1])(2, 1) = 0;
00105
00106
00107 (*m_j[1])(0, 3) = 0;
00108 (*m_j[1])(0, 4) = -b.m_z;
00109 (*m_j[1])(0, 5) = b.m_y;
00110 (*m_j[1])(1, 3) = b.m_z;
00111 (*m_j[1])(1, 4) = 0;
00112 (*m_j[1])(1, 5) = -b.m_x;
00113 (*m_j[1])(2, 3) = -b.m_y;
00114 (*m_j[1])(2, 4) = b.m_x;
00115 (*m_j[1])(2, 5) = 0;
00116
00117 Vector3 omega0 = m_bodies[0]->GetAngularVelocity();
00118 Vector3 omega1 = m_bodies[1]->GetAngularVelocity();
00119
00120 Vector3 t = (omega0 ^ (omega0 ^ a)) - (omega1 ^ (omega1 ^ b));
00121
00122 (*m_c)[0] = t.m_x;
00123 (*m_c)[1] = t.m_y;
00124 (*m_c)[2] = t.m_z;
00125 }
00126
00127 Real SphericalJoint::GetError() {
00128 Vector3 a = m_bodies[0]->TransformPointToWorld(m_anchor0);
00129 Vector3 b = m_bodies[1]->TransformPointToWorld(m_anchor1);
00130
00131 return (a - b).Norm();
00132 }
00133
00134 void SphericalJoint::CorrectError() {
00135 assert(!(m_bodies[0]->IsFrozen() && m_bodies[1]->IsFrozen()));
00136
00137 Vector3 shift = m_bodies[0]->TransformPointToWorld(m_anchor0) -
00138 m_bodies[1]->TransformPointToWorld(m_anchor1);
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169 m_bodies[1]->SetPosition(m_bodies[1]->GetPosition() + shift);
00170 }
00171
00172 FixedPathJoint::FixedPathJoint(RigidBody *body, const Vector3 &anchor,
00173 const Vector3 *ccp, int nccp)
00174 : Joint(2, 1) {
00175 assert(body);
00176
00177 m_bodies[0] = body;
00178
00179 m_anchor = anchor;
00180
00181
00182 m_nccp = nccp + 2;
00183 m_ccp = new Vector3[m_nccp];
00184
00185
00186 for(int i = 0; i < m_nccp - 2; i++)
00187 m_ccp[i + 1] = ccp[i];
00188
00189
00190 m_ccp[0] = 2 * m_ccp[1] - m_ccp[2];
00191 m_ccp[m_nccp - 1] = 2 * m_ccp[m_nccp - 2] - m_ccp[m_nccp - 3];
00192 }
00193
00194 void FixedPathJoint::Update() {
00195 Vector3 a = m_bodies[0]->TransformVectorToWorld(m_anchor);
00196 Vector3 p = m_bodies[0]->TransformPointToWorld(m_anchor);
00197
00198 int seg;
00199 Real t;
00200
00201
00202 project_on_curve(p, &seg, &t);
00203
00204 CatmullRomCurve3 curve(&m_ccp[seg]);
00205
00206 Vector3 i = curve.GetTangentAt(t);
00207 Vector3 j, k;
00208
00209 build_basis(i, &j, &k);
00210
00211
00212
00213
00214
00215
00216 (*m_j[0])(0, 0) = j.m_x;
00217 (*m_j[0])(0, 1) = j.m_y;
00218 (*m_j[0])(0, 2) = j.m_z;
00219 (*m_j[0])(1, 0) = k.m_x;
00220 (*m_j[0])(1, 1) = k.m_y;
00221 (*m_j[0])(1, 2) = k.m_z;
00222
00223
00224
00225
00226
00227
00228 (*m_j[0])(0, 3) = -j.m_y * a.m_z + j.m_z * a.m_y;
00229 (*m_j[0])(0, 4) = j.m_x * a.m_z - j.m_z * a.m_x;
00230 (*m_j[0])(0, 5) = -j.m_x * a.m_y + j.m_y * a.m_x;
00231 (*m_j[0])(1, 3) = -k.m_y * a.m_z + k.m_z * a.m_y;
00232 (*m_j[0])(1, 4) = k.m_x * a.m_z - k.m_z * a.m_x;
00233 (*m_j[0])(1, 5) = -k.m_x * a.m_y + k.m_y * a.m_x;
00234
00235 Vector3 omega = m_bodies[0]->GetAngularVelocity();
00236 Vector3 tmp = omega ^ (omega ^ a);
00237
00238 (*m_c)[0] = j * tmp;
00239 (*m_c)[1] = k * tmp;
00240 }
00241
00242 Real FixedPathJoint::GetError() {
00243
00244 return -1;
00245 }
00246
00247 void FixedPathJoint::CorrectError() {
00248 Vector3 p = m_bodies[0]->TransformPointToWorld(m_anchor);
00249
00250 int seg;
00251 Real t;
00252
00253
00254 project_on_curve(p, &seg, &t);
00255
00256 CatmullRomCurve3 curve(&m_ccp[seg]);
00257
00258 Vector3 shift = curve.GetPointAt(t) - p;
00259
00260
00261
00262 m_bodies[0]->SetPosition(m_bodies[0]->GetPosition() + shift);
00263 }
00264
00265 FixedPathJoint::DistanceFunction::DistanceFunction(const Vector3 *q, const Vector3 &p) {
00266 m_a = 0.5 * (-q[0] + 3 * q[1] - 3 * q[2] + q[3]);
00267 m_b = 0.5 * (2 * q[0] - 5 * q[1] + 4 * q[2] - q[3]);
00268 m_c = 0.5 * (-q[0] + q[2]);
00269 m_d = 0.5 * 2 * q[1];
00270
00271 m_p = p;
00272 }
00273
00274 Real FixedPathJoint::DistanceFunction::EvaluateAt(Real x) const {
00275 return -2 * (m_p - ((m_a * x + m_b) * x + m_c) * x - m_d) * ((3 * m_a * x + 2 * m_b) * x + m_c);
00276 }
00277
00278 void FixedPathJoint::project_on_curve(const Vector3 &p, int *seg, Real *t) const {
00279 Real min_d = 1e6;
00280
00281 for(int i = 0; i < m_nccp - 3; i++) {
00282 DistanceFunction f(&m_ccp[i], p);
00283
00284 const Real EPS = 1e-6;
00285
00286 Real f0 = f.EvaluateAt(0);
00287 Real f1 = f.EvaluateAt(1);
00288
00289 Real t0;
00290
00291 if(fabs(f0) < EPS)
00292 t0 = 0;
00293 else if(fabs(f1) < EPS)
00294 t0 = 1;
00295 else {
00296 if(f0 * f1 > 0)
00297 continue;
00298
00299 t0 = FindRoot(f, 0, 1, EPS);
00300 }
00301
00302 assert(t0 >= 0 && t0 <= 1);
00303
00304 CatmullRomCurve3 curve(&m_ccp[i]);
00305
00306 Vector3 q = curve.GetPointAt(t0);
00307
00308 Real d = (p - q).Norm();
00309
00310 if(d < min_d) {
00311 min_d = d;
00312 *seg = i;
00313 *t = t0;
00314 }
00315 }
00316 }
00317
00318 JointManager::JointManager() {
00319
00320
00321 m_invm = 0;
00322
00323 m_j = 0;
00324 m_c = 0;
00325 m_fext = 0;
00326
00327 m_a = 0;
00328 m_b = 0;
00329 m_lambda = 0;
00330 m_f = 0;
00331 }
00332
00333 void JointManager::Insert(Joint *joint) {
00334 assert(joint);
00335
00336 m_joints.push_back(joint);
00337
00338 int n = joint->GetBodyCount();
00339
00340 for(int i = 0; i < n; i++) {
00341 RigidBody *body = joint->GetBody(i);
00342
00343 if(std::find(m_bodies.begin(), m_bodies.end(), body) == m_bodies.end())
00344 m_bodies.push_back(body);
00345 }
00346 }
00347
00348 void JointManager::Remove(Joint *joint) {
00349 assert(joint);
00350
00351 m_joints.remove(joint);
00352
00353
00354 }
00355
00356 void JointManager::Setup() {
00357 int d = 0;
00358
00359 for(joint_list::const_iterator i = m_joints.begin(); i != m_joints.end(); i++)
00360 d += (*i)->GetDimension();
00361
00362 delete m_invm;
00363 delete m_j;
00364 delete m_c;
00365 delete m_fext;
00366 delete m_a;
00367 delete m_b;
00368 delete m_lambda;
00369 delete m_f;
00370
00371 if(d > 0) {
00372 int n = m_bodies.size();
00373
00374 m_invm = new Matrix(6 * n, 6 * n);
00375 m_j = new Matrix(d, 6 * n);
00376 m_c = new Vector(d);
00377 m_fext = new Vector(6 * n);
00378 m_a = new Matrix(d, d);
00379 m_b = new Vector(d);
00380 m_lambda = new Vector(d);
00381 m_f = new Vector(6 * n);
00382 }
00383 }
00384
00385 void JointManager::ApplyContraints() {
00386
00387 if(m_joints.size() == 0)
00388 return;
00389
00390 rigidbody_list::const_iterator bi;
00391 joint_list::const_iterator ji;
00392 int k, p;
00393
00394
00395
00396 *m_invm = 0;
00397
00398 k = 0;
00399
00400 for(bi = m_bodies.begin(); bi != m_bodies.end(); bi++) {
00401 const RigidBody *body = *bi;
00402
00403 Real inv_mass = body->IsFrozen() ? 0 : 1.0 / body->GetMass();
00404
00405
00406 (*m_invm)(k, k) =
00407 (*m_invm)(k + 1, k + 1) =
00408 (*m_invm)(k + 2, k + 2) = inv_mass;
00409
00410 const Matrix3 inv_iw = body->IsFrozen() ? 0 : (body->GetWorldInertiaTensor()).Inverse();
00411
00412 for(int r = 0; r < 3; r++) {
00413 for(int c = 0; c < 3; c++) {
00414
00415 (*m_invm)(k + 3 + r, k + 3 + c) = inv_iw(r, c);
00416 }
00417 }
00418
00419 k += 6;
00420 }
00421
00422
00423
00424 for(ji = m_joints.begin(); ji != m_joints.end(); ji++) {
00425 (*ji)->Update();
00426 }
00427
00428
00429
00430 p = 0;
00431
00432 for(ji = m_joints.begin(); ji != m_joints.end(); ji++) {
00433 int d = (*ji)->GetDimension();
00434
00435 k = 0;
00436
00437 for(bi = m_bodies.begin(); bi != m_bodies.end(); bi++) {
00438 Matrix *j = (*ji)->GetJ(*bi);
00439
00440 for(int r = 0; r < d; r++) {
00441 for(int c = 0; c < 6; c++) {
00442 (*m_j)(p + r, k + c) = (*j)(r, c);
00443 }
00444 }
00445
00446 k += 6;
00447 }
00448
00449 p += d;
00450 }
00451
00452
00453
00454
00455
00456 p = 0;
00457
00458 for(ji = m_joints.begin(); ji != m_joints.end(); ji++) {
00459 int d = (*ji)->GetDimension();
00460
00461 Vector *c = (*ji)->GetC();
00462
00463 for(int r = 0; r < d; r++)
00464 (*m_c)[p + r] = (*c)[r];
00465
00466 p += d;
00467 }
00468
00469
00470
00471
00472
00473 k = 0;
00474
00475 for(bi = m_bodies.begin(); bi != m_bodies.end(); bi++) {
00476 const Vector3 &f = (*bi)->GetTotalForce();
00477
00478 (*m_fext)[k + 0] = f.m_x;
00479 (*m_fext)[k + 1] = f.m_y;
00480 (*m_fext)[k + 2] = f.m_z;
00481
00482 const Vector3 &t = (*bi)->GetTotalTorque();
00483
00484 (*m_fext)[k + 3] = t.m_x;
00485 (*m_fext)[k + 4] = t.m_y;
00486 (*m_fext)[k + 5] = t.m_z;
00487
00488 k += 6;
00489 }
00490
00491
00492
00493 Matrix j_t = m_j->Transpose();
00494
00495
00496
00497 *m_a = (*m_j) * (*m_invm) * j_t;
00498 *m_b = - ((*m_j) * (*m_invm) * (*m_fext)) - (*m_c);
00499
00500
00501
00502
00503
00504
00505 itl_bicgstab(*m_a, *m_b, m_lambda);
00506
00507
00508
00509 *m_f = j_t * (*m_lambda);
00510
00511
00512
00513 k = 0;
00514
00515 for(bi = m_bodies.begin(); bi != m_bodies.end(); bi++) {
00516 Vector3 f((*m_f)[k + 0], (*m_f)[k + 1], (*m_f)[k + 2]);
00517 Vector3 t((*m_f)[k + 3], (*m_f)[k + 4], (*m_f)[k + 5]);
00518
00519 (*bi)->ApplyForce(f);
00520 (*bi)->ApplyTorque(t);
00521
00522 k += 6;
00523 }
00524
00525
00526
00527 for(joint_list::const_iterator ji = m_joints.begin(); ji != m_joints.end(); ji++) {
00528 Joint *joint = *ji;
00529
00530 joint->CorrectError();
00531 }
00532 }