From fca74b0bf0a0833f5701e9c0de7b3bc15b2233dd Mon Sep 17 00:00:00 2001 From: dan miller Date: Fri, 19 Oct 2007 05:20:07 +0000 Subject: dont ask --- libraries/ode-0.9/ode/src/stepfast.cpp | 1139 -------------------------------- 1 file changed, 1139 deletions(-) delete mode 100755 libraries/ode-0.9/ode/src/stepfast.cpp (limited to 'libraries/ode-0.9/ode/src/stepfast.cpp') diff --git a/libraries/ode-0.9/ode/src/stepfast.cpp b/libraries/ode-0.9/ode/src/stepfast.cpp deleted file mode 100755 index 35c45db..0000000 --- a/libraries/ode-0.9/ode/src/stepfast.cpp +++ /dev/null @@ -1,1139 +0,0 @@ -/************************************************************************* - * * - * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * - * All rights reserved. Email: russ@q12.org Web: www.q12.org * - * * - * Fast iterative solver, David Whittaker. Email: david@csworkbench.com * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of EITHER: * - * (1) The GNU Lesser General Public License as published by the Free * - * Software Foundation; either version 2.1 of the License, or (at * - * your option) any later version. The text of the GNU Lesser * - * General Public License is included with this library in the * - * file LICENSE.TXT. * - * (2) The BSD-style license that is included with this library in * - * the file LICENSE-BSD.TXT. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * - * LICENSE.TXT and LICENSE-BSD.TXT for more details. * - * * - *************************************************************************/ - -// This is the StepFast code by David Whittaker. This code is faster, but -// sometimes less stable than, the original "big matrix" code. -// Refer to the user's manual for more information. -// Note that this source file duplicates a lot of stuff from step.cpp, -// eventually we should move the common code to a third file. - -#include "objects.h" -#include "joint.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include "lcp.h" -#include "step.h" -#include "util.h" - - -// misc defines - -#define ALLOCA dALLOCA16 - -#define RANDOM_JOINT_ORDER -//#define FAST_FACTOR //use a factorization approximation to the LCP solver (fast, theoretically less accurate) -#define SLOW_LCP //use the old LCP solver -//#define NO_ISLANDS //does not perform island creation code (3~4% of simulation time), body disabling doesn't work -//#define TIMING - - -static int autoEnableDepth = 2; - -void dWorldSetAutoEnableDepthSF1 (dxWorld *world, int autodepth) -{ - if (autodepth > 0) - autoEnableDepth = autodepth; - else - autoEnableDepth = 0; -} - -int dWorldGetAutoEnableDepthSF1 (dxWorld *world) -{ - return autoEnableDepth; -} - -//little bit of math.... the _sym_ functions assume the return matrix will be symmetric -static void -Multiply2_sym_p8p (dReal * A, dReal * B, dReal * C, int p, int Askip) -{ - int i, j; - dReal sum, *aa, *ad, *bb, *cc; - dIASSERT (p > 0 && A && B && C); - bb = B; - for (i = 0; i < p; i++) - { - //aa is going accross the matrix, ad down - aa = ad = A; - cc = C; - for (j = i; j < p; j++) - { - sum = bb[0] * cc[0]; - sum += bb[1] * cc[1]; - sum += bb[2] * cc[2]; - sum += bb[4] * cc[4]; - sum += bb[5] * cc[5]; - sum += bb[6] * cc[6]; - *(aa++) = *ad = sum; - ad += Askip; - cc += 8; - } - bb += 8; - A += Askip + 1; - C += 8; - } -} - -static void -MultiplyAdd2_sym_p8p (dReal * A, dReal * B, dReal * C, int p, int Askip) -{ - int i, j; - dReal sum, *aa, *ad, *bb, *cc; - dIASSERT (p > 0 && A && B && C); - bb = B; - for (i = 0; i < p; i++) - { - //aa is going accross the matrix, ad down - aa = ad = A; - cc = C; - for (j = i; j < p; j++) - { - sum = bb[0] * cc[0]; - sum += bb[1] * cc[1]; - sum += bb[2] * cc[2]; - sum += bb[4] * cc[4]; - sum += bb[5] * cc[5]; - sum += bb[6] * cc[6]; - *(aa++) += sum; - *ad += sum; - ad += Askip; - cc += 8; - } - bb += 8; - A += Askip + 1; - C += 8; - } -} - - -// this assumes the 4th and 8th rows of B are zero. - -static void -Multiply0_p81 (dReal * A, dReal * B, dReal * C, int p) -{ - int i; - dIASSERT (p > 0 && A && B && C); - dReal sum; - for (i = p; i; i--) - { - sum = B[0] * C[0]; - sum += B[1] * C[1]; - sum += B[2] * C[2]; - sum += B[4] * C[4]; - sum += B[5] * C[5]; - sum += B[6] * C[6]; - *(A++) = sum; - B += 8; - } -} - - -// this assumes the 4th and 8th rows of B are zero. - -static void -MultiplyAdd0_p81 (dReal * A, dReal * B, dReal * C, int p) -{ - int i; - dIASSERT (p > 0 && A && B && C); - dReal sum; - for (i = p; i; i--) - { - sum = B[0] * C[0]; - sum += B[1] * C[1]; - sum += B[2] * C[2]; - sum += B[4] * C[4]; - sum += B[5] * C[5]; - sum += B[6] * C[6]; - *(A++) += sum; - B += 8; - } -} - - -// this assumes the 4th and 8th rows of B are zero. - -static void -Multiply1_8q1 (dReal * A, dReal * B, dReal * C, int q) -{ - int k; - dReal sum; - dIASSERT (q > 0 && A && B && C); - sum = 0; - for (k = 0; k < q; k++) - sum += B[k * 8] * C[k]; - A[0] = sum; - sum = 0; - for (k = 0; k < q; k++) - sum += B[1 + k * 8] * C[k]; - A[1] = sum; - sum = 0; - for (k = 0; k < q; k++) - sum += B[2 + k * 8] * C[k]; - A[2] = sum; - sum = 0; - for (k = 0; k < q; k++) - sum += B[4 + k * 8] * C[k]; - A[4] = sum; - sum = 0; - for (k = 0; k < q; k++) - sum += B[5 + k * 8] * C[k]; - A[5] = sum; - sum = 0; - for (k = 0; k < q; k++) - sum += B[6 + k * 8] * C[k]; - A[6] = sum; -} - -//**************************************************************************** -// body rotation - -// return sin(x)/x. this has a singularity at 0 so special handling is needed -// for small arguments. - -static inline dReal -sinc (dReal x) -{ - // if |x| < 1e-4 then use a taylor series expansion. this two term expansion - // is actually accurate to one LS bit within this range if double precision - // is being used - so don't worry! - if (dFabs (x) < 1.0e-4) - return REAL (1.0) - x * x * REAL (0.166666666666666666667); - else - return dSin (x) / x; -} - - -// given a body b, apply its linear and angular rotation over the time -// interval h, thereby adjusting its position and orientation. - -static inline void -moveAndRotateBody (dxBody * b, dReal h) -{ - int j; - - // handle linear velocity - for (j = 0; j < 3; j++) - b->posr.pos[j] += h * b->lvel[j]; - - if (b->flags & dxBodyFlagFiniteRotation) - { - dVector3 irv; // infitesimal rotation vector - dQuaternion q; // quaternion for finite rotation - - if (b->flags & dxBodyFlagFiniteRotationAxis) - { - // split the angular velocity vector into a component along the finite - // rotation axis, and a component orthogonal to it. - dVector3 frv, irv; // finite rotation vector - dReal k = dDOT (b->finite_rot_axis, b->avel); - frv[0] = b->finite_rot_axis[0] * k; - frv[1] = b->finite_rot_axis[1] * k; - frv[2] = b->finite_rot_axis[2] * k; - irv[0] = b->avel[0] - frv[0]; - irv[1] = b->avel[1] - frv[1]; - irv[2] = b->avel[2] - frv[2]; - - // make a rotation quaternion q that corresponds to frv * h. - // compare this with the full-finite-rotation case below. - h *= REAL (0.5); - dReal theta = k * h; - q[0] = dCos (theta); - dReal s = sinc (theta) * h; - q[1] = frv[0] * s; - q[2] = frv[1] * s; - q[3] = frv[2] * s; - } - else - { - // make a rotation quaternion q that corresponds to w * h - dReal wlen = dSqrt (b->avel[0] * b->avel[0] + b->avel[1] * b->avel[1] + b->avel[2] * b->avel[2]); - h *= REAL (0.5); - dReal theta = wlen * h; - q[0] = dCos (theta); - dReal s = sinc (theta) * h; - q[1] = b->avel[0] * s; - q[2] = b->avel[1] * s; - q[3] = b->avel[2] * s; - } - - // do the finite rotation - dQuaternion q2; - dQMultiply0 (q2, q, b->q); - for (j = 0; j < 4; j++) - b->q[j] = q2[j]; - - // do the infitesimal rotation if required - if (b->flags & dxBodyFlagFiniteRotationAxis) - { - dReal dq[4]; - dWtoDQ (irv, b->q, dq); - for (j = 0; j < 4; j++) - b->q[j] += h * dq[j]; - } - } - else - { - // the normal way - do an infitesimal rotation - dReal dq[4]; - dWtoDQ (b->avel, b->q, dq); - for (j = 0; j < 4; j++) - b->q[j] += h * dq[j]; - } - - // normalize the quaternion and convert it to a rotation matrix - dNormalize4 (b->q); - dQtoR (b->q, b->posr.R); - - // notify all attached geoms that this body has moved - for (dxGeom * geom = b->geom; geom; geom = dGeomGetBodyNext (geom)) - dGeomMoved (geom); -} - -//**************************************************************************** -//This is an implementation of the iterated/relaxation algorithm. -//Here is a quick overview of the algorithm per Sergi Valverde's posts to the -//mailing list: -// -// for i=0..N-1 do -// for c = 0..C-1 do -// Solve constraint c-th -// Apply forces to constraint bodies -// next -// next -// Integrate bodies - -void -dInternalStepFast (dxWorld * world, dxBody * body[2], dReal * GI[2], dReal * GinvI[2], dxJoint * joint, dxJoint::Info1 info, dxJoint::Info2 Jinfo, dReal stepsize) -{ - int i, j, k; -# ifdef TIMING - dTimerNow ("constraint preprocessing"); -# endif - - dReal stepsize1 = dRecip (stepsize); - - int m = info.m; - // nothing to do if no constraints. - if (m <= 0) - return; - - int nub = 0; - if (info.nub == info.m) - nub = m; - - // compute A = J*invM*J'. first compute JinvM = J*invM. this has the same - // format as J so we just go through the constraints in J multiplying by - // the appropriate scalars and matrices. -# ifdef TIMING - dTimerNow ("compute A"); -# endif - dReal JinvM[2 * 6 * 8]; - //dSetZero (JinvM, 2 * m * 8); - - dReal *Jsrc = Jinfo.J1l; - dReal *Jdst = JinvM; - if (body[0]) - { - for (j = m - 1; j >= 0; j--) - { - for (k = 0; k < 3; k++) - Jdst[k] = Jsrc[k] * body[0]->invMass; - dMULTIPLY0_133 (Jdst + 4, Jsrc + 4, GinvI[0]); - Jsrc += 8; - Jdst += 8; - } - } - if (body[1]) - { - Jsrc = Jinfo.J2l; - Jdst = JinvM + 8 * m; - for (j = m - 1; j >= 0; j--) - { - for (k = 0; k < 3; k++) - Jdst[k] = Jsrc[k] * body[1]->invMass; - dMULTIPLY0_133 (Jdst + 4, Jsrc + 4, GinvI[1]); - Jsrc += 8; - Jdst += 8; - } - } - - - // now compute A = JinvM * J'. - int mskip = dPAD (m); - dReal A[6 * 8]; - //dSetZero (A, 6 * 8); - - if (body[0]) { - Multiply2_sym_p8p (A, JinvM, Jinfo.J1l, m, mskip); - if (body[1]) - MultiplyAdd2_sym_p8p (A, JinvM + 8 * m, Jinfo.J2l, - m, mskip); - } else { - if (body[1]) - Multiply2_sym_p8p (A, JinvM + 8 * m, Jinfo.J2l, - m, mskip); - } - - // add cfm to the diagonal of A - for (i = 0; i < m; i++) - A[i * mskip + i] += Jinfo.cfm[i] * stepsize1; - - // compute the right hand side `rhs' -# ifdef TIMING - dTimerNow ("compute rhs"); -# endif - dReal tmp1[16]; - //dSetZero (tmp1, 16); - // put v/h + invM*fe into tmp1 - for (i = 0; i < 2; i++) - { - if (!body[i]) - continue; - for (j = 0; j < 3; j++) - tmp1[i * 8 + j] = body[i]->facc[j] * body[i]->invMass + body[i]->lvel[j] * stepsize1; - dMULTIPLY0_331 (tmp1 + i * 8 + 4, GinvI[i], body[i]->tacc); - for (j = 0; j < 3; j++) - tmp1[i * 8 + 4 + j] += body[i]->avel[j] * stepsize1; - } - // put J*tmp1 into rhs - dReal rhs[6]; - //dSetZero (rhs, 6); - - if (body[0]) { - Multiply0_p81 (rhs, Jinfo.J1l, tmp1, m); - if (body[1]) - MultiplyAdd0_p81 (rhs, Jinfo.J2l, tmp1 + 8, m); - } else { - if (body[1]) - Multiply0_p81 (rhs, Jinfo.J2l, tmp1 + 8, m); - } - - // complete rhs - for (i = 0; i < m; i++) - rhs[i] = Jinfo.c[i] * stepsize1 - rhs[i]; - -#ifdef SLOW_LCP - // solve the LCP problem and get lambda. - // this will destroy A but that's okay -# ifdef TIMING - dTimerNow ("solving LCP problem"); -# endif - dReal *lambda = (dReal *) ALLOCA (m * sizeof (dReal)); - dReal *residual = (dReal *) ALLOCA (m * sizeof (dReal)); - dReal lo[6], hi[6]; - memcpy (lo, Jinfo.lo, m * sizeof (dReal)); - memcpy (hi, Jinfo.hi, m * sizeof (dReal)); - dSolveLCP (m, A, lambda, rhs, residual, nub, lo, hi, Jinfo.findex); -#endif - - // LCP Solver replacement: - // This algorithm goes like this: - // Do a straightforward LDLT factorization of the matrix A, solving for - // A*x = rhs - // For each x[i] that is outside of the bounds of lo[i] and hi[i], - // clamp x[i] into that range. - // Substitute into A the now known x's - // subtract the residual away from the rhs. - // Remove row and column i from L, updating the factorization - // place the known x's at the end of the array, keeping up with location in p - // Repeat until all constraints have been clamped or all are within bounds - // - // This is probably only faster in the single joint case where only one repeat is - // the norm. - -#ifdef FAST_FACTOR - // factorize A (L*D*L'=A) -# ifdef TIMING - dTimerNow ("factorize A"); -# endif - dReal d[6]; - dReal L[6 * 8]; - memcpy (L, A, m * mskip * sizeof (dReal)); - dFactorLDLT (L, d, m, mskip); - - // compute lambda -# ifdef TIMING - dTimerNow ("compute lambda"); -# endif - - int left = m; //constraints left to solve. - int remove[6]; - dReal lambda[6]; - dReal x[6]; - int p[6]; - for (i = 0; i < 6; i++) - p[i] = i; - while (true) - { - memcpy (x, rhs, left * sizeof (dReal)); - dSolveLDLT (L, d, x, left, mskip); - - int fixed = 0; - for (i = 0; i < left; i++) - { - j = p[i]; - remove[i] = false; - // This isn't the exact same use of findex as dSolveLCP.... since x[findex] - // may change after I've already clamped x[i], but it should be close - if (Jinfo.findex[j] > -1) - { - dReal f = fabs (Jinfo.hi[j] * x[p[Jinfo.findex[j]]]); - if (x[i] > f) - x[i] = f; - else if (x[i] < -f) - x[i] = -f; - else - continue; - } - else - { - if (x[i] > Jinfo.hi[j]) - x[i] = Jinfo.hi[j]; - else if (x[i] < Jinfo.lo[j]) - x[i] = Jinfo.lo[j]; - else - continue; - } - remove[i] = true; - fixed++; - } - if (fixed == 0 || fixed == left) //no change or all constraints solved - break; - - for (i = 0; i < left; i++) //sub in to right hand side. - if (remove[i]) - for (j = 0; j < left; j++) - if (!remove[j]) - rhs[j] -= A[j * mskip + i] * x[i]; - - for (int r = left - 1; r >= 0; r--) //eliminate row/col for fixed variables - { - if (remove[r]) - { - //dRemoveLDLT adapted for use without row pointers. - if (r == left - 1) - { - left--; - continue; // deleting last row/col is easy - } - else if (r == 0) - { - dReal a[6]; - for (i = 0; i < left; i++) - a[i] = -A[i * mskip]; - a[0] += REAL (1.0); - dLDLTAddTL (L, d, a, left, mskip); - } - else - { - dReal t[6]; - dReal a[6]; - for (i = 0; i < r; i++) - t[i] = L[r * mskip + i] / d[i]; - for (i = 0; i < left - r; i++) - a[i] = dDot (L + (r + i) * mskip, t, r) - A[(r + i) * mskip + r]; - a[0] += REAL (1.0); - dLDLTAddTL (L + r * mskip + r, d + r, a, left - r, mskip); - } - - dRemoveRowCol (L, left, mskip, r); - //end dRemoveLDLT - - left--; - if (r < (left - 1)) - { - dReal tx = x[r]; - memmove (d + r, d + r + 1, (left - r) * sizeof (dReal)); - memmove (rhs + r, rhs + r + 1, (left - r) * sizeof (dReal)); - //x will get written over by rhs anyway, no need to move it around - //just store the fixed value we just discovered in it. - x[left] = tx; - for (i = 0; i < m; i++) - if (p[i] > r && p[i] <= left) - p[i]--; - p[r] = left; - } - } - } - } - - for (i = 0; i < m; i++) - lambda[i] = x[p[i]]; -# endif - // compute the constraint force `cforce' -# ifdef TIMING - dTimerNow ("compute constraint force"); -#endif - - // compute cforce = J'*lambda - dJointFeedback *fb = joint->feedback; - dReal cforce[16]; - //dSetZero (cforce, 16); - - if (fb) - { - // the user has requested feedback on the amount of force that this - // joint is applying to the bodies. we use a slightly slower - // computation that splits out the force components and puts them - // in the feedback structure. - dReal data1[8], data2[8]; - if (body[0]) - { - Multiply1_8q1 (data1, Jinfo.J1l, lambda, m); - dReal *cf1 = cforce; - cf1[0] = (fb->f1[0] = data1[0]); - cf1[1] = (fb->f1[1] = data1[1]); - cf1[2] = (fb->f1[2] = data1[2]); - cf1[4] = (fb->t1[0] = data1[4]); - cf1[5] = (fb->t1[1] = data1[5]); - cf1[6] = (fb->t1[2] = data1[6]); - } - if (body[1]) - { - Multiply1_8q1 (data2, Jinfo.J2l, lambda, m); - dReal *cf2 = cforce + 8; - cf2[0] = (fb->f2[0] = data2[0]); - cf2[1] = (fb->f2[1] = data2[1]); - cf2[2] = (fb->f2[2] = data2[2]); - cf2[4] = (fb->t2[0] = data2[4]); - cf2[5] = (fb->t2[1] = data2[5]); - cf2[6] = (fb->t2[2] = data2[6]); - } - } - else - { - // no feedback is required, let's compute cforce the faster way - if (body[0]) - Multiply1_8q1 (cforce, Jinfo.J1l, lambda, m); - if (body[1]) - Multiply1_8q1 (cforce + 8, Jinfo.J2l, lambda, m); - } - - for (i = 0; i < 2; i++) - { - if (!body[i]) - continue; - for (j = 0; j < 3; j++) - { - body[i]->facc[j] += cforce[i * 8 + j]; - body[i]->tacc[j] += cforce[i * 8 + 4 + j]; - } - } -} - -void -dInternalStepIslandFast (dxWorld * world, dxBody * const *bodies, int nb, dxJoint * const *_joints, int nj, dReal stepsize, int maxiterations) -{ -# ifdef TIMING - dTimerNow ("preprocessing"); -# endif - dxBody *bodyPair[2], *body; - dReal *GIPair[2], *GinvIPair[2]; - dxJoint *joint; - int iter, b, j, i; - dReal ministep = stepsize / maxiterations; - - // make a local copy of the joint array, because we might want to modify it. - // (the "dxJoint *const*" declaration says we're allowed to modify the joints - // but not the joint array, because the caller might need it unchanged). - dxJoint **joints = (dxJoint **) ALLOCA (nj * sizeof (dxJoint *)); - memcpy (joints, _joints, nj * sizeof (dxJoint *)); - - // get m = total constraint dimension, nub = number of unbounded variables. - // create constraint offset array and number-of-rows array for all joints. - // the constraints are re-ordered as follows: the purely unbounded - // constraints, the mixed unbounded + LCP constraints, and last the purely - // LCP constraints. this assists the LCP solver to put all unbounded - // variables at the start for a quick factorization. - // - // joints with m=0 are inactive and are removed from the joints array - // entirely, so that the code that follows does not consider them. - // also number all active joints in the joint list (set their tag values). - // inactive joints receive a tag value of -1. - - int m = 0; - dxJoint::Info1 * info = (dxJoint::Info1 *) ALLOCA (nj * sizeof (dxJoint::Info1)); - int *ofs = (int *) ALLOCA (nj * sizeof (int)); - for (i = 0, j = 0; j < nj; j++) - { // i=dest, j=src - joints[j]->vtable->getInfo1 (joints[j], info + i); - dIASSERT (info[i].m >= 0 && info[i].m <= 6 && info[i].nub >= 0 && info[i].nub <= info[i].m); - if (info[i].m > 0) - { - joints[i] = joints[j]; - joints[i]->tag = i; - i++; - } - else - { - joints[j]->tag = -1; - } - } - nj = i; - - // the purely unbounded constraints - for (i = 0; i < nj; i++) - { - ofs[i] = m; - m += info[i].m; - } - dReal *c = NULL; - dReal *cfm = NULL; - dReal *lo = NULL; - dReal *hi = NULL; - int *findex = NULL; - - dReal *J = NULL; - dxJoint::Info2 * Jinfo = NULL; - - if (m) - { - // create a constraint equation right hand side vector `c', a constraint - // force mixing vector `cfm', and LCP low and high bound vectors, and an - // 'findex' vector. - c = (dReal *) ALLOCA (m * sizeof (dReal)); - cfm = (dReal *) ALLOCA (m * sizeof (dReal)); - lo = (dReal *) ALLOCA (m * sizeof (dReal)); - hi = (dReal *) ALLOCA (m * sizeof (dReal)); - findex = (int *) ALLOCA (m * sizeof (int)); - dSetZero (c, m); - dSetValue (cfm, m, world->global_cfm); - dSetValue (lo, m, -dInfinity); - dSetValue (hi, m, dInfinity); - for (i = 0; i < m; i++) - findex[i] = -1; - - // get jacobian data from constraints. a (2*m)x8 matrix will be created - // to store the two jacobian blocks from each constraint. it has this - // format: - // - // l l l 0 a a a 0 \ . - // l l l 0 a a a 0 }-- jacobian body 1 block for joint 0 (3 rows) - // l l l 0 a a a 0 / - // l l l 0 a a a 0 \ . - // l l l 0 a a a 0 }-- jacobian body 2 block for joint 0 (3 rows) - // l l l 0 a a a 0 / - // l l l 0 a a a 0 }--- jacobian body 1 block for joint 1 (1 row) - // l l l 0 a a a 0 }--- jacobian body 2 block for joint 1 (1 row) - // etc... - // - // (lll) = linear jacobian data - // (aaa) = angular jacobian data - // -# ifdef TIMING - dTimerNow ("create J"); -# endif - J = (dReal *) ALLOCA (2 * m * 8 * sizeof (dReal)); - dSetZero (J, 2 * m * 8); - Jinfo = (dxJoint::Info2 *) ALLOCA (nj * sizeof (dxJoint::Info2)); - for (i = 0; i < nj; i++) - { - Jinfo[i].rowskip = 8; - Jinfo[i].fps = dRecip (stepsize); - Jinfo[i].erp = world->global_erp; - Jinfo[i].J1l = J + 2 * 8 * ofs[i]; - Jinfo[i].J1a = Jinfo[i].J1l + 4; - Jinfo[i].J2l = Jinfo[i].J1l + 8 * info[i].m; - Jinfo[i].J2a = Jinfo[i].J2l + 4; - Jinfo[i].c = c + ofs[i]; - Jinfo[i].cfm = cfm + ofs[i]; - Jinfo[i].lo = lo + ofs[i]; - Jinfo[i].hi = hi + ofs[i]; - Jinfo[i].findex = findex + ofs[i]; - //joints[i]->vtable->getInfo2 (joints[i], Jinfo+i); - } - - } - - dReal *saveFacc = (dReal *) ALLOCA (nb * 4 * sizeof (dReal)); - dReal *saveTacc = (dReal *) ALLOCA (nb * 4 * sizeof (dReal)); - dReal *globalI = (dReal *) ALLOCA (nb * 12 * sizeof (dReal)); - dReal *globalInvI = (dReal *) ALLOCA (nb * 12 * sizeof (dReal)); - for (b = 0; b < nb; b++) - { - for (i = 0; i < 4; i++) - { - saveFacc[b * 4 + i] = bodies[b]->facc[i]; - saveTacc[b * 4 + i] = bodies[b]->tacc[i]; - } - bodies[b]->tag = b; - } - - for (iter = 0; iter < maxiterations; iter++) - { -# ifdef TIMING - dTimerNow ("applying inertia and gravity"); -# endif - dReal tmp[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - - for (b = 0; b < nb; b++) - { - body = bodies[b]; - - // for all bodies, compute the inertia tensor and its inverse in the global - // frame, and compute the rotational force and add it to the torque - // accumulator. I and invI are vertically stacked 3x4 matrices, one per body. - // @@@ check computation of rotational force. - - // compute inertia tensor in global frame - dMULTIPLY2_333 (tmp, body->mass.I, body->posr.R); - dMULTIPLY0_333 (globalI + b * 12, body->posr.R, tmp); - // compute inverse inertia tensor in global frame - dMULTIPLY2_333 (tmp, body->invI, body->posr.R); - dMULTIPLY0_333 (globalInvI + b * 12, body->posr.R, tmp); - - for (i = 0; i < 4; i++) - body->tacc[i] = saveTacc[b * 4 + i]; -#ifdef dGYROSCOPIC - // compute rotational force - dMULTIPLY0_331 (tmp, globalI + b * 12, body->avel); - dCROSS (body->tacc, -=, body->avel, tmp); -#endif - - // add the gravity force to all bodies - if ((body->flags & dxBodyNoGravity) == 0) - { - body->facc[0] = saveFacc[b * 4 + 0] + body->mass.mass * world->gravity[0]; - body->facc[1] = saveFacc[b * 4 + 1] + body->mass.mass * world->gravity[1]; - body->facc[2] = saveFacc[b * 4 + 2] + body->mass.mass * world->gravity[2]; - body->facc[3] = 0; - } else { - body->facc[0] = saveFacc[b * 4 + 0]; - body->facc[1] = saveFacc[b * 4 + 1]; - body->facc[2] = saveFacc[b * 4 + 2]; - body->facc[3] = 0; - } - - } - -#ifdef RANDOM_JOINT_ORDER -#ifdef TIMING - dTimerNow ("randomizing joint order"); -#endif - //randomize the order of the joints by looping through the array - //and swapping the current joint pointer with a random one before it. - for (j = 0; j < nj; j++) - { - joint = joints[j]; - dxJoint::Info1 i1 = info[j]; - dxJoint::Info2 i2 = Jinfo[j]; - const int r = dRandInt(j+1); - dIASSERT (r < nj); - joints[j] = joints[r]; - info[j] = info[r]; - Jinfo[j] = Jinfo[r]; - joints[r] = joint; - info[r] = i1; - Jinfo[r] = i2; - } -#endif - - //now iterate through the random ordered joint array we created. - for (j = 0; j < nj; j++) - { -#ifdef TIMING - dTimerNow ("setting up joint"); -#endif - joint = joints[j]; - bodyPair[0] = joint->node[0].body; - bodyPair[1] = joint->node[1].body; - - if (bodyPair[0] && (bodyPair[0]->flags & dxBodyDisabled)) - bodyPair[0] = 0; - if (bodyPair[1] && (bodyPair[1]->flags & dxBodyDisabled)) - bodyPair[1] = 0; - - //if this joint is not connected to any enabled bodies, skip it. - if (!bodyPair[0] && !bodyPair[1]) - continue; - - if (bodyPair[0]) - { - GIPair[0] = globalI + bodyPair[0]->tag * 12; - GinvIPair[0] = globalInvI + bodyPair[0]->tag * 12; - } - if (bodyPair[1]) - { - GIPair[1] = globalI + bodyPair[1]->tag * 12; - GinvIPair[1] = globalInvI + bodyPair[1]->tag * 12; - } - - joints[j]->vtable->getInfo2 (joints[j], Jinfo + j); - - //dInternalStepIslandFast is an exact copy of the old routine with one - //modification: the calculated forces are added back to the facc and tacc - //vectors instead of applying them to the bodies and moving them. - if (info[j].m > 0) - { - dInternalStepFast (world, bodyPair, GIPair, GinvIPair, joint, info[j], Jinfo[j], ministep); - } - } - // } -# ifdef TIMING - dTimerNow ("moving bodies"); -# endif - //Now we can simulate all the free floating bodies, and move them. - for (b = 0; b < nb; b++) - { - body = bodies[b]; - - for (i = 0; i < 4; i++) - { - body->facc[i] *= ministep; - body->tacc[i] *= ministep; - } - - //apply torque - dMULTIPLYADD0_331 (body->avel, globalInvI + b * 12, body->tacc); - - //apply force - for (i = 0; i < 3; i++) - body->lvel[i] += body->invMass * body->facc[i]; - - //move It! - moveAndRotateBody (body, ministep); - } - } - for (b = 0; b < nb; b++) - for (j = 0; j < 4; j++) - bodies[b]->facc[j] = bodies[b]->tacc[j] = 0; -} - - -#ifdef NO_ISLANDS - -// Since the iterative algorithm doesn't care about islands of bodies, this is a -// faster algorithm that just sends it all the joints and bodies in one array. -// It's downfall is it's inability to handle disabled bodies as well as the old one. -static void -processIslandsFast (dxWorld * world, dReal stepsize, int maxiterations) -{ - // nothing to do if no bodies - if (world->nb <= 0) - return; - - dInternalHandleAutoDisabling (world,stepsize); - -# ifdef TIMING - dTimerStart ("creating joint and body arrays"); -# endif - dxBody **bodies, *body; - dxJoint **joints, *joint; - joints = (dxJoint **) ALLOCA (world->nj * sizeof (dxJoint *)); - bodies = (dxBody **) ALLOCA (world->nb * sizeof (dxBody *)); - - int nj = 0; - for (joint = world->firstjoint; joint; joint = (dxJoint *) joint->next) - joints[nj++] = joint; - - int nb = 0; - for (body = world->firstbody; body; body = (dxBody *) body->next) - bodies[nb++] = body; - - dInternalStepIslandFast (world, bodies, nb, joints, nj, stepsize, maxiterations); -# ifdef TIMING - dTimerEnd (); - dTimerReport (stdout, 1); -# endif -} - -#else - -//**************************************************************************** -// island processing - -// this groups all joints and bodies in a world into islands. all objects -// in an island are reachable by going through connected bodies and joints. -// each island can be simulated separately. -// note that joints that are not attached to anything will not be included -// in any island, an so they do not affect the simulation. -// -// this function starts new island from unvisited bodies. however, it will -// never start a new islands from a disabled body. thus islands of disabled -// bodies will not be included in the simulation. disabled bodies are -// re-enabled if they are found to be part of an active island. - -static void -processIslandsFast (dxWorld * world, dReal stepsize, int maxiterations) -{ -#ifdef TIMING - dTimerStart ("Island Setup"); -#endif - dxBody *b, *bb, **body; - dxJoint *j, **joint; - - // nothing to do if no bodies - if (world->nb <= 0) - return; - - dInternalHandleAutoDisabling (world,stepsize); - - // make arrays for body and joint lists (for a single island) to go into - body = (dxBody **) ALLOCA (world->nb * sizeof (dxBody *)); - joint = (dxJoint **) ALLOCA (world->nj * sizeof (dxJoint *)); - int bcount = 0; // number of bodies in `body' - int jcount = 0; // number of joints in `joint' - int tbcount = 0; - int tjcount = 0; - - // set all body/joint tags to 0 - for (b = world->firstbody; b; b = (dxBody *) b->next) - b->tag = 0; - for (j = world->firstjoint; j; j = (dxJoint *) j->next) - j->tag = 0; - - // allocate a stack of unvisited bodies in the island. the maximum size of - // the stack can be the lesser of the number of bodies or joints, because - // new bodies are only ever added to the stack by going through untagged - // joints. all the bodies in the stack must be tagged! - int stackalloc = (world->nj < world->nb) ? world->nj : world->nb; - dxBody **stack = (dxBody **) ALLOCA (stackalloc * sizeof (dxBody *)); - int *autostack = (int *) ALLOCA (stackalloc * sizeof (int)); - - for (bb = world->firstbody; bb; bb = (dxBody *) bb->next) - { -#ifdef TIMING - dTimerNow ("Island Processing"); -#endif - // get bb = the next enabled, untagged body, and tag it - if (bb->tag || (bb->flags & dxBodyDisabled)) - continue; - bb->tag = 1; - - // tag all bodies and joints starting from bb. - int stacksize = 0; - int autoDepth = autoEnableDepth; - b = bb; - body[0] = bb; - bcount = 1; - jcount = 0; - goto quickstart; - while (stacksize > 0) - { - b = stack[--stacksize]; // pop body off stack - autoDepth = autostack[stacksize]; - body[bcount++] = b; // put body on body list - quickstart: - - // traverse and tag all body's joints, add untagged connected bodies - // to stack - for (dxJointNode * n = b->firstjoint; n; n = n->next) - { - if (!n->joint->tag) - { - int thisDepth = autoEnableDepth; - n->joint->tag = 1; - joint[jcount++] = n->joint; - if (n->body && !n->body->tag) - { - if (n->body->flags & dxBodyDisabled) - thisDepth = autoDepth - 1; - if (thisDepth < 0) - continue; - n->body->flags &= ~dxBodyDisabled; - n->body->tag = 1; - autostack[stacksize] = thisDepth; - stack[stacksize++] = n->body; - } - } - } - dIASSERT (stacksize <= world->nb); - dIASSERT (stacksize <= world->nj); - } - - // now do something with body and joint lists - dInternalStepIslandFast (world, body, bcount, joint, jcount, stepsize, maxiterations); - - // what we've just done may have altered the body/joint tag values. - // we must make sure that these tags are nonzero. - // also make sure all bodies are in the enabled state. - int i; - for (i = 0; i < bcount; i++) - { - body[i]->tag = 1; - body[i]->flags &= ~dxBodyDisabled; - } - for (i = 0; i < jcount; i++) - joint[i]->tag = 1; - - tbcount += bcount; - tjcount += jcount; - } - -#ifdef TIMING - dMessage(0, "Total joints processed: %i, bodies: %i", tjcount, tbcount); -#endif - - // if debugging, check that all objects (except for disabled bodies, - // unconnected joints, and joints that are connected to disabled bodies) - // were tagged. -# ifndef dNODEBUG - for (b = world->firstbody; b; b = (dxBody *) b->next) - { - if (b->flags & dxBodyDisabled) - { - if (b->tag) - dDebug (0, "disabled body tagged"); - } - else - { - if (!b->tag) - dDebug (0, "enabled body not tagged"); - } - } - for (j = world->firstjoint; j; j = (dxJoint *) j->next) - { - if ((j->node[0].body && (j->node[0].body->flags & dxBodyDisabled) == 0) || (j->node[1].body && (j->node[1].body->flags & dxBodyDisabled) == 0)) - { - if (!j->tag) - dDebug (0, "attached enabled joint not tagged"); - } - else - { - if (j->tag) - dDebug (0, "unattached or disabled joint tagged"); - } - } -# endif - -# ifdef TIMING - dTimerEnd (); - dTimerReport (stdout, 1); -# endif -} - -#endif - - -void dWorldStepFast1 (dWorldID w, dReal stepsize, int maxiterations) -{ - dUASSERT (w, "bad world argument"); - dUASSERT (stepsize > 0, "stepsize must be > 0"); - processIslandsFast (w, stepsize, maxiterations); -} -- cgit v1.1