Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

joints.cpp

Go to the documentation of this file.
00001 /*
00002     Sheep - A Rigid Body Dynamics Engine
00003     Copyright (C) 2001-2004 Francois Beaune
00004     Contact: http://toxicengine.sourceforge.net/
00005 
00006     This file is part of Sheep.
00007 
00008     Sheep is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     Sheep is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with Sheep; if not, write to the Free Software
00020     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021 */
00022 
00023 #include "joints.h" // include first
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) // dimension 3, 2 bodies involved
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     // j_{1L} = 1_3
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     // j_{1A} = -a^*
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     // j_{2L} = -1_3
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     // j_{2A} = b^*
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     // Velocity correction.
00141 
00142 /*  if(shift.SquareNorm() > 1e-12) {
00143         Vector3 u = shift.Normalized();
00144 
00145         std::cerr << "u.Norm()=" << u.Norm() << std::endl;
00146 
00147         Vector3 rb = m_body2->TransformVectorToWorld(m_anchor2);
00148 
00149         Vector3 k = (u / m_body2->GetMass() + m_body2->GetWorldInertiaTensor().Inverse() * (rb ^ u)) ^ rb;
00150 
00151         const Real H = 0.01;
00152         
00153         Real j_mag = ((shift / H - m_body2->GetPointVelocity(m_anchor2)) * k) / k.SquareNorm();
00154 
00155         std::cerr << "j_mag=" << j_mag << std::endl;
00156 
00157         Vector3 j = j_mag * u;
00158 
00159         m_body2->ApplyLinearImpulse(j);
00160         m_body2->ApplyAngularImpulse(rb ^ j);
00161     }*/
00162 
00163 //  const Real H = 0.01;
00164 
00165 //  m_body2->ApplyLinearImpulse(shift / H);
00166 
00167     // Position correction.
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) {     // dimension 2, only 1 body involved (plus a curve).
00175     assert(body);
00176 
00177     m_bodies[0] = body;
00178 
00179     m_anchor = anchor;
00180 
00181     // Compute the number of control points and allocate them.
00182     m_nccp = nccp + 2;      // we need two additional control points
00183     m_ccp = new Vector3[m_nccp];
00184 
00185     // Copy the control points (this is a safety measure).
00186     for(int i = 0; i < m_nccp - 2; i++)
00187         m_ccp[i + 1] = ccp[i];
00188 
00189     // Compute the two additional control points.
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     // Compute location of the body on the curve.
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     // j_{1L} = \begin{pmatrix}
00212     //   \vec{j}\transpose \\
00213     //   \vec{k}\transpose \\
00214     // \end{pmatrix}
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     // j_{1A} = \begin{pmatrix}
00224     //   - \vec{j}\transpose a^* \\
00225     //   - \vec{k}\transpose a^* \\
00226     // \end{pmatrix}
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     //!\todo Implement?
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     // Compute location of the body on the curve.
00254     project_on_curve(p, &seg, &t);
00255 
00256     CatmullRomCurve3 curve(&m_ccp[seg]);
00257 
00258     Vector3 shift = curve.GetPointAt(t) - p;
00259 
00260     // Position correction.
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 //  debug = new HTMLStream("jointmanager.html");
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     //!\todo Remove unused bodies from the 'm_bodies' list.
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     //!\todo This is a quick hack for Sheep Lab.
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     // Compute the M matrix.
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         // {m_k}^{-1}.
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                 // {I_k}^{-1}.
00415                 (*m_invm)(k + 3 + r, k + 3 + c) = inv_iw(r, c);
00416             }
00417         }
00418 
00419         k += 6;
00420     }
00421 
00422 //  *debug << "M^(-1) matrix: " << *m_invm;
00423 
00424     for(ji = m_joints.begin(); ji != m_joints.end(); ji++) {
00425         (*ji)->Update();
00426     }
00427 
00428     // Compute the J matrix.
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 //  *debug << "J matrix: " << *m_j;
00453 
00454     // Compute the C vector.
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 //  *debug << "C vector: " << *m_c;
00470 
00471     // Compute the F^{ext} vector.
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 //  *debug << "Fext vector: " << *m_fext;
00492 
00493     Matrix j_t = m_j->Transpose();
00494 
00495     // Form the linear system to be solved.
00496 
00497     *m_a = (*m_j) * (*m_invm) * j_t;
00498     *m_b = - ((*m_j) * (*m_invm) * (*m_fext)) - (*m_c);
00499 
00500 //  *debug << "A matrix: " << *m_a;
00501 //  *debug << "B vector: " << *m_b;
00502 
00503     // Solve the system.
00504 //  *m_lambda = m_a->Inverse() * (*m_b);
00505     itl_bicgstab(*m_a, *m_b, m_lambda);
00506 
00507 //  *debug << "Lambda vector: " << *m_lambda << std::endl;
00508 
00509     *m_f = j_t * (*m_lambda);
00510 
00511 //  *debug << "F vector: " << *m_f;
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     // Error reduction step.
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 }

Generated on Tue May 11 01:31:50 2004 for toxic by doxygen 1.3.6