Blender V2.61 - r43446

btHingeConstraint.cpp

Go to the documentation of this file.
00001 /*
00002 Bullet Continuous Collision Detection and Physics Library
00003 Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
00004 
00005 This software is provided 'as-is', without any express or implied warranty.
00006 In no event will the authors be held liable for any damages arising from the use of this software.
00007 Permission is granted to anyone to use this software for any purpose, 
00008 including commercial applications, and to alter it and redistribute it freely, 
00009 subject to the following restrictions:
00010 
00011 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
00012 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
00013 3. This notice may not be removed or altered from any source distribution.
00014 */
00015 
00016 
00017 #include "btHingeConstraint.h"
00018 #include "BulletDynamics/Dynamics/btRigidBody.h"
00019 #include "LinearMath/btTransformUtil.h"
00020 #include "LinearMath/btMinMax.h"
00021 #include <new>
00022 #include "btSolverBody.h"
00023 
00024 
00025 
00026 //#define HINGE_USE_OBSOLETE_SOLVER false
00027 #define HINGE_USE_OBSOLETE_SOLVER false
00028 
00029 #define HINGE_USE_FRAME_OFFSET true
00030 
00031 #ifndef __SPU__
00032 
00033 
00034 
00035 
00036 
00037 btHingeConstraint::btHingeConstraint(btRigidBody& rbA,btRigidBody& rbB, const btVector3& pivotInA,const btVector3& pivotInB,
00038                                      const btVector3& axisInA,const btVector3& axisInB, bool useReferenceFrameA)
00039                                      :btTypedConstraint(HINGE_CONSTRAINT_TYPE, rbA,rbB),
00040                                      m_angularOnly(false),
00041                                      m_enableAngularMotor(false),
00042                                      m_useSolveConstraintObsolete(HINGE_USE_OBSOLETE_SOLVER),
00043                                      m_useOffsetForConstraintFrame(HINGE_USE_FRAME_OFFSET),
00044                                      m_useReferenceFrameA(useReferenceFrameA),
00045                                      m_flags(0)
00046 #ifdef _BT_USE_CENTER_LIMIT_
00047                                     ,m_limit()
00048 #endif
00049 {
00050     m_rbAFrame.getOrigin() = pivotInA;
00051     
00052     // since no frame is given, assume this to be zero angle and just pick rb transform axis
00053     btVector3 rbAxisA1 = rbA.getCenterOfMassTransform().getBasis().getColumn(0);
00054 
00055     btVector3 rbAxisA2;
00056     btScalar projection = axisInA.dot(rbAxisA1);
00057     if (projection >= 1.0f - SIMD_EPSILON) {
00058         rbAxisA1 = -rbA.getCenterOfMassTransform().getBasis().getColumn(2);
00059         rbAxisA2 = rbA.getCenterOfMassTransform().getBasis().getColumn(1);
00060     } else if (projection <= -1.0f + SIMD_EPSILON) {
00061         rbAxisA1 = rbA.getCenterOfMassTransform().getBasis().getColumn(2);
00062         rbAxisA2 = rbA.getCenterOfMassTransform().getBasis().getColumn(1);      
00063     } else {
00064         rbAxisA2 = axisInA.cross(rbAxisA1);
00065         rbAxisA1 = rbAxisA2.cross(axisInA);
00066     }
00067 
00068     m_rbAFrame.getBasis().setValue( rbAxisA1.getX(),rbAxisA2.getX(),axisInA.getX(),
00069                                     rbAxisA1.getY(),rbAxisA2.getY(),axisInA.getY(),
00070                                     rbAxisA1.getZ(),rbAxisA2.getZ(),axisInA.getZ() );
00071 
00072     btQuaternion rotationArc = shortestArcQuat(axisInA,axisInB);
00073     btVector3 rbAxisB1 =  quatRotate(rotationArc,rbAxisA1);
00074     btVector3 rbAxisB2 =  axisInB.cross(rbAxisB1);  
00075     
00076     m_rbBFrame.getOrigin() = pivotInB;
00077     m_rbBFrame.getBasis().setValue( rbAxisB1.getX(),rbAxisB2.getX(),axisInB.getX(),
00078                                     rbAxisB1.getY(),rbAxisB2.getY(),axisInB.getY(),
00079                                     rbAxisB1.getZ(),rbAxisB2.getZ(),axisInB.getZ() );
00080     
00081 #ifndef _BT_USE_CENTER_LIMIT_
00082     //start with free
00083     m_lowerLimit = btScalar(1.0f);
00084     m_upperLimit = btScalar(-1.0f);
00085     m_biasFactor = 0.3f;
00086     m_relaxationFactor = 1.0f;
00087     m_limitSoftness = 0.9f;
00088     m_solveLimit = false;
00089 #endif
00090     m_referenceSign = m_useReferenceFrameA ? btScalar(-1.f) : btScalar(1.f);
00091 }
00092 
00093 
00094 
00095 btHingeConstraint::btHingeConstraint(btRigidBody& rbA,const btVector3& pivotInA,const btVector3& axisInA, bool useReferenceFrameA)
00096 :btTypedConstraint(HINGE_CONSTRAINT_TYPE, rbA), m_angularOnly(false), m_enableAngularMotor(false), 
00097 m_useSolveConstraintObsolete(HINGE_USE_OBSOLETE_SOLVER),
00098 m_useOffsetForConstraintFrame(HINGE_USE_FRAME_OFFSET),
00099 m_useReferenceFrameA(useReferenceFrameA),
00100 m_flags(0)
00101 #ifdef  _BT_USE_CENTER_LIMIT_
00102 ,m_limit()
00103 #endif
00104 {
00105 
00106     // since no frame is given, assume this to be zero angle and just pick rb transform axis
00107     // fixed axis in worldspace
00108     btVector3 rbAxisA1, rbAxisA2;
00109     btPlaneSpace1(axisInA, rbAxisA1, rbAxisA2);
00110 
00111     m_rbAFrame.getOrigin() = pivotInA;
00112     m_rbAFrame.getBasis().setValue( rbAxisA1.getX(),rbAxisA2.getX(),axisInA.getX(),
00113                                     rbAxisA1.getY(),rbAxisA2.getY(),axisInA.getY(),
00114                                     rbAxisA1.getZ(),rbAxisA2.getZ(),axisInA.getZ() );
00115 
00116     btVector3 axisInB = rbA.getCenterOfMassTransform().getBasis() * axisInA;
00117 
00118     btQuaternion rotationArc = shortestArcQuat(axisInA,axisInB);
00119     btVector3 rbAxisB1 =  quatRotate(rotationArc,rbAxisA1);
00120     btVector3 rbAxisB2 = axisInB.cross(rbAxisB1);
00121 
00122 
00123     m_rbBFrame.getOrigin() = rbA.getCenterOfMassTransform()(pivotInA);
00124     m_rbBFrame.getBasis().setValue( rbAxisB1.getX(),rbAxisB2.getX(),axisInB.getX(),
00125                                     rbAxisB1.getY(),rbAxisB2.getY(),axisInB.getY(),
00126                                     rbAxisB1.getZ(),rbAxisB2.getZ(),axisInB.getZ() );
00127     
00128 #ifndef _BT_USE_CENTER_LIMIT_
00129     //start with free
00130     m_lowerLimit = btScalar(1.0f);
00131     m_upperLimit = btScalar(-1.0f);
00132     m_biasFactor = 0.3f;
00133     m_relaxationFactor = 1.0f;
00134     m_limitSoftness = 0.9f;
00135     m_solveLimit = false;
00136 #endif
00137     m_referenceSign = m_useReferenceFrameA ? btScalar(-1.f) : btScalar(1.f);
00138 }
00139 
00140 
00141 
00142 btHingeConstraint::btHingeConstraint(btRigidBody& rbA,btRigidBody& rbB, 
00143                                      const btTransform& rbAFrame, const btTransform& rbBFrame, bool useReferenceFrameA)
00144 :btTypedConstraint(HINGE_CONSTRAINT_TYPE, rbA,rbB),m_rbAFrame(rbAFrame),m_rbBFrame(rbBFrame),
00145 m_angularOnly(false),
00146 m_enableAngularMotor(false),
00147 m_useSolveConstraintObsolete(HINGE_USE_OBSOLETE_SOLVER),
00148 m_useOffsetForConstraintFrame(HINGE_USE_FRAME_OFFSET),
00149 m_useReferenceFrameA(useReferenceFrameA),
00150 m_flags(0)
00151 #ifdef  _BT_USE_CENTER_LIMIT_
00152 ,m_limit()
00153 #endif
00154 {
00155 #ifndef _BT_USE_CENTER_LIMIT_
00156     //start with free
00157     m_lowerLimit = btScalar(1.0f);
00158     m_upperLimit = btScalar(-1.0f);
00159     m_biasFactor = 0.3f;
00160     m_relaxationFactor = 1.0f;
00161     m_limitSoftness = 0.9f;
00162     m_solveLimit = false;
00163 #endif
00164     m_referenceSign = m_useReferenceFrameA ? btScalar(-1.f) : btScalar(1.f);
00165 }           
00166 
00167 
00168 
00169 btHingeConstraint::btHingeConstraint(btRigidBody& rbA, const btTransform& rbAFrame, bool useReferenceFrameA)
00170 :btTypedConstraint(HINGE_CONSTRAINT_TYPE, rbA),m_rbAFrame(rbAFrame),m_rbBFrame(rbAFrame),
00171 m_angularOnly(false),
00172 m_enableAngularMotor(false),
00173 m_useSolveConstraintObsolete(HINGE_USE_OBSOLETE_SOLVER),
00174 m_useOffsetForConstraintFrame(HINGE_USE_FRAME_OFFSET),
00175 m_useReferenceFrameA(useReferenceFrameA),
00176 m_flags(0)
00177 #ifdef  _BT_USE_CENTER_LIMIT_
00178 ,m_limit()
00179 #endif
00180 {
00182 
00183     m_rbBFrame.getOrigin() = m_rbA.getCenterOfMassTransform()(m_rbAFrame.getOrigin());
00184 #ifndef _BT_USE_CENTER_LIMIT_
00185     //start with free
00186     m_lowerLimit = btScalar(1.0f);
00187     m_upperLimit = btScalar(-1.0f);
00188     m_biasFactor = 0.3f;
00189     m_relaxationFactor = 1.0f;
00190     m_limitSoftness = 0.9f;
00191     m_solveLimit = false;
00192 #endif
00193     m_referenceSign = m_useReferenceFrameA ? btScalar(-1.f) : btScalar(1.f);
00194 }
00195 
00196 
00197 
00198 void    btHingeConstraint::buildJacobian()
00199 {
00200     if (m_useSolveConstraintObsolete)
00201     {
00202         m_appliedImpulse = btScalar(0.);
00203         m_accMotorImpulse = btScalar(0.);
00204 
00205         if (!m_angularOnly)
00206         {
00207             btVector3 pivotAInW = m_rbA.getCenterOfMassTransform()*m_rbAFrame.getOrigin();
00208             btVector3 pivotBInW = m_rbB.getCenterOfMassTransform()*m_rbBFrame.getOrigin();
00209             btVector3 relPos = pivotBInW - pivotAInW;
00210 
00211             btVector3 normal[3];
00212             if (relPos.length2() > SIMD_EPSILON)
00213             {
00214                 normal[0] = relPos.normalized();
00215             }
00216             else
00217             {
00218                 normal[0].setValue(btScalar(1.0),0,0);
00219             }
00220 
00221             btPlaneSpace1(normal[0], normal[1], normal[2]);
00222 
00223             for (int i=0;i<3;i++)
00224             {
00225                 new (&m_jac[i]) btJacobianEntry(
00226                 m_rbA.getCenterOfMassTransform().getBasis().transpose(),
00227                 m_rbB.getCenterOfMassTransform().getBasis().transpose(),
00228                 pivotAInW - m_rbA.getCenterOfMassPosition(),
00229                 pivotBInW - m_rbB.getCenterOfMassPosition(),
00230                 normal[i],
00231                 m_rbA.getInvInertiaDiagLocal(),
00232                 m_rbA.getInvMass(),
00233                 m_rbB.getInvInertiaDiagLocal(),
00234                 m_rbB.getInvMass());
00235             }
00236         }
00237 
00238         //calculate two perpendicular jointAxis, orthogonal to hingeAxis
00239         //these two jointAxis require equal angular velocities for both bodies
00240 
00241         //this is unused for now, it's a todo
00242         btVector3 jointAxis0local;
00243         btVector3 jointAxis1local;
00244         
00245         btPlaneSpace1(m_rbAFrame.getBasis().getColumn(2),jointAxis0local,jointAxis1local);
00246 
00247         btVector3 jointAxis0 = getRigidBodyA().getCenterOfMassTransform().getBasis() * jointAxis0local;
00248         btVector3 jointAxis1 = getRigidBodyA().getCenterOfMassTransform().getBasis() * jointAxis1local;
00249         btVector3 hingeAxisWorld = getRigidBodyA().getCenterOfMassTransform().getBasis() * m_rbAFrame.getBasis().getColumn(2);
00250             
00251         new (&m_jacAng[0])  btJacobianEntry(jointAxis0,
00252             m_rbA.getCenterOfMassTransform().getBasis().transpose(),
00253             m_rbB.getCenterOfMassTransform().getBasis().transpose(),
00254             m_rbA.getInvInertiaDiagLocal(),
00255             m_rbB.getInvInertiaDiagLocal());
00256 
00257         new (&m_jacAng[1])  btJacobianEntry(jointAxis1,
00258             m_rbA.getCenterOfMassTransform().getBasis().transpose(),
00259             m_rbB.getCenterOfMassTransform().getBasis().transpose(),
00260             m_rbA.getInvInertiaDiagLocal(),
00261             m_rbB.getInvInertiaDiagLocal());
00262 
00263         new (&m_jacAng[2])  btJacobianEntry(hingeAxisWorld,
00264             m_rbA.getCenterOfMassTransform().getBasis().transpose(),
00265             m_rbB.getCenterOfMassTransform().getBasis().transpose(),
00266             m_rbA.getInvInertiaDiagLocal(),
00267             m_rbB.getInvInertiaDiagLocal());
00268 
00269             // clear accumulator
00270             m_accLimitImpulse = btScalar(0.);
00271 
00272             // test angular limit
00273             testLimit(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform());
00274 
00275         //Compute K = J*W*J' for hinge axis
00276         btVector3 axisA =  getRigidBodyA().getCenterOfMassTransform().getBasis() *  m_rbAFrame.getBasis().getColumn(2);
00277         m_kHinge =   1.0f / (getRigidBodyA().computeAngularImpulseDenominator(axisA) +
00278                              getRigidBodyB().computeAngularImpulseDenominator(axisA));
00279 
00280     }
00281 }
00282 
00283 
00284 #endif //__SPU__
00285 
00286 
00287 void btHingeConstraint::getInfo1(btConstraintInfo1* info)
00288 {
00289     if (m_useSolveConstraintObsolete)
00290     {
00291         info->m_numConstraintRows = 0;
00292         info->nub = 0;
00293     }
00294     else
00295     {
00296         info->m_numConstraintRows = 5; // Fixed 3 linear + 2 angular
00297         info->nub = 1; 
00298         //always add the row, to avoid computation (data is not available yet)
00299         //prepare constraint
00300         testLimit(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform());
00301         if(getSolveLimit() || getEnableAngularMotor())
00302         {
00303             info->m_numConstraintRows++; // limit 3rd anguar as well
00304             info->nub--; 
00305         }
00306 
00307     }
00308 }
00309 
00310 void btHingeConstraint::getInfo1NonVirtual(btConstraintInfo1* info)
00311 {
00312     if (m_useSolveConstraintObsolete)
00313     {
00314         info->m_numConstraintRows = 0;
00315         info->nub = 0;
00316     }
00317     else
00318     {
00319         //always add the 'limit' row, to avoid computation (data is not available yet)
00320         info->m_numConstraintRows = 6; // Fixed 3 linear + 2 angular
00321         info->nub = 0; 
00322     }
00323 }
00324 
00325 void btHingeConstraint::getInfo2 (btConstraintInfo2* info)
00326 {
00327     if(m_useOffsetForConstraintFrame)
00328     {
00329         getInfo2InternalUsingFrameOffset(info, m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform(),m_rbA.getAngularVelocity(),m_rbB.getAngularVelocity());
00330     }
00331     else
00332     {
00333         getInfo2Internal(info, m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform(),m_rbA.getAngularVelocity(),m_rbB.getAngularVelocity());
00334     }
00335 }
00336 
00337 
00338 void    btHingeConstraint::getInfo2NonVirtual (btConstraintInfo2* info,const btTransform& transA,const btTransform& transB,const btVector3& angVelA,const btVector3& angVelB)
00339 {
00341     testLimit(transA,transB);
00342 
00343     getInfo2Internal(info,transA,transB,angVelA,angVelB);
00344 }
00345 
00346 
00347 void btHingeConstraint::getInfo2Internal(btConstraintInfo2* info, const btTransform& transA,const btTransform& transB,const btVector3& angVelA,const btVector3& angVelB)
00348 {
00349 
00350     btAssert(!m_useSolveConstraintObsolete);
00351     int i, skip = info->rowskip;
00352     // transforms in world space
00353     btTransform trA = transA*m_rbAFrame;
00354     btTransform trB = transB*m_rbBFrame;
00355     // pivot point
00356     btVector3 pivotAInW = trA.getOrigin();
00357     btVector3 pivotBInW = trB.getOrigin();
00358 #if 0
00359     if (0)
00360     {
00361         for (i=0;i<6;i++)
00362         {
00363             info->m_J1linearAxis[i*skip]=0;
00364             info->m_J1linearAxis[i*skip+1]=0;
00365             info->m_J1linearAxis[i*skip+2]=0;
00366 
00367             info->m_J1angularAxis[i*skip]=0;
00368             info->m_J1angularAxis[i*skip+1]=0;
00369             info->m_J1angularAxis[i*skip+2]=0;
00370 
00371             info->m_J2angularAxis[i*skip]=0;
00372             info->m_J2angularAxis[i*skip+1]=0;
00373             info->m_J2angularAxis[i*skip+2]=0;
00374 
00375             info->m_constraintError[i*skip]=0.f;
00376         }
00377     }
00378 #endif //#if 0
00379     // linear (all fixed)
00380 
00381     if (!m_angularOnly)
00382     {
00383         info->m_J1linearAxis[0] = 1;
00384         info->m_J1linearAxis[skip + 1] = 1;
00385         info->m_J1linearAxis[2 * skip + 2] = 1;
00386     }   
00387 
00388 
00389 
00390 
00391     btVector3 a1 = pivotAInW - transA.getOrigin();
00392     {
00393         btVector3* angular0 = (btVector3*)(info->m_J1angularAxis);
00394         btVector3* angular1 = (btVector3*)(info->m_J1angularAxis + skip);
00395         btVector3* angular2 = (btVector3*)(info->m_J1angularAxis + 2 * skip);
00396         btVector3 a1neg = -a1;
00397         a1neg.getSkewSymmetricMatrix(angular0,angular1,angular2);
00398     }
00399     btVector3 a2 = pivotBInW - transB.getOrigin();
00400     {
00401         btVector3* angular0 = (btVector3*)(info->m_J2angularAxis);
00402         btVector3* angular1 = (btVector3*)(info->m_J2angularAxis + skip);
00403         btVector3* angular2 = (btVector3*)(info->m_J2angularAxis + 2 * skip);
00404         a2.getSkewSymmetricMatrix(angular0,angular1,angular2);
00405     }
00406     // linear RHS
00407     btScalar k = info->fps * info->erp;
00408     if (!m_angularOnly)
00409     {
00410         for(i = 0; i < 3; i++)
00411         {
00412             info->m_constraintError[i * skip] = k * (pivotBInW[i] - pivotAInW[i]);
00413         }
00414     }
00415     // make rotations around X and Y equal
00416     // the hinge axis should be the only unconstrained
00417     // rotational axis, the angular velocity of the two bodies perpendicular to
00418     // the hinge axis should be equal. thus the constraint equations are
00419     //    p*w1 - p*w2 = 0
00420     //    q*w1 - q*w2 = 0
00421     // where p and q are unit vectors normal to the hinge axis, and w1 and w2
00422     // are the angular velocity vectors of the two bodies.
00423     // get hinge axis (Z)
00424     btVector3 ax1 = trA.getBasis().getColumn(2);
00425     // get 2 orthos to hinge axis (X, Y)
00426     btVector3 p = trA.getBasis().getColumn(0);
00427     btVector3 q = trA.getBasis().getColumn(1);
00428     // set the two hinge angular rows 
00429     int s3 = 3 * info->rowskip;
00430     int s4 = 4 * info->rowskip;
00431 
00432     info->m_J1angularAxis[s3 + 0] = p[0];
00433     info->m_J1angularAxis[s3 + 1] = p[1];
00434     info->m_J1angularAxis[s3 + 2] = p[2];
00435     info->m_J1angularAxis[s4 + 0] = q[0];
00436     info->m_J1angularAxis[s4 + 1] = q[1];
00437     info->m_J1angularAxis[s4 + 2] = q[2];
00438 
00439     info->m_J2angularAxis[s3 + 0] = -p[0];
00440     info->m_J2angularAxis[s3 + 1] = -p[1];
00441     info->m_J2angularAxis[s3 + 2] = -p[2];
00442     info->m_J2angularAxis[s4 + 0] = -q[0];
00443     info->m_J2angularAxis[s4 + 1] = -q[1];
00444     info->m_J2angularAxis[s4 + 2] = -q[2];
00445     // compute the right hand side of the constraint equation. set relative
00446     // body velocities along p and q to bring the hinge back into alignment.
00447     // if ax1,ax2 are the unit length hinge axes as computed from body1 and
00448     // body2, we need to rotate both bodies along the axis u = (ax1 x ax2).
00449     // if `theta' is the angle between ax1 and ax2, we need an angular velocity
00450     // along u to cover angle erp*theta in one step :
00451     //   |angular_velocity| = angle/time = erp*theta / stepsize
00452     //                      = (erp*fps) * theta
00453     //    angular_velocity  = |angular_velocity| * (ax1 x ax2) / |ax1 x ax2|
00454     //                      = (erp*fps) * theta * (ax1 x ax2) / sin(theta)
00455     // ...as ax1 and ax2 are unit length. if theta is smallish,
00456     // theta ~= sin(theta), so
00457     //    angular_velocity  = (erp*fps) * (ax1 x ax2)
00458     // ax1 x ax2 is in the plane space of ax1, so we project the angular
00459     // velocity to p and q to find the right hand side.
00460     btVector3 ax2 = trB.getBasis().getColumn(2);
00461     btVector3 u = ax1.cross(ax2);
00462     info->m_constraintError[s3] = k * u.dot(p);
00463     info->m_constraintError[s4] = k * u.dot(q);
00464     // check angular limits
00465     int nrow = 4; // last filled row
00466     int srow;
00467     btScalar limit_err = btScalar(0.0);
00468     int limit = 0;
00469     if(getSolveLimit())
00470     {
00471 #ifdef  _BT_USE_CENTER_LIMIT_
00472     limit_err = m_limit.getCorrection() * m_referenceSign;
00473 #else
00474     limit_err = m_correction * m_referenceSign;
00475 #endif
00476     limit = (limit_err > btScalar(0.0)) ? 1 : 2;
00477 
00478     }
00479     // if the hinge has joint limits or motor, add in the extra row
00480     int powered = 0;
00481     if(getEnableAngularMotor())
00482     {
00483         powered = 1;
00484     }
00485     if(limit || powered) 
00486     {
00487         nrow++;
00488         srow = nrow * info->rowskip;
00489         info->m_J1angularAxis[srow+0] = ax1[0];
00490         info->m_J1angularAxis[srow+1] = ax1[1];
00491         info->m_J1angularAxis[srow+2] = ax1[2];
00492 
00493         info->m_J2angularAxis[srow+0] = -ax1[0];
00494         info->m_J2angularAxis[srow+1] = -ax1[1];
00495         info->m_J2angularAxis[srow+2] = -ax1[2];
00496 
00497         btScalar lostop = getLowerLimit();
00498         btScalar histop = getUpperLimit();
00499         if(limit && (lostop == histop))
00500         {  // the joint motor is ineffective
00501             powered = 0;
00502         }
00503         info->m_constraintError[srow] = btScalar(0.0f);
00504         btScalar currERP = (m_flags & BT_HINGE_FLAGS_ERP_STOP) ? m_stopERP : info->erp;
00505         if(powered)
00506         {
00507             if(m_flags & BT_HINGE_FLAGS_CFM_NORM)
00508             {
00509                 info->cfm[srow] = m_normalCFM;
00510             }
00511             btScalar mot_fact = getMotorFactor(m_hingeAngle, lostop, histop, m_motorTargetVelocity, info->fps * currERP);
00512             info->m_constraintError[srow] += mot_fact * m_motorTargetVelocity * m_referenceSign;
00513             info->m_lowerLimit[srow] = - m_maxMotorImpulse;
00514             info->m_upperLimit[srow] =   m_maxMotorImpulse;
00515         }
00516         if(limit)
00517         {
00518             k = info->fps * currERP;
00519             info->m_constraintError[srow] += k * limit_err;
00520             if(m_flags & BT_HINGE_FLAGS_CFM_STOP)
00521             {
00522                 info->cfm[srow] = m_stopCFM;
00523             }
00524             if(lostop == histop) 
00525             {
00526                 // limited low and high simultaneously
00527                 info->m_lowerLimit[srow] = -SIMD_INFINITY;
00528                 info->m_upperLimit[srow] = SIMD_INFINITY;
00529             }
00530             else if(limit == 1) 
00531             { // low limit
00532                 info->m_lowerLimit[srow] = 0;
00533                 info->m_upperLimit[srow] = SIMD_INFINITY;
00534             }
00535             else 
00536             { // high limit
00537                 info->m_lowerLimit[srow] = -SIMD_INFINITY;
00538                 info->m_upperLimit[srow] = 0;
00539             }
00540             // bounce (we'll use slider parameter abs(1.0 - m_dampingLimAng) for that)
00541 #ifdef  _BT_USE_CENTER_LIMIT_
00542             btScalar bounce = m_limit.getRelaxationFactor();
00543 #else
00544             btScalar bounce = m_relaxationFactor;
00545 #endif
00546             if(bounce > btScalar(0.0))
00547             {
00548                 btScalar vel = angVelA.dot(ax1);
00549                 vel -= angVelB.dot(ax1);
00550                 // only apply bounce if the velocity is incoming, and if the
00551                 // resulting c[] exceeds what we already have.
00552                 if(limit == 1)
00553                 {   // low limit
00554                     if(vel < 0)
00555                     {
00556                         btScalar newc = -bounce * vel;
00557                         if(newc > info->m_constraintError[srow])
00558                         {
00559                             info->m_constraintError[srow] = newc;
00560                         }
00561                     }
00562                 }
00563                 else
00564                 {   // high limit - all those computations are reversed
00565                     if(vel > 0)
00566                     {
00567                         btScalar newc = -bounce * vel;
00568                         if(newc < info->m_constraintError[srow])
00569                         {
00570                             info->m_constraintError[srow] = newc;
00571                         }
00572                     }
00573                 }
00574             }
00575 #ifdef  _BT_USE_CENTER_LIMIT_
00576             info->m_constraintError[srow] *= m_limit.getBiasFactor();
00577 #else
00578             info->m_constraintError[srow] *= m_biasFactor;
00579 #endif
00580         } // if(limit)
00581     } // if angular limit or powered
00582 }
00583 
00584 
00585 void btHingeConstraint::setFrames(const btTransform & frameA, const btTransform & frameB)
00586 {
00587     m_rbAFrame = frameA;
00588     m_rbBFrame = frameB;
00589     buildJacobian();
00590 }
00591 
00592 
00593 void    btHingeConstraint::updateRHS(btScalar   timeStep)
00594 {
00595     (void)timeStep;
00596 
00597 }
00598 
00599 
00600 btScalar btHingeConstraint::getHingeAngle()
00601 {
00602     return getHingeAngle(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform());
00603 }
00604 
00605 btScalar btHingeConstraint::getHingeAngle(const btTransform& transA,const btTransform& transB)
00606 {
00607     const btVector3 refAxis0  = transA.getBasis() * m_rbAFrame.getBasis().getColumn(0);
00608     const btVector3 refAxis1  = transA.getBasis() * m_rbAFrame.getBasis().getColumn(1);
00609     const btVector3 swingAxis = transB.getBasis() * m_rbBFrame.getBasis().getColumn(1);
00610 //  btScalar angle = btAtan2Fast(swingAxis.dot(refAxis0), swingAxis.dot(refAxis1));
00611     btScalar angle = btAtan2(swingAxis.dot(refAxis0), swingAxis.dot(refAxis1));
00612     return m_referenceSign * angle;
00613 }
00614 
00615 
00616 
00617 void btHingeConstraint::testLimit(const btTransform& transA,const btTransform& transB)
00618 {
00619     // Compute limit information
00620     m_hingeAngle = getHingeAngle(transA,transB);
00621 #ifdef  _BT_USE_CENTER_LIMIT_
00622     m_limit.test(m_hingeAngle);
00623 #else
00624     m_correction = btScalar(0.);
00625     m_limitSign = btScalar(0.);
00626     m_solveLimit = false;
00627     if (m_lowerLimit <= m_upperLimit)
00628     {
00629         m_hingeAngle = btAdjustAngleToLimits(m_hingeAngle, m_lowerLimit, m_upperLimit);
00630         if (m_hingeAngle <= m_lowerLimit)
00631         {
00632             m_correction = (m_lowerLimit - m_hingeAngle);
00633             m_limitSign = 1.0f;
00634             m_solveLimit = true;
00635         } 
00636         else if (m_hingeAngle >= m_upperLimit)
00637         {
00638             m_correction = m_upperLimit - m_hingeAngle;
00639             m_limitSign = -1.0f;
00640             m_solveLimit = true;
00641         }
00642     }
00643 #endif
00644     return;
00645 }
00646 
00647 
00648 static btVector3 vHinge(0, 0, btScalar(1));
00649 
00650 void btHingeConstraint::setMotorTarget(const btQuaternion& qAinB, btScalar dt)
00651 {
00652     // convert target from body to constraint space
00653     btQuaternion qConstraint = m_rbBFrame.getRotation().inverse() * qAinB * m_rbAFrame.getRotation();
00654     qConstraint.normalize();
00655 
00656     // extract "pure" hinge component
00657     btVector3 vNoHinge = quatRotate(qConstraint, vHinge); vNoHinge.normalize();
00658     btQuaternion qNoHinge = shortestArcQuat(vHinge, vNoHinge);
00659     btQuaternion qHinge = qNoHinge.inverse() * qConstraint;
00660     qHinge.normalize();
00661 
00662     // compute angular target, clamped to limits
00663     btScalar targetAngle = qHinge.getAngle();
00664     if (targetAngle > SIMD_PI) // long way around. flip quat and recalculate.
00665     {
00666         qHinge = operator-(qHinge);
00667         targetAngle = qHinge.getAngle();
00668     }
00669     if (qHinge.getZ() < 0)
00670         targetAngle = -targetAngle;
00671 
00672     setMotorTarget(targetAngle, dt);
00673 }
00674 
00675 void btHingeConstraint::setMotorTarget(btScalar targetAngle, btScalar dt)
00676 {
00677 #ifdef  _BT_USE_CENTER_LIMIT_
00678     m_limit.fit(targetAngle);
00679 #else
00680     if (m_lowerLimit < m_upperLimit)
00681     {
00682         if (targetAngle < m_lowerLimit)
00683             targetAngle = m_lowerLimit;
00684         else if (targetAngle > m_upperLimit)
00685             targetAngle = m_upperLimit;
00686     }
00687 #endif
00688     // compute angular velocity
00689     btScalar curAngle  = getHingeAngle(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform());
00690     btScalar dAngle = targetAngle - curAngle;
00691     m_motorTargetVelocity = dAngle / dt;
00692 }
00693 
00694 
00695 
00696 void btHingeConstraint::getInfo2InternalUsingFrameOffset(btConstraintInfo2* info, const btTransform& transA,const btTransform& transB,const btVector3& angVelA,const btVector3& angVelB)
00697 {
00698     btAssert(!m_useSolveConstraintObsolete);
00699     int i, s = info->rowskip;
00700     // transforms in world space
00701     btTransform trA = transA*m_rbAFrame;
00702     btTransform trB = transB*m_rbBFrame;
00703     // pivot point
00704     btVector3 pivotAInW = trA.getOrigin();
00705     btVector3 pivotBInW = trB.getOrigin();
00706 #if 1
00707     // difference between frames in WCS
00708     btVector3 ofs = trB.getOrigin() - trA.getOrigin();
00709     // now get weight factors depending on masses
00710     btScalar miA = getRigidBodyA().getInvMass();
00711     btScalar miB = getRigidBodyB().getInvMass();
00712     bool hasStaticBody = (miA < SIMD_EPSILON) || (miB < SIMD_EPSILON);
00713     btScalar miS = miA + miB;
00714     btScalar factA, factB;
00715     if(miS > btScalar(0.f))
00716     {
00717         factA = miB / miS;
00718     }
00719     else 
00720     {
00721         factA = btScalar(0.5f);
00722     }
00723     factB = btScalar(1.0f) - factA;
00724     // get the desired direction of hinge axis
00725     // as weighted sum of Z-orthos of frameA and frameB in WCS
00726     btVector3 ax1A = trA.getBasis().getColumn(2);
00727     btVector3 ax1B = trB.getBasis().getColumn(2);
00728     btVector3 ax1 = ax1A * factA + ax1B * factB;
00729     ax1.normalize();
00730     // fill first 3 rows 
00731     // we want: velA + wA x relA == velB + wB x relB
00732     btTransform bodyA_trans = transA;
00733     btTransform bodyB_trans = transB;
00734     int s0 = 0;
00735     int s1 = s;
00736     int s2 = s * 2;
00737     int nrow = 2; // last filled row
00738     btVector3 tmpA, tmpB, relA, relB, p, q;
00739     // get vector from bodyB to frameB in WCS
00740     relB = trB.getOrigin() - bodyB_trans.getOrigin();
00741     // get its projection to hinge axis
00742     btVector3 projB = ax1 * relB.dot(ax1);
00743     // get vector directed from bodyB to hinge axis (and orthogonal to it)
00744     btVector3 orthoB = relB - projB;
00745     // same for bodyA
00746     relA = trA.getOrigin() - bodyA_trans.getOrigin();
00747     btVector3 projA = ax1 * relA.dot(ax1);
00748     btVector3 orthoA = relA - projA;
00749     btVector3 totalDist = projA - projB;
00750     // get offset vectors relA and relB
00751     relA = orthoA + totalDist * factA;
00752     relB = orthoB - totalDist * factB;
00753     // now choose average ortho to hinge axis
00754     p = orthoB * factA + orthoA * factB;
00755     btScalar len2 = p.length2();
00756     if(len2 > SIMD_EPSILON)
00757     {
00758         p /= btSqrt(len2);
00759     }
00760     else
00761     {
00762         p = trA.getBasis().getColumn(1);
00763     }
00764     // make one more ortho
00765     q = ax1.cross(p);
00766     // fill three rows
00767     tmpA = relA.cross(p);
00768     tmpB = relB.cross(p);
00769     for (i=0; i<3; i++) info->m_J1angularAxis[s0+i] = tmpA[i];
00770     for (i=0; i<3; i++) info->m_J2angularAxis[s0+i] = -tmpB[i];
00771     tmpA = relA.cross(q);
00772     tmpB = relB.cross(q);
00773     if(hasStaticBody && getSolveLimit())
00774     { // to make constraint between static and dynamic objects more rigid
00775         // remove wA (or wB) from equation if angular limit is hit
00776         tmpB *= factB;
00777         tmpA *= factA;
00778     }
00779     for (i=0; i<3; i++) info->m_J1angularAxis[s1+i] = tmpA[i];
00780     for (i=0; i<3; i++) info->m_J2angularAxis[s1+i] = -tmpB[i];
00781     tmpA = relA.cross(ax1);
00782     tmpB = relB.cross(ax1);
00783     if(hasStaticBody)
00784     { // to make constraint between static and dynamic objects more rigid
00785         // remove wA (or wB) from equation
00786         tmpB *= factB;
00787         tmpA *= factA;
00788     }
00789     for (i=0; i<3; i++) info->m_J1angularAxis[s2+i] = tmpA[i];
00790     for (i=0; i<3; i++) info->m_J2angularAxis[s2+i] = -tmpB[i];
00791 
00792     btScalar k = info->fps * info->erp;
00793 
00794     if (!m_angularOnly)
00795     {
00796         for (i=0; i<3; i++) info->m_J1linearAxis[s0+i] = p[i];
00797         for (i=0; i<3; i++) info->m_J1linearAxis[s1+i] = q[i];
00798         for (i=0; i<3; i++) info->m_J1linearAxis[s2+i] = ax1[i];
00799     
00800     // compute three elements of right hand side
00801     
00802         btScalar rhs = k * p.dot(ofs);
00803         info->m_constraintError[s0] = rhs;
00804         rhs = k * q.dot(ofs);
00805         info->m_constraintError[s1] = rhs;
00806         rhs = k * ax1.dot(ofs);
00807         info->m_constraintError[s2] = rhs;
00808     }
00809     // the hinge axis should be the only unconstrained
00810     // rotational axis, the angular velocity of the two bodies perpendicular to
00811     // the hinge axis should be equal. thus the constraint equations are
00812     //    p*w1 - p*w2 = 0
00813     //    q*w1 - q*w2 = 0
00814     // where p and q are unit vectors normal to the hinge axis, and w1 and w2
00815     // are the angular velocity vectors of the two bodies.
00816     int s3 = 3 * s;
00817     int s4 = 4 * s;
00818     info->m_J1angularAxis[s3 + 0] = p[0];
00819     info->m_J1angularAxis[s3 + 1] = p[1];
00820     info->m_J1angularAxis[s3 + 2] = p[2];
00821     info->m_J1angularAxis[s4 + 0] = q[0];
00822     info->m_J1angularAxis[s4 + 1] = q[1];
00823     info->m_J1angularAxis[s4 + 2] = q[2];
00824 
00825     info->m_J2angularAxis[s3 + 0] = -p[0];
00826     info->m_J2angularAxis[s3 + 1] = -p[1];
00827     info->m_J2angularAxis[s3 + 2] = -p[2];
00828     info->m_J2angularAxis[s4 + 0] = -q[0];
00829     info->m_J2angularAxis[s4 + 1] = -q[1];
00830     info->m_J2angularAxis[s4 + 2] = -q[2];
00831     // compute the right hand side of the constraint equation. set relative
00832     // body velocities along p and q to bring the hinge back into alignment.
00833     // if ax1A,ax1B are the unit length hinge axes as computed from bodyA and
00834     // bodyB, we need to rotate both bodies along the axis u = (ax1 x ax2).
00835     // if "theta" is the angle between ax1 and ax2, we need an angular velocity
00836     // along u to cover angle erp*theta in one step :
00837     //   |angular_velocity| = angle/time = erp*theta / stepsize
00838     //                      = (erp*fps) * theta
00839     //    angular_velocity  = |angular_velocity| * (ax1 x ax2) / |ax1 x ax2|
00840     //                      = (erp*fps) * theta * (ax1 x ax2) / sin(theta)
00841     // ...as ax1 and ax2 are unit length. if theta is smallish,
00842     // theta ~= sin(theta), so
00843     //    angular_velocity  = (erp*fps) * (ax1 x ax2)
00844     // ax1 x ax2 is in the plane space of ax1, so we project the angular
00845     // velocity to p and q to find the right hand side.
00846     k = info->fps * info->erp;
00847     btVector3 u = ax1A.cross(ax1B);
00848     info->m_constraintError[s3] = k * u.dot(p);
00849     info->m_constraintError[s4] = k * u.dot(q);
00850 #endif
00851     // check angular limits
00852     nrow = 4; // last filled row
00853     int srow;
00854     btScalar limit_err = btScalar(0.0);
00855     int limit = 0;
00856     if(getSolveLimit())
00857     {
00858 #ifdef  _BT_USE_CENTER_LIMIT_
00859     limit_err = m_limit.getCorrection() * m_referenceSign;
00860 #else
00861     limit_err = m_correction * m_referenceSign;
00862 #endif
00863     limit = (limit_err > btScalar(0.0)) ? 1 : 2;
00864 
00865     }
00866     // if the hinge has joint limits or motor, add in the extra row
00867     int powered = 0;
00868     if(getEnableAngularMotor())
00869     {
00870         powered = 1;
00871     }
00872     if(limit || powered) 
00873     {
00874         nrow++;
00875         srow = nrow * info->rowskip;
00876         info->m_J1angularAxis[srow+0] = ax1[0];
00877         info->m_J1angularAxis[srow+1] = ax1[1];
00878         info->m_J1angularAxis[srow+2] = ax1[2];
00879 
00880         info->m_J2angularAxis[srow+0] = -ax1[0];
00881         info->m_J2angularAxis[srow+1] = -ax1[1];
00882         info->m_J2angularAxis[srow+2] = -ax1[2];
00883 
00884         btScalar lostop = getLowerLimit();
00885         btScalar histop = getUpperLimit();
00886         if(limit && (lostop == histop))
00887         {  // the joint motor is ineffective
00888             powered = 0;
00889         }
00890         info->m_constraintError[srow] = btScalar(0.0f);
00891         btScalar currERP = (m_flags & BT_HINGE_FLAGS_ERP_STOP) ? m_stopERP : info->erp;
00892         if(powered)
00893         {
00894             if(m_flags & BT_HINGE_FLAGS_CFM_NORM)
00895             {
00896                 info->cfm[srow] = m_normalCFM;
00897             }
00898             btScalar mot_fact = getMotorFactor(m_hingeAngle, lostop, histop, m_motorTargetVelocity, info->fps * currERP);
00899             info->m_constraintError[srow] += mot_fact * m_motorTargetVelocity * m_referenceSign;
00900             info->m_lowerLimit[srow] = - m_maxMotorImpulse;
00901             info->m_upperLimit[srow] =   m_maxMotorImpulse;
00902         }
00903         if(limit)
00904         {
00905             k = info->fps * currERP;
00906             info->m_constraintError[srow] += k * limit_err;
00907             if(m_flags & BT_HINGE_FLAGS_CFM_STOP)
00908             {
00909                 info->cfm[srow] = m_stopCFM;
00910             }
00911             if(lostop == histop) 
00912             {
00913                 // limited low and high simultaneously
00914                 info->m_lowerLimit[srow] = -SIMD_INFINITY;
00915                 info->m_upperLimit[srow] = SIMD_INFINITY;
00916             }
00917             else if(limit == 1) 
00918             { // low limit
00919                 info->m_lowerLimit[srow] = 0;
00920                 info->m_upperLimit[srow] = SIMD_INFINITY;
00921             }
00922             else 
00923             { // high limit
00924                 info->m_lowerLimit[srow] = -SIMD_INFINITY;
00925                 info->m_upperLimit[srow] = 0;
00926             }
00927             // bounce (we'll use slider parameter abs(1.0 - m_dampingLimAng) for that)
00928 #ifdef  _BT_USE_CENTER_LIMIT_
00929             btScalar bounce = m_limit.getRelaxationFactor();
00930 #else
00931             btScalar bounce = m_relaxationFactor;
00932 #endif
00933             if(bounce > btScalar(0.0))
00934             {
00935                 btScalar vel = angVelA.dot(ax1);
00936                 vel -= angVelB.dot(ax1);
00937                 // only apply bounce if the velocity is incoming, and if the
00938                 // resulting c[] exceeds what we already have.
00939                 if(limit == 1)
00940                 {   // low limit
00941                     if(vel < 0)
00942                     {
00943                         btScalar newc = -bounce * vel;
00944                         if(newc > info->m_constraintError[srow])
00945                         {
00946                             info->m_constraintError[srow] = newc;
00947                         }
00948                     }
00949                 }
00950                 else
00951                 {   // high limit - all those computations are reversed
00952                     if(vel > 0)
00953                     {
00954                         btScalar newc = -bounce * vel;
00955                         if(newc < info->m_constraintError[srow])
00956                         {
00957                             info->m_constraintError[srow] = newc;
00958                         }
00959                     }
00960                 }
00961             }
00962 #ifdef  _BT_USE_CENTER_LIMIT_
00963             info->m_constraintError[srow] *= m_limit.getBiasFactor();
00964 #else
00965             info->m_constraintError[srow] *= m_biasFactor;
00966 #endif
00967         } // if(limit)
00968     } // if angular limit or powered
00969 }
00970 
00971 
00974 void btHingeConstraint::setParam(int num, btScalar value, int axis)
00975 {
00976     if((axis == -1) || (axis == 5))
00977     {
00978         switch(num)
00979         {   
00980             case BT_CONSTRAINT_STOP_ERP :
00981                 m_stopERP = value;
00982                 m_flags |= BT_HINGE_FLAGS_ERP_STOP;
00983                 break;
00984             case BT_CONSTRAINT_STOP_CFM :
00985                 m_stopCFM = value;
00986                 m_flags |= BT_HINGE_FLAGS_CFM_STOP;
00987                 break;
00988             case BT_CONSTRAINT_CFM :
00989                 m_normalCFM = value;
00990                 m_flags |= BT_HINGE_FLAGS_CFM_NORM;
00991                 break;
00992             default : 
00993                 btAssertConstrParams(0);
00994         }
00995     }
00996     else
00997     {
00998         btAssertConstrParams(0);
00999     }
01000 }
01001 
01003 btScalar btHingeConstraint::getParam(int num, int axis) const 
01004 {
01005     btScalar retVal = 0;
01006     if((axis == -1) || (axis == 5))
01007     {
01008         switch(num)
01009         {   
01010             case BT_CONSTRAINT_STOP_ERP :
01011                 btAssertConstrParams(m_flags & BT_HINGE_FLAGS_ERP_STOP);
01012                 retVal = m_stopERP;
01013                 break;
01014             case BT_CONSTRAINT_STOP_CFM :
01015                 btAssertConstrParams(m_flags & BT_HINGE_FLAGS_CFM_STOP);
01016                 retVal = m_stopCFM;
01017                 break;
01018             case BT_CONSTRAINT_CFM :
01019                 btAssertConstrParams(m_flags & BT_HINGE_FLAGS_CFM_NORM);
01020                 retVal = m_normalCFM;
01021                 break;
01022             default : 
01023                 btAssertConstrParams(0);
01024         }
01025     }
01026     else
01027     {
01028         btAssertConstrParams(0);
01029     }
01030     return retVal;
01031 }
01032 
01033