Blender  V2.59
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