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

Generated on Mon Feb 15 22:17:04 2010 for Bullet Collision Detection & Physics Library by  doxygen 1.6.1