btConeTwistConstraint.cpp

Go to the documentation of this file.
00001 /*
00002 Bullet Continuous Collision Detection and Physics Library
00003 btConeTwistConstraint is Copyright (c) 2007 Starbreeze Studios
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 Written by: Marcus Hennix
00016 */
00017 
00018 
00019 #include "btConeTwistConstraint.h"
00020 #include "BulletDynamics/Dynamics/btRigidBody.h"
00021 #include "LinearMath/btTransformUtil.h"
00022 #include "LinearMath/btMinMax.h"
00023 #include <new>
00024 
00025 
00026 
00027 //#define CONETWIST_USE_OBSOLETE_SOLVER true
00028 #define CONETWIST_USE_OBSOLETE_SOLVER false
00029 #define CONETWIST_DEF_FIX_THRESH btScalar(.05f)
00030 
00031 
00032 SIMD_FORCE_INLINE btScalar computeAngularImpulseDenominator(const btVector3& axis, const btMatrix3x3& invInertiaWorld)
00033 {
00034         btVector3 vec = axis * invInertiaWorld;
00035         return axis.dot(vec);
00036 }
00037 
00038 
00039 
00040 
00041 btConeTwistConstraint::btConeTwistConstraint(btRigidBody& rbA,btRigidBody& rbB, 
00042                                                                                          const btTransform& rbAFrame,const btTransform& rbBFrame)
00043                                                                                          :btTypedConstraint(CONETWIST_CONSTRAINT_TYPE, rbA,rbB),m_rbAFrame(rbAFrame),m_rbBFrame(rbBFrame),
00044                                                                                          m_angularOnly(false),
00045                                                                                          m_useSolveConstraintObsolete(CONETWIST_USE_OBSOLETE_SOLVER)
00046 {
00047         init();
00048 }
00049 
00050 btConeTwistConstraint::btConeTwistConstraint(btRigidBody& rbA,const btTransform& rbAFrame)
00051                                                                                         :btTypedConstraint(CONETWIST_CONSTRAINT_TYPE,rbA),m_rbAFrame(rbAFrame),
00052                                                                                          m_angularOnly(false),
00053                                                                                          m_useSolveConstraintObsolete(CONETWIST_USE_OBSOLETE_SOLVER)
00054 {
00055         m_rbBFrame = m_rbAFrame;
00056         init(); 
00057 }
00058 
00059 
00060 void btConeTwistConstraint::init()
00061 {
00062         m_angularOnly = false;
00063         m_solveTwistLimit = false;
00064         m_solveSwingLimit = false;
00065         m_bMotorEnabled = false;
00066         m_maxMotorImpulse = btScalar(-1);
00067 
00068         setLimit(btScalar(BT_LARGE_FLOAT), btScalar(BT_LARGE_FLOAT), btScalar(BT_LARGE_FLOAT));
00069         m_damping = btScalar(0.01);
00070         m_fixThresh = CONETWIST_DEF_FIX_THRESH;
00071         m_flags = 0;
00072         m_linCFM = btScalar(0.f);
00073         m_linERP = btScalar(0.7f);
00074         m_angCFM = btScalar(0.f);
00075 }
00076 
00077 
00078 void btConeTwistConstraint::getInfo1 (btConstraintInfo1* info)
00079 {
00080         if (m_useSolveConstraintObsolete)
00081         {
00082                 info->m_numConstraintRows = 0;
00083                 info->nub = 0;
00084         } 
00085         else
00086         {
00087                 info->m_numConstraintRows = 3;
00088                 info->nub = 3;
00089                 calcAngleInfo2(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform(),m_rbA.getInvInertiaTensorWorld(),m_rbB.getInvInertiaTensorWorld());
00090                 if(m_solveSwingLimit)
00091                 {
00092                         info->m_numConstraintRows++;
00093                         info->nub--;
00094                         if((m_swingSpan1 < m_fixThresh) && (m_swingSpan2 < m_fixThresh))
00095                         {
00096                                 info->m_numConstraintRows++;
00097                                 info->nub--;
00098                         }
00099                 }
00100                 if(m_solveTwistLimit)
00101                 {
00102                         info->m_numConstraintRows++;
00103                         info->nub--;
00104                 }
00105         }
00106 }
00107 
00108 void btConeTwistConstraint::getInfo1NonVirtual (btConstraintInfo1* info)
00109 {
00110         //always reserve 6 rows: object transform is not available on SPU
00111         info->m_numConstraintRows = 6;
00112         info->nub = 0;
00113                 
00114 }
00115         
00116 
00117 void btConeTwistConstraint::getInfo2 (btConstraintInfo2* info)
00118 {
00119         getInfo2NonVirtual(info,m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform(),m_rbA.getInvInertiaTensorWorld(),m_rbB.getInvInertiaTensorWorld());
00120 }
00121 
00122 void btConeTwistConstraint::getInfo2NonVirtual (btConstraintInfo2* info,const btTransform& transA,const btTransform& transB,const btMatrix3x3& invInertiaWorldA,const btMatrix3x3& invInertiaWorldB)
00123 {
00124         calcAngleInfo2(transA,transB,invInertiaWorldA,invInertiaWorldB);
00125         
00126         btAssert(!m_useSolveConstraintObsolete);
00127     // set jacobian
00128     info->m_J1linearAxis[0] = 1;
00129     info->m_J1linearAxis[info->rowskip+1] = 1;
00130     info->m_J1linearAxis[2*info->rowskip+2] = 1;
00131         btVector3 a1 = transA.getBasis() * m_rbAFrame.getOrigin();
00132         {
00133                 btVector3* angular0 = (btVector3*)(info->m_J1angularAxis);
00134                 btVector3* angular1 = (btVector3*)(info->m_J1angularAxis+info->rowskip);
00135                 btVector3* angular2 = (btVector3*)(info->m_J1angularAxis+2*info->rowskip);
00136                 btVector3 a1neg = -a1;
00137                 a1neg.getSkewSymmetricMatrix(angular0,angular1,angular2);
00138         }
00139         btVector3 a2 = transB.getBasis() * m_rbBFrame.getOrigin();
00140         {
00141                 btVector3* angular0 = (btVector3*)(info->m_J2angularAxis);
00142                 btVector3* angular1 = (btVector3*)(info->m_J2angularAxis+info->rowskip);
00143                 btVector3* angular2 = (btVector3*)(info->m_J2angularAxis+2*info->rowskip);
00144                 a2.getSkewSymmetricMatrix(angular0,angular1,angular2);
00145         }
00146     // set right hand side
00147         btScalar linERP = (m_flags & BT_CONETWIST_FLAGS_LIN_ERP) ? m_linERP : info->erp;
00148     btScalar k = info->fps * linERP;
00149     int j;
00150         for (j=0; j<3; j++)
00151     {
00152         info->m_constraintError[j*info->rowskip] = k * (a2[j] + transB.getOrigin()[j] - a1[j] - transA.getOrigin()[j]);
00153                 info->m_lowerLimit[j*info->rowskip] = -SIMD_INFINITY;
00154                 info->m_upperLimit[j*info->rowskip] = SIMD_INFINITY;
00155                 if(m_flags & BT_CONETWIST_FLAGS_LIN_CFM)
00156                 {
00157                         info->cfm[j*info->rowskip] = m_linCFM;
00158                 }
00159     }
00160         int row = 3;
00161     int srow = row * info->rowskip;
00162         btVector3 ax1;
00163         // angular limits
00164         if(m_solveSwingLimit)
00165         {
00166                 btScalar *J1 = info->m_J1angularAxis;
00167                 btScalar *J2 = info->m_J2angularAxis;
00168                 if((m_swingSpan1 < m_fixThresh) && (m_swingSpan2 < m_fixThresh))
00169                 {
00170                         btTransform trA = transA*m_rbAFrame;
00171                         btVector3 p = trA.getBasis().getColumn(1);
00172                         btVector3 q = trA.getBasis().getColumn(2);
00173                         int srow1 = srow + info->rowskip;
00174                         J1[srow+0] = p[0];
00175                         J1[srow+1] = p[1];
00176                         J1[srow+2] = p[2];
00177                         J1[srow1+0] = q[0];
00178                         J1[srow1+1] = q[1];
00179                         J1[srow1+2] = q[2];
00180                         J2[srow+0] = -p[0];
00181                         J2[srow+1] = -p[1];
00182                         J2[srow+2] = -p[2];
00183                         J2[srow1+0] = -q[0];
00184                         J2[srow1+1] = -q[1];
00185                         J2[srow1+2] = -q[2];
00186                         btScalar fact = info->fps * m_relaxationFactor;
00187                         info->m_constraintError[srow] =   fact * m_swingAxis.dot(p);
00188                         info->m_constraintError[srow1] =  fact * m_swingAxis.dot(q);
00189                         info->m_lowerLimit[srow] = -SIMD_INFINITY;
00190                         info->m_upperLimit[srow] = SIMD_INFINITY;
00191                         info->m_lowerLimit[srow1] = -SIMD_INFINITY;
00192                         info->m_upperLimit[srow1] = SIMD_INFINITY;
00193                         srow = srow1 + info->rowskip;
00194                 }
00195                 else
00196                 {
00197                         ax1 = m_swingAxis * m_relaxationFactor * m_relaxationFactor;
00198                         J1[srow+0] = ax1[0];
00199                         J1[srow+1] = ax1[1];
00200                         J1[srow+2] = ax1[2];
00201                         J2[srow+0] = -ax1[0];
00202                         J2[srow+1] = -ax1[1];
00203                         J2[srow+2] = -ax1[2];
00204                         btScalar k = info->fps * m_biasFactor;
00205 
00206                         info->m_constraintError[srow] = k * m_swingCorrection;
00207                         if(m_flags & BT_CONETWIST_FLAGS_ANG_CFM)
00208                         {
00209                                 info->cfm[srow] = m_angCFM;
00210                         }
00211                         // m_swingCorrection is always positive or 0
00212                         info->m_lowerLimit[srow] = 0;
00213                         info->m_upperLimit[srow] = SIMD_INFINITY;
00214                         srow += info->rowskip;
00215                 }
00216         }
00217         if(m_solveTwistLimit)
00218         {
00219                 ax1 = m_twistAxis * m_relaxationFactor * m_relaxationFactor;
00220                 btScalar *J1 = info->m_J1angularAxis;
00221                 btScalar *J2 = info->m_J2angularAxis;
00222                 J1[srow+0] = ax1[0];
00223                 J1[srow+1] = ax1[1];
00224                 J1[srow+2] = ax1[2];
00225                 J2[srow+0] = -ax1[0];
00226                 J2[srow+1] = -ax1[1];
00227                 J2[srow+2] = -ax1[2];
00228                 btScalar k = info->fps * m_biasFactor;
00229                 info->m_constraintError[srow] = k * m_twistCorrection;
00230                 if(m_flags & BT_CONETWIST_FLAGS_ANG_CFM)
00231                 {
00232                         info->cfm[srow] = m_angCFM;
00233                 }
00234                 if(m_twistSpan > 0.0f)
00235                 {
00236 
00237                         if(m_twistCorrection > 0.0f)
00238                         {
00239                                 info->m_lowerLimit[srow] = 0;
00240                                 info->m_upperLimit[srow] = SIMD_INFINITY;
00241                         } 
00242                         else
00243                         {
00244                                 info->m_lowerLimit[srow] = -SIMD_INFINITY;
00245                                 info->m_upperLimit[srow] = 0;
00246                         } 
00247                 }
00248                 else
00249                 {
00250                         info->m_lowerLimit[srow] = -SIMD_INFINITY;
00251                         info->m_upperLimit[srow] = SIMD_INFINITY;
00252                 }
00253                 srow += info->rowskip;
00254         }
00255 }
00256         
00257 
00258 
00259 void    btConeTwistConstraint::buildJacobian()
00260 {
00261         if (m_useSolveConstraintObsolete)
00262         {
00263                 m_appliedImpulse = btScalar(0.);
00264                 m_accTwistLimitImpulse = btScalar(0.);
00265                 m_accSwingLimitImpulse = btScalar(0.);
00266                 m_accMotorImpulse = btVector3(0.,0.,0.);
00267 
00268                 if (!m_angularOnly)
00269                 {
00270                         btVector3 pivotAInW = m_rbA.getCenterOfMassTransform()*m_rbAFrame.getOrigin();
00271                         btVector3 pivotBInW = m_rbB.getCenterOfMassTransform()*m_rbBFrame.getOrigin();
00272                         btVector3 relPos = pivotBInW - pivotAInW;
00273 
00274                         btVector3 normal[3];
00275                         if (relPos.length2() > SIMD_EPSILON)
00276                         {
00277                                 normal[0] = relPos.normalized();
00278                         }
00279                         else
00280                         {
00281                                 normal[0].setValue(btScalar(1.0),0,0);
00282                         }
00283 
00284                         btPlaneSpace1(normal[0], normal[1], normal[2]);
00285 
00286                         for (int i=0;i<3;i++)
00287                         {
00288                                 new (&m_jac[i]) btJacobianEntry(
00289                                 m_rbA.getCenterOfMassTransform().getBasis().transpose(),
00290                                 m_rbB.getCenterOfMassTransform().getBasis().transpose(),
00291                                 pivotAInW - m_rbA.getCenterOfMassPosition(),
00292                                 pivotBInW - m_rbB.getCenterOfMassPosition(),
00293                                 normal[i],
00294                                 m_rbA.getInvInertiaDiagLocal(),
00295                                 m_rbA.getInvMass(),
00296                                 m_rbB.getInvInertiaDiagLocal(),
00297                                 m_rbB.getInvMass());
00298                         }
00299                 }
00300 
00301                 calcAngleInfo2(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform(),m_rbA.getInvInertiaTensorWorld(),m_rbB.getInvInertiaTensorWorld());
00302         }
00303 }
00304 
00305 
00306 
00307 void    btConeTwistConstraint::solveConstraintObsolete(btRigidBody& bodyA,btRigidBody& bodyB,btScalar   timeStep)
00308 {
00309         #ifndef __SPU__
00310         if (m_useSolveConstraintObsolete)
00311         {
00312                 btVector3 pivotAInW = m_rbA.getCenterOfMassTransform()*m_rbAFrame.getOrigin();
00313                 btVector3 pivotBInW = m_rbB.getCenterOfMassTransform()*m_rbBFrame.getOrigin();
00314 
00315                 btScalar tau = btScalar(0.3);
00316 
00317                 //linear part
00318                 if (!m_angularOnly)
00319                 {
00320                         btVector3 rel_pos1 = pivotAInW - m_rbA.getCenterOfMassPosition(); 
00321                         btVector3 rel_pos2 = pivotBInW - m_rbB.getCenterOfMassPosition();
00322 
00323                         btVector3 vel1;
00324                         bodyA.internalGetVelocityInLocalPointObsolete(rel_pos1,vel1);
00325                         btVector3 vel2;
00326                         bodyB.internalGetVelocityInLocalPointObsolete(rel_pos2,vel2);
00327                         btVector3 vel = vel1 - vel2;
00328 
00329                         for (int i=0;i<3;i++)
00330                         {               
00331                                 const btVector3& normal = m_jac[i].m_linearJointAxis;
00332                                 btScalar jacDiagABInv = btScalar(1.) / m_jac[i].getDiagonal();
00333 
00334                                 btScalar rel_vel;
00335                                 rel_vel = normal.dot(vel);
00336                                 //positional error (zeroth order error)
00337                                 btScalar depth = -(pivotAInW - pivotBInW).dot(normal); //this is the error projected on the normal
00338                                 btScalar impulse = depth*tau/timeStep  * jacDiagABInv -  rel_vel * jacDiagABInv;
00339                                 m_appliedImpulse += impulse;
00340                                 
00341                                 btVector3 ftorqueAxis1 = rel_pos1.cross(normal);
00342                                 btVector3 ftorqueAxis2 = rel_pos2.cross(normal);
00343                                 bodyA.internalApplyImpulse(normal*m_rbA.getInvMass(), m_rbA.getInvInertiaTensorWorld()*ftorqueAxis1,impulse);
00344                                 bodyB.internalApplyImpulse(normal*m_rbB.getInvMass(), m_rbB.getInvInertiaTensorWorld()*ftorqueAxis2,-impulse);
00345                 
00346                         }
00347                 }
00348 
00349                 // apply motor
00350                 if (m_bMotorEnabled)
00351                 {
00352                         // compute current and predicted transforms
00353                         btTransform trACur = m_rbA.getCenterOfMassTransform();
00354                         btTransform trBCur = m_rbB.getCenterOfMassTransform();
00355                         btVector3 omegaA; bodyA.internalGetAngularVelocity(omegaA);
00356                         btVector3 omegaB; bodyB.internalGetAngularVelocity(omegaB);
00357                         btTransform trAPred; trAPred.setIdentity(); 
00358                         btVector3 zerovec(0,0,0);
00359                         btTransformUtil::integrateTransform(
00360                                 trACur, zerovec, omegaA, timeStep, trAPred);
00361                         btTransform trBPred; trBPred.setIdentity(); 
00362                         btTransformUtil::integrateTransform(
00363                                 trBCur, zerovec, omegaB, timeStep, trBPred);
00364 
00365                         // compute desired transforms in world
00366                         btTransform trPose(m_qTarget);
00367                         btTransform trABDes = m_rbBFrame * trPose * m_rbAFrame.inverse();
00368                         btTransform trADes = trBPred * trABDes;
00369                         btTransform trBDes = trAPred * trABDes.inverse();
00370 
00371                         // compute desired omegas in world
00372                         btVector3 omegaADes, omegaBDes;
00373                         
00374                         btTransformUtil::calculateVelocity(trACur, trADes, timeStep, zerovec, omegaADes);
00375                         btTransformUtil::calculateVelocity(trBCur, trBDes, timeStep, zerovec, omegaBDes);
00376 
00377                         // compute delta omegas
00378                         btVector3 dOmegaA = omegaADes - omegaA;
00379                         btVector3 dOmegaB = omegaBDes - omegaB;
00380 
00381                         // compute weighted avg axis of dOmega (weighting based on inertias)
00382                         btVector3 axisA, axisB;
00383                         btScalar kAxisAInv = 0, kAxisBInv = 0;
00384 
00385                         if (dOmegaA.length2() > SIMD_EPSILON)
00386                         {
00387                                 axisA = dOmegaA.normalized();
00388                                 kAxisAInv = getRigidBodyA().computeAngularImpulseDenominator(axisA);
00389                         }
00390 
00391                         if (dOmegaB.length2() > SIMD_EPSILON)
00392                         {
00393                                 axisB = dOmegaB.normalized();
00394                                 kAxisBInv = getRigidBodyB().computeAngularImpulseDenominator(axisB);
00395                         }
00396 
00397                         btVector3 avgAxis = kAxisAInv * axisA + kAxisBInv * axisB;
00398 
00399                         static bool bDoTorque = true;
00400                         if (bDoTorque && avgAxis.length2() > SIMD_EPSILON)
00401                         {
00402                                 avgAxis.normalize();
00403                                 kAxisAInv = getRigidBodyA().computeAngularImpulseDenominator(avgAxis);
00404                                 kAxisBInv = getRigidBodyB().computeAngularImpulseDenominator(avgAxis);
00405                                 btScalar kInvCombined = kAxisAInv + kAxisBInv;
00406 
00407                                 btVector3 impulse = (kAxisAInv * dOmegaA - kAxisBInv * dOmegaB) /
00408                                                                         (kInvCombined * kInvCombined);
00409 
00410                                 if (m_maxMotorImpulse >= 0)
00411                                 {
00412                                         btScalar fMaxImpulse = m_maxMotorImpulse;
00413                                         if (m_bNormalizedMotorStrength)
00414                                                 fMaxImpulse = fMaxImpulse/kAxisAInv;
00415 
00416                                         btVector3 newUnclampedAccImpulse = m_accMotorImpulse + impulse;
00417                                         btScalar  newUnclampedMag = newUnclampedAccImpulse.length();
00418                                         if (newUnclampedMag > fMaxImpulse)
00419                                         {
00420                                                 newUnclampedAccImpulse.normalize();
00421                                                 newUnclampedAccImpulse *= fMaxImpulse;
00422                                                 impulse = newUnclampedAccImpulse - m_accMotorImpulse;
00423                                         }
00424                                         m_accMotorImpulse += impulse;
00425                                 }
00426 
00427                                 btScalar  impulseMag  = impulse.length();
00428                                 btVector3 impulseAxis =  impulse / impulseMag;
00429 
00430                                 bodyA.internalApplyImpulse(btVector3(0,0,0), m_rbA.getInvInertiaTensorWorld()*impulseAxis, impulseMag);
00431                                 bodyB.internalApplyImpulse(btVector3(0,0,0), m_rbB.getInvInertiaTensorWorld()*impulseAxis, -impulseMag);
00432 
00433                         }
00434                 }
00435                 else if (m_damping > SIMD_EPSILON) // no motor: do a little damping
00436                 {
00437                         btVector3 angVelA; bodyA.internalGetAngularVelocity(angVelA);
00438                         btVector3 angVelB; bodyB.internalGetAngularVelocity(angVelB);
00439                         btVector3 relVel = angVelB - angVelA;
00440                         if (relVel.length2() > SIMD_EPSILON)
00441                         {
00442                                 btVector3 relVelAxis = relVel.normalized();
00443                                 btScalar m_kDamping =  btScalar(1.) /
00444                                         (getRigidBodyA().computeAngularImpulseDenominator(relVelAxis) +
00445                                          getRigidBodyB().computeAngularImpulseDenominator(relVelAxis));
00446                                 btVector3 impulse = m_damping * m_kDamping * relVel;
00447 
00448                                 btScalar  impulseMag  = impulse.length();
00449                                 btVector3 impulseAxis = impulse / impulseMag;
00450                                 bodyA.internalApplyImpulse(btVector3(0,0,0), m_rbA.getInvInertiaTensorWorld()*impulseAxis, impulseMag);
00451                                 bodyB.internalApplyImpulse(btVector3(0,0,0), m_rbB.getInvInertiaTensorWorld()*impulseAxis, -impulseMag);
00452                         }
00453                 }
00454 
00455                 // joint limits
00456                 {
00458                         btVector3 angVelA;
00459                         bodyA.internalGetAngularVelocity(angVelA);
00460                         btVector3 angVelB;
00461                         bodyB.internalGetAngularVelocity(angVelB);
00462 
00463                         // solve swing limit
00464                         if (m_solveSwingLimit)
00465                         {
00466                                 btScalar amplitude = m_swingLimitRatio * m_swingCorrection*m_biasFactor/timeStep;
00467                                 btScalar relSwingVel = (angVelB - angVelA).dot(m_swingAxis);
00468                                 if (relSwingVel > 0)
00469                                         amplitude += m_swingLimitRatio * relSwingVel * m_relaxationFactor;
00470                                 btScalar impulseMag = amplitude * m_kSwing;
00471 
00472                                 // Clamp the accumulated impulse
00473                                 btScalar temp = m_accSwingLimitImpulse;
00474                                 m_accSwingLimitImpulse = btMax(m_accSwingLimitImpulse + impulseMag, btScalar(0.0) );
00475                                 impulseMag = m_accSwingLimitImpulse - temp;
00476 
00477                                 btVector3 impulse = m_swingAxis * impulseMag;
00478 
00479                                 // don't let cone response affect twist
00480                                 // (this can happen since body A's twist doesn't match body B's AND we use an elliptical cone limit)
00481                                 {
00482                                         btVector3 impulseTwistCouple = impulse.dot(m_twistAxisA) * m_twistAxisA;
00483                                         btVector3 impulseNoTwistCouple = impulse - impulseTwistCouple;
00484                                         impulse = impulseNoTwistCouple;
00485                                 }
00486 
00487                                 impulseMag = impulse.length();
00488                                 btVector3 noTwistSwingAxis = impulse / impulseMag;
00489 
00490                                 bodyA.internalApplyImpulse(btVector3(0,0,0), m_rbA.getInvInertiaTensorWorld()*noTwistSwingAxis, impulseMag);
00491                                 bodyB.internalApplyImpulse(btVector3(0,0,0), m_rbB.getInvInertiaTensorWorld()*noTwistSwingAxis, -impulseMag);
00492                         }
00493 
00494 
00495                         // solve twist limit
00496                         if (m_solveTwistLimit)
00497                         {
00498                                 btScalar amplitude = m_twistLimitRatio * m_twistCorrection*m_biasFactor/timeStep;
00499                                 btScalar relTwistVel = (angVelB - angVelA).dot( m_twistAxis );
00500                                 if (relTwistVel > 0) // only damp when moving towards limit (m_twistAxis flipping is important)
00501                                         amplitude += m_twistLimitRatio * relTwistVel * m_relaxationFactor;
00502                                 btScalar impulseMag = amplitude * m_kTwist;
00503 
00504                                 // Clamp the accumulated impulse
00505                                 btScalar temp = m_accTwistLimitImpulse;
00506                                 m_accTwistLimitImpulse = btMax(m_accTwistLimitImpulse + impulseMag, btScalar(0.0) );
00507                                 impulseMag = m_accTwistLimitImpulse - temp;
00508 
00509                                 btVector3 impulse = m_twistAxis * impulseMag;
00510 
00511                                 bodyA.internalApplyImpulse(btVector3(0,0,0), m_rbA.getInvInertiaTensorWorld()*m_twistAxis,impulseMag);
00512                                 bodyB.internalApplyImpulse(btVector3(0,0,0), m_rbB.getInvInertiaTensorWorld()*m_twistAxis,-impulseMag);
00513                         }               
00514                 }
00515         }
00516 #else
00517 btAssert(0);
00518 #endif //__SPU__
00519 }
00520 
00521 
00522 
00523 
00524 void    btConeTwistConstraint::updateRHS(btScalar       timeStep)
00525 {
00526         (void)timeStep;
00527 
00528 }
00529 
00530 
00531 #ifndef __SPU__
00532 void btConeTwistConstraint::calcAngleInfo()
00533 {
00534         m_swingCorrection = btScalar(0.);
00535         m_twistLimitSign = btScalar(0.);
00536         m_solveTwistLimit = false;
00537         m_solveSwingLimit = false;
00538 
00539         btVector3 b1Axis1,b1Axis2,b1Axis3;
00540         btVector3 b2Axis1,b2Axis2;
00541 
00542         b1Axis1 = getRigidBodyA().getCenterOfMassTransform().getBasis() * this->m_rbAFrame.getBasis().getColumn(0);
00543         b2Axis1 = getRigidBodyB().getCenterOfMassTransform().getBasis() * this->m_rbBFrame.getBasis().getColumn(0);
00544 
00545         btScalar swing1=btScalar(0.),swing2 = btScalar(0.);
00546 
00547         btScalar swx=btScalar(0.),swy = btScalar(0.);
00548         btScalar thresh = btScalar(10.);
00549         btScalar fact;
00550 
00551         // Get Frame into world space
00552         if (m_swingSpan1 >= btScalar(0.05f))
00553         {
00554                 b1Axis2 = getRigidBodyA().getCenterOfMassTransform().getBasis() * this->m_rbAFrame.getBasis().getColumn(1);
00555                 swx = b2Axis1.dot(b1Axis1);
00556                 swy = b2Axis1.dot(b1Axis2);
00557                 swing1  = btAtan2Fast(swy, swx);
00558                 fact = (swy*swy + swx*swx) * thresh * thresh;
00559                 fact = fact / (fact + btScalar(1.0));
00560                 swing1 *= fact; 
00561         }
00562 
00563         if (m_swingSpan2 >= btScalar(0.05f))
00564         {
00565                 b1Axis3 = getRigidBodyA().getCenterOfMassTransform().getBasis() * this->m_rbAFrame.getBasis().getColumn(2);                     
00566                 swx = b2Axis1.dot(b1Axis1);
00567                 swy = b2Axis1.dot(b1Axis3);
00568                 swing2  = btAtan2Fast(swy, swx);
00569                 fact = (swy*swy + swx*swx) * thresh * thresh;
00570                 fact = fact / (fact + btScalar(1.0));
00571                 swing2 *= fact; 
00572         }
00573 
00574         btScalar RMaxAngle1Sq = 1.0f / (m_swingSpan1*m_swingSpan1);             
00575         btScalar RMaxAngle2Sq = 1.0f / (m_swingSpan2*m_swingSpan2);     
00576         btScalar EllipseAngle = btFabs(swing1*swing1)* RMaxAngle1Sq + btFabs(swing2*swing2) * RMaxAngle2Sq;
00577 
00578         if (EllipseAngle > 1.0f)
00579         {
00580                 m_swingCorrection = EllipseAngle-1.0f;
00581                 m_solveSwingLimit = true;
00582                 // Calculate necessary axis & factors
00583                 m_swingAxis = b2Axis1.cross(b1Axis2* b2Axis1.dot(b1Axis2) + b1Axis3* b2Axis1.dot(b1Axis3));
00584                 m_swingAxis.normalize();
00585                 btScalar swingAxisSign = (b2Axis1.dot(b1Axis1) >= 0.0f) ? 1.0f : -1.0f;
00586                 m_swingAxis *= swingAxisSign;
00587         }
00588 
00589         // Twist limits
00590         if (m_twistSpan >= btScalar(0.))
00591         {
00592                 btVector3 b2Axis2 = getRigidBodyB().getCenterOfMassTransform().getBasis() * this->m_rbBFrame.getBasis().getColumn(1);
00593                 btQuaternion rotationArc = shortestArcQuat(b2Axis1,b1Axis1);
00594                 btVector3 TwistRef = quatRotate(rotationArc,b2Axis2); 
00595                 btScalar twist = btAtan2Fast( TwistRef.dot(b1Axis3), TwistRef.dot(b1Axis2) );
00596                 m_twistAngle = twist;
00597 
00598 //              btScalar lockedFreeFactor = (m_twistSpan > btScalar(0.05f)) ? m_limitSoftness : btScalar(0.);
00599                 btScalar lockedFreeFactor = (m_twistSpan > btScalar(0.05f)) ? btScalar(1.0f) : btScalar(0.);
00600                 if (twist <= -m_twistSpan*lockedFreeFactor)
00601                 {
00602                         m_twistCorrection = -(twist + m_twistSpan);
00603                         m_solveTwistLimit = true;
00604                         m_twistAxis = (b2Axis1 + b1Axis1) * 0.5f;
00605                         m_twistAxis.normalize();
00606                         m_twistAxis *= -1.0f;
00607                 }
00608                 else if (twist >  m_twistSpan*lockedFreeFactor)
00609                 {
00610                         m_twistCorrection = (twist - m_twistSpan);
00611                         m_solveTwistLimit = true;
00612                         m_twistAxis = (b2Axis1 + b1Axis1) * 0.5f;
00613                         m_twistAxis.normalize();
00614                 }
00615         }
00616 }
00617 #endif //__SPU__
00618 
00619 static btVector3 vTwist(1,0,0); // twist axis in constraint's space
00620 
00621 
00622 
00623 void btConeTwistConstraint::calcAngleInfo2(const btTransform& transA, const btTransform& transB, const btMatrix3x3& invInertiaWorldA,const btMatrix3x3& invInertiaWorldB)
00624 {
00625         m_swingCorrection = btScalar(0.);
00626         m_twistLimitSign = btScalar(0.);
00627         m_solveTwistLimit = false;
00628         m_solveSwingLimit = false;
00629         // compute rotation of A wrt B (in constraint space)
00630         if (m_bMotorEnabled && (!m_useSolveConstraintObsolete))
00631         {       // it is assumed that setMotorTarget() was alredy called 
00632                 // and motor target m_qTarget is within constraint limits
00633                 // TODO : split rotation to pure swing and pure twist
00634                 // compute desired transforms in world
00635                 btTransform trPose(m_qTarget);
00636                 btTransform trA = transA * m_rbAFrame;
00637                 btTransform trB = transB * m_rbBFrame;
00638                 btTransform trDeltaAB = trB * trPose * trA.inverse();
00639                 btQuaternion qDeltaAB = trDeltaAB.getRotation();
00640                 btVector3 swingAxis =   btVector3(qDeltaAB.x(), qDeltaAB.y(), qDeltaAB.z());
00641                 m_swingAxis = swingAxis;
00642                 m_swingAxis.normalize();
00643                 m_swingCorrection = qDeltaAB.getAngle();
00644                 if(!btFuzzyZero(m_swingCorrection))
00645                 {
00646                         m_solveSwingLimit = true;
00647                 }
00648                 return;
00649         }
00650 
00651 
00652         {
00653                 // compute rotation of A wrt B (in constraint space)
00654                 btQuaternion qA = transA.getRotation() * m_rbAFrame.getRotation();
00655                 btQuaternion qB = transB.getRotation() * m_rbBFrame.getRotation();
00656                 btQuaternion qAB = qB.inverse() * qA;
00657                 // split rotation into cone and twist
00658                 // (all this is done from B's perspective. Maybe I should be averaging axes...)
00659                 btVector3 vConeNoTwist = quatRotate(qAB, vTwist); vConeNoTwist.normalize();
00660                 btQuaternion qABCone  = shortestArcQuat(vTwist, vConeNoTwist); qABCone.normalize();
00661                 btQuaternion qABTwist = qABCone.inverse() * qAB; qABTwist.normalize();
00662 
00663                 if (m_swingSpan1 >= m_fixThresh && m_swingSpan2 >= m_fixThresh)
00664                 {
00665                         btScalar swingAngle, swingLimit = 0; btVector3 swingAxis;
00666                         computeConeLimitInfo(qABCone, swingAngle, swingAxis, swingLimit);
00667 
00668                         if (swingAngle > swingLimit * m_limitSoftness)
00669                         {
00670                                 m_solveSwingLimit = true;
00671 
00672                                 // compute limit ratio: 0->1, where
00673                                 // 0 == beginning of soft limit
00674                                 // 1 == hard/real limit
00675                                 m_swingLimitRatio = 1.f;
00676                                 if (swingAngle < swingLimit && m_limitSoftness < 1.f - SIMD_EPSILON)
00677                                 {
00678                                         m_swingLimitRatio = (swingAngle - swingLimit * m_limitSoftness)/
00679                                                                                 (swingLimit - swingLimit * m_limitSoftness);
00680                                 }                               
00681 
00682                                 // swing correction tries to get back to soft limit
00683                                 m_swingCorrection = swingAngle - (swingLimit * m_limitSoftness);
00684 
00685                                 // adjustment of swing axis (based on ellipse normal)
00686                                 adjustSwingAxisToUseEllipseNormal(swingAxis);
00687 
00688                                 // Calculate necessary axis & factors           
00689                                 m_swingAxis = quatRotate(qB, -swingAxis);
00690 
00691                                 m_twistAxisA.setValue(0,0,0);
00692 
00693                                 m_kSwing =  btScalar(1.) /
00694                                         (computeAngularImpulseDenominator(m_swingAxis,invInertiaWorldA) +
00695                                          computeAngularImpulseDenominator(m_swingAxis,invInertiaWorldB));
00696                         }
00697                 }
00698                 else
00699                 {
00700                         // you haven't set any limits;
00701                         // or you're trying to set at least one of the swing limits too small. (if so, do you really want a conetwist constraint?)
00702                         // anyway, we have either hinge or fixed joint
00703                         btVector3 ivA = transA.getBasis() * m_rbAFrame.getBasis().getColumn(0);
00704                         btVector3 jvA = transA.getBasis() * m_rbAFrame.getBasis().getColumn(1);
00705                         btVector3 kvA = transA.getBasis() * m_rbAFrame.getBasis().getColumn(2);
00706                         btVector3 ivB = transB.getBasis() * m_rbBFrame.getBasis().getColumn(0);
00707                         btVector3 target;
00708                         btScalar x = ivB.dot(ivA);
00709                         btScalar y = ivB.dot(jvA);
00710                         btScalar z = ivB.dot(kvA);
00711                         if((m_swingSpan1 < m_fixThresh) && (m_swingSpan2 < m_fixThresh))
00712                         { // fixed. We'll need to add one more row to constraint
00713                                 if((!btFuzzyZero(y)) || (!(btFuzzyZero(z))))
00714                                 {
00715                                         m_solveSwingLimit = true;
00716                                         m_swingAxis = -ivB.cross(ivA);
00717                                 }
00718                         }
00719                         else
00720                         {
00721                                 if(m_swingSpan1 < m_fixThresh)
00722                                 { // hinge around Y axis
00723                                         if(!(btFuzzyZero(y)))
00724                                         {
00725                                                 m_solveSwingLimit = true;
00726                                                 if(m_swingSpan2 >= m_fixThresh)
00727                                                 {
00728                                                         y = btScalar(0.f);
00729                                                         btScalar span2 = btAtan2(z, x);
00730                                                         if(span2 > m_swingSpan2)
00731                                                         {
00732                                                                 x = btCos(m_swingSpan2);
00733                                                                 z = btSin(m_swingSpan2);
00734                                                         }
00735                                                         else if(span2 < -m_swingSpan2)
00736                                                         {
00737                                                                 x =  btCos(m_swingSpan2);
00738                                                                 z = -btSin(m_swingSpan2);
00739                                                         }
00740                                                 }
00741                                         }
00742                                 }
00743                                 else
00744                                 { // hinge around Z axis
00745                                         if(!btFuzzyZero(z))
00746                                         {
00747                                                 m_solveSwingLimit = true;
00748                                                 if(m_swingSpan1 >= m_fixThresh)
00749                                                 {
00750                                                         z = btScalar(0.f);
00751                                                         btScalar span1 = btAtan2(y, x);
00752                                                         if(span1 > m_swingSpan1)
00753                                                         {
00754                                                                 x = btCos(m_swingSpan1);
00755                                                                 y = btSin(m_swingSpan1);
00756                                                         }
00757                                                         else if(span1 < -m_swingSpan1)
00758                                                         {
00759                                                                 x =  btCos(m_swingSpan1);
00760                                                                 y = -btSin(m_swingSpan1);
00761                                                         }
00762                                                 }
00763                                         }
00764                                 }
00765                                 target[0] = x * ivA[0] + y * jvA[0] + z * kvA[0];
00766                                 target[1] = x * ivA[1] + y * jvA[1] + z * kvA[1];
00767                                 target[2] = x * ivA[2] + y * jvA[2] + z * kvA[2];
00768                                 target.normalize();
00769                                 m_swingAxis = -ivB.cross(target);
00770                                 m_swingCorrection = m_swingAxis.length();
00771                                 m_swingAxis.normalize();
00772                         }
00773                 }
00774 
00775                 if (m_twistSpan >= btScalar(0.f))
00776                 {
00777                         btVector3 twistAxis;
00778                         computeTwistLimitInfo(qABTwist, m_twistAngle, twistAxis);
00779 
00780                         if (m_twistAngle > m_twistSpan*m_limitSoftness)
00781                         {
00782                                 m_solveTwistLimit = true;
00783 
00784                                 m_twistLimitRatio = 1.f;
00785                                 if (m_twistAngle < m_twistSpan && m_limitSoftness < 1.f - SIMD_EPSILON)
00786                                 {
00787                                         m_twistLimitRatio = (m_twistAngle - m_twistSpan * m_limitSoftness)/
00788                                                                                 (m_twistSpan  - m_twistSpan * m_limitSoftness);
00789                                 }
00790 
00791                                 // twist correction tries to get back to soft limit
00792                                 m_twistCorrection = m_twistAngle - (m_twistSpan * m_limitSoftness);
00793 
00794                                 m_twistAxis = quatRotate(qB, -twistAxis);
00795 
00796                                 m_kTwist = btScalar(1.) /
00797                                         (computeAngularImpulseDenominator(m_twistAxis,invInertiaWorldA) +
00798                                          computeAngularImpulseDenominator(m_twistAxis,invInertiaWorldB));
00799                         }
00800 
00801                         if (m_solveSwingLimit)
00802                                 m_twistAxisA = quatRotate(qA, -twistAxis);
00803                 }
00804                 else
00805                 {
00806                         m_twistAngle = btScalar(0.f);
00807                 }
00808         }
00809 }
00810 
00811 
00812 
00813 // given a cone rotation in constraint space, (pre: twist must already be removed)
00814 // this method computes its corresponding swing angle and axis.
00815 // more interestingly, it computes the cone/swing limit (angle) for this cone "pose".
00816 void btConeTwistConstraint::computeConeLimitInfo(const btQuaternion& qCone,
00817                                                                                                  btScalar& swingAngle, // out
00818                                                                                                  btVector3& vSwingAxis, // out
00819                                                                                                  btScalar& swingLimit) // out
00820 {
00821         swingAngle = qCone.getAngle();
00822         if (swingAngle > SIMD_EPSILON)
00823         {
00824                 vSwingAxis = btVector3(qCone.x(), qCone.y(), qCone.z());
00825                 vSwingAxis.normalize();
00826                 if (fabs(vSwingAxis.x()) > SIMD_EPSILON)
00827                 {
00828                         // non-zero twist?! this should never happen.
00829                         int wtf = 0; wtf = wtf;
00830                 }
00831 
00832                 // Compute limit for given swing. tricky:
00833                 // Given a swing axis, we're looking for the intersection with the bounding cone ellipse.
00834                 // (Since we're dealing with angles, this ellipse is embedded on the surface of a sphere.)
00835 
00836                 // For starters, compute the direction from center to surface of ellipse.
00837                 // This is just the perpendicular (ie. rotate 2D vector by PI/2) of the swing axis.
00838                 // (vSwingAxis is the cone rotation (in z,y); change vars and rotate to (x,y) coords.)
00839                 btScalar xEllipse =  vSwingAxis.y();
00840                 btScalar yEllipse = -vSwingAxis.z();
00841 
00842                 // Now, we use the slope of the vector (using x/yEllipse) and find the length
00843                 // of the line that intersects the ellipse:
00844                 //  x^2   y^2
00845                 //  --- + --- = 1, where a and b are semi-major axes 2 and 1 respectively (ie. the limits)
00846                 //  a^2   b^2
00847                 // Do the math and it should be clear.
00848 
00849                 swingLimit = m_swingSpan1; // if xEllipse == 0, we have a pure vSwingAxis.z rotation: just use swingspan1
00850                 if (fabs(xEllipse) > SIMD_EPSILON)
00851                 {
00852                         btScalar surfaceSlope2 = (yEllipse*yEllipse)/(xEllipse*xEllipse);
00853                         btScalar norm = 1 / (m_swingSpan2 * m_swingSpan2);
00854                         norm += surfaceSlope2 / (m_swingSpan1 * m_swingSpan1);
00855                         btScalar swingLimit2 = (1 + surfaceSlope2) / norm;
00856                         swingLimit = sqrt(swingLimit2);
00857                 }
00858 
00859                 // test!
00860                 /*swingLimit = m_swingSpan2;
00861                 if (fabs(vSwingAxis.z()) > SIMD_EPSILON)
00862                 {
00863                 btScalar mag_2 = m_swingSpan1*m_swingSpan1 + m_swingSpan2*m_swingSpan2;
00864                 btScalar sinphi = m_swingSpan2 / sqrt(mag_2);
00865                 btScalar phi = asin(sinphi);
00866                 btScalar theta = atan2(fabs(vSwingAxis.y()),fabs(vSwingAxis.z()));
00867                 btScalar alpha = 3.14159f - theta - phi;
00868                 btScalar sinalpha = sin(alpha);
00869                 swingLimit = m_swingSpan1 * sinphi/sinalpha;
00870                 }*/
00871         }
00872         else if (swingAngle < 0)
00873         {
00874                 // this should never happen!
00875                 int wtf = 0; wtf = wtf;
00876         }
00877 }
00878 
00879 btVector3 btConeTwistConstraint::GetPointForAngle(btScalar fAngleInRadians, btScalar fLength) const
00880 {
00881         // compute x/y in ellipse using cone angle (0 -> 2*PI along surface of cone)
00882         btScalar xEllipse = btCos(fAngleInRadians);
00883         btScalar yEllipse = btSin(fAngleInRadians);
00884 
00885         // Use the slope of the vector (using x/yEllipse) and find the length
00886         // of the line that intersects the ellipse:
00887         //  x^2   y^2
00888         //  --- + --- = 1, where a and b are semi-major axes 2 and 1 respectively (ie. the limits)
00889         //  a^2   b^2
00890         // Do the math and it should be clear.
00891 
00892         float swingLimit = m_swingSpan1; // if xEllipse == 0, just use axis b (1)
00893         if (fabs(xEllipse) > SIMD_EPSILON)
00894         {
00895                 btScalar surfaceSlope2 = (yEllipse*yEllipse)/(xEllipse*xEllipse);
00896                 btScalar norm = 1 / (m_swingSpan2 * m_swingSpan2);
00897                 norm += surfaceSlope2 / (m_swingSpan1 * m_swingSpan1);
00898                 btScalar swingLimit2 = (1 + surfaceSlope2) / norm;
00899                 swingLimit = sqrt(swingLimit2);
00900         }
00901 
00902         // convert into point in constraint space:
00903         // note: twist is x-axis, swing 1 and 2 are along the z and y axes respectively
00904         btVector3 vSwingAxis(0, xEllipse, -yEllipse);
00905         btQuaternion qSwing(vSwingAxis, swingLimit);
00906         btVector3 vPointInConstraintSpace(fLength,0,0);
00907         return quatRotate(qSwing, vPointInConstraintSpace);
00908 }
00909 
00910 // given a twist rotation in constraint space, (pre: cone must already be removed)
00911 // this method computes its corresponding angle and axis.
00912 void btConeTwistConstraint::computeTwistLimitInfo(const btQuaternion& qTwist,
00913                                                                                                   btScalar& twistAngle, // out
00914                                                                                                   btVector3& vTwistAxis) // out
00915 {
00916         btQuaternion qMinTwist = qTwist;
00917         twistAngle = qTwist.getAngle();
00918 
00919         if (twistAngle > SIMD_PI) // long way around. flip quat and recalculate.
00920         {
00921                 qMinTwist = operator-(qTwist);
00922                 twistAngle = qMinTwist.getAngle();
00923         }
00924         if (twistAngle < 0)
00925         {
00926                 // this should never happen
00927                 int wtf = 0; wtf = wtf;                 
00928         }
00929 
00930         vTwistAxis = btVector3(qMinTwist.x(), qMinTwist.y(), qMinTwist.z());
00931         if (twistAngle > SIMD_EPSILON)
00932                 vTwistAxis.normalize();
00933 }
00934 
00935 
00936 void btConeTwistConstraint::adjustSwingAxisToUseEllipseNormal(btVector3& vSwingAxis) const
00937 {
00938         // the swing axis is computed as the "twist-free" cone rotation,
00939         // but the cone limit is not circular, but elliptical (if swingspan1 != swingspan2).
00940         // so, if we're outside the limits, the closest way back inside the cone isn't 
00941         // along the vector back to the center. better (and more stable) to use the ellipse normal.
00942 
00943         // convert swing axis to direction from center to surface of ellipse
00944         // (ie. rotate 2D vector by PI/2)
00945         btScalar y = -vSwingAxis.z();
00946         btScalar z =  vSwingAxis.y();
00947 
00948         // do the math...
00949         if (fabs(z) > SIMD_EPSILON) // avoid division by 0. and we don't need an update if z == 0.
00950         {
00951                 // compute gradient/normal of ellipse surface at current "point"
00952                 btScalar grad = y/z;
00953                 grad *= m_swingSpan2 / m_swingSpan1;
00954 
00955                 // adjust y/z to represent normal at point (instead of vector to point)
00956                 if (y > 0)
00957                         y =  fabs(grad * z);
00958                 else
00959                         y = -fabs(grad * z);
00960 
00961                 // convert ellipse direction back to swing axis
00962                 vSwingAxis.setZ(-y);
00963                 vSwingAxis.setY( z);
00964                 vSwingAxis.normalize();
00965         }
00966 }
00967 
00968 
00969 
00970 void btConeTwistConstraint::setMotorTarget(const btQuaternion &q)
00971 {
00972         btTransform trACur = m_rbA.getCenterOfMassTransform();
00973         btTransform trBCur = m_rbB.getCenterOfMassTransform();
00974         btTransform trABCur = trBCur.inverse() * trACur;
00975         btQuaternion qABCur = trABCur.getRotation();
00976         btTransform trConstraintCur = (trBCur * m_rbBFrame).inverse() * (trACur * m_rbAFrame);
00977         btQuaternion qConstraintCur = trConstraintCur.getRotation();
00978 
00979         btQuaternion qConstraint = m_rbBFrame.getRotation().inverse() * q * m_rbAFrame.getRotation();
00980         setMotorTargetInConstraintSpace(qConstraint);
00981 }
00982 
00983 
00984 void btConeTwistConstraint::setMotorTargetInConstraintSpace(const btQuaternion &q)
00985 {
00986         m_qTarget = q;
00987 
00988         // clamp motor target to within limits
00989         {
00990                 btScalar softness = 1.f;//m_limitSoftness;
00991 
00992                 // split into twist and cone
00993                 btVector3 vTwisted = quatRotate(m_qTarget, vTwist);
00994                 btQuaternion qTargetCone  = shortestArcQuat(vTwist, vTwisted); qTargetCone.normalize();
00995                 btQuaternion qTargetTwist = qTargetCone.inverse() * m_qTarget; qTargetTwist.normalize();
00996 
00997                 // clamp cone
00998                 if (m_swingSpan1 >= btScalar(0.05f) && m_swingSpan2 >= btScalar(0.05f))
00999                 {
01000                         btScalar swingAngle, swingLimit; btVector3 swingAxis;
01001                         computeConeLimitInfo(qTargetCone, swingAngle, swingAxis, swingLimit);
01002 
01003                         if (fabs(swingAngle) > SIMD_EPSILON)
01004                         {
01005                                 if (swingAngle > swingLimit*softness)
01006                                         swingAngle = swingLimit*softness;
01007                                 else if (swingAngle < -swingLimit*softness)
01008                                         swingAngle = -swingLimit*softness;
01009                                 qTargetCone = btQuaternion(swingAxis, swingAngle);
01010                         }
01011                 }
01012 
01013                 // clamp twist
01014                 if (m_twistSpan >= btScalar(0.05f))
01015                 {
01016                         btScalar twistAngle; btVector3 twistAxis;
01017                         computeTwistLimitInfo(qTargetTwist, twistAngle, twistAxis);
01018 
01019                         if (fabs(twistAngle) > SIMD_EPSILON)
01020                         {
01021                                 // eddy todo: limitSoftness used here???
01022                                 if (twistAngle > m_twistSpan*softness)
01023                                         twistAngle = m_twistSpan*softness;
01024                                 else if (twistAngle < -m_twistSpan*softness)
01025                                         twistAngle = -m_twistSpan*softness;
01026                                 qTargetTwist = btQuaternion(twistAxis, twistAngle);
01027                         }
01028                 }
01029 
01030                 m_qTarget = qTargetCone * qTargetTwist;
01031         }
01032 }
01033 
01036 void btConeTwistConstraint::setParam(int num, btScalar value, int axis)
01037 {
01038         switch(num)
01039         {
01040                 case BT_CONSTRAINT_ERP :
01041                 case BT_CONSTRAINT_STOP_ERP :
01042                         if((axis >= 0) && (axis < 3)) 
01043                         {
01044                                 m_linERP = value;
01045                                 m_flags |= BT_CONETWIST_FLAGS_LIN_ERP;
01046                         }
01047                         else
01048                         {
01049                                 m_biasFactor = value;
01050                         }
01051                         break;
01052                 case BT_CONSTRAINT_CFM :
01053                 case BT_CONSTRAINT_STOP_CFM :
01054                         if((axis >= 0) && (axis < 3)) 
01055                         {
01056                                 m_linCFM = value;
01057                                 m_flags |= BT_CONETWIST_FLAGS_LIN_CFM;
01058                         }
01059                         else
01060                         {
01061                                 m_angCFM = value;
01062                                 m_flags |= BT_CONETWIST_FLAGS_ANG_CFM;
01063                         }
01064                         break;
01065                 default:
01066                         btAssertConstrParams(0);
01067                         break;
01068         }
01069 }
01070 
01072 btScalar btConeTwistConstraint::getParam(int num, int axis) const 
01073 {
01074         btScalar retVal = 0;
01075         switch(num)
01076         {
01077                 case BT_CONSTRAINT_ERP :
01078                 case BT_CONSTRAINT_STOP_ERP :
01079                         if((axis >= 0) && (axis < 3)) 
01080                         {
01081                                 btAssertConstrParams(m_flags & BT_CONETWIST_FLAGS_LIN_ERP);
01082                                 retVal = m_linERP;
01083                         }
01084                         else if((axis >= 3) && (axis < 6)) 
01085                         {
01086                                 retVal = m_biasFactor;
01087                         }
01088                         else
01089                         {
01090                                 btAssertConstrParams(0);
01091                         }
01092                         break;
01093                 case BT_CONSTRAINT_CFM :
01094                 case BT_CONSTRAINT_STOP_CFM :
01095                         if((axis >= 0) && (axis < 3)) 
01096                         {
01097                                 btAssertConstrParams(m_flags & BT_CONETWIST_FLAGS_LIN_CFM);
01098                                 retVal = m_linCFM;
01099                         }
01100                         else if((axis >= 3) && (axis < 6)) 
01101                         {
01102                                 btAssertConstrParams(m_flags & BT_CONETWIST_FLAGS_ANG_CFM);
01103                                 retVal = m_angCFM;
01104                         }
01105                         else
01106                         {
01107                                 btAssertConstrParams(0);
01108                         }
01109                         break;
01110                 default : 
01111                         btAssertConstrParams(0);
01112         }
01113         return retVal;
01114 }
01115 
01116 
01117 

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