Bullet Collision Detection & Physics Library

btGeneric6DofConstraint.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 2007-09-09
00017 Refactored by Francisco Le?n
00018 email: projectileman@yahoo.com
00019 http://gimpact.sf.net
00020 */
00021 
00022 #include "btGeneric6DofConstraint.h"
00023 #include "BulletDynamics/Dynamics/btRigidBody.h"
00024 #include "LinearMath/btTransformUtil.h"
00025 #include "LinearMath/btTransformUtil.h"
00026 #include <new>
00027 
00028 
00029 
00030 #define D6_USE_OBSOLETE_METHOD false
00031 #define D6_USE_FRAME_OFFSET true
00032 
00033 
00034 
00035 
00036 
00037 
00038 btGeneric6DofConstraint::btGeneric6DofConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB, bool useLinearReferenceFrameA)
00039 : btTypedConstraint(D6_CONSTRAINT_TYPE, rbA, rbB)
00040 , m_frameInA(frameInA)
00041 , m_frameInB(frameInB),
00042 m_useLinearReferenceFrameA(useLinearReferenceFrameA),
00043 m_useOffsetForConstraintFrame(D6_USE_FRAME_OFFSET),
00044 m_flags(0),
00045 m_useSolveConstraintObsolete(D6_USE_OBSOLETE_METHOD)
00046 {
00047         calculateTransforms();
00048 }
00049 
00050 
00051 
00052 btGeneric6DofConstraint::btGeneric6DofConstraint(btRigidBody& rbB, const btTransform& frameInB, bool useLinearReferenceFrameB)
00053         : btTypedConstraint(D6_CONSTRAINT_TYPE, getFixedBody(), rbB),
00054                 m_frameInB(frameInB),
00055                 m_useLinearReferenceFrameA(useLinearReferenceFrameB),
00056                 m_useOffsetForConstraintFrame(D6_USE_FRAME_OFFSET),
00057                 m_flags(0),
00058                 m_useSolveConstraintObsolete(false)
00059 {
00061         m_frameInA = rbB.getCenterOfMassTransform() * m_frameInB;
00062         calculateTransforms();
00063 }
00064 
00065 
00066 
00067 
00068 #define GENERIC_D6_DISABLE_WARMSTARTING 1
00069 
00070 
00071 
00072 btScalar btGetMatrixElem(const btMatrix3x3& mat, int index);
00073 btScalar btGetMatrixElem(const btMatrix3x3& mat, int index)
00074 {
00075         int i = index%3;
00076         int j = index/3;
00077         return mat[i][j];
00078 }
00079 
00080 
00081 
00083 bool    matrixToEulerXYZ(const btMatrix3x3& mat,btVector3& xyz);
00084 bool    matrixToEulerXYZ(const btMatrix3x3& mat,btVector3& xyz)
00085 {
00086         //      // rot =  cy*cz          -cy*sz           sy
00087         //      //        cz*sx*sy+cx*sz  cx*cz-sx*sy*sz -cy*sx
00088         //      //       -cx*cz*sy+sx*sz  cz*sx+cx*sy*sz  cx*cy
00089         //
00090 
00091         btScalar fi = btGetMatrixElem(mat,2);
00092         if (fi < btScalar(1.0f))
00093         {
00094                 if (fi > btScalar(-1.0f))
00095                 {
00096                         xyz[0] = btAtan2(-btGetMatrixElem(mat,5),btGetMatrixElem(mat,8));
00097                         xyz[1] = btAsin(btGetMatrixElem(mat,2));
00098                         xyz[2] = btAtan2(-btGetMatrixElem(mat,1),btGetMatrixElem(mat,0));
00099                         return true;
00100                 }
00101                 else
00102                 {
00103                         // WARNING.  Not unique.  XA - ZA = -atan2(r10,r11)
00104                         xyz[0] = -btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4));
00105                         xyz[1] = -SIMD_HALF_PI;
00106                         xyz[2] = btScalar(0.0);
00107                         return false;
00108                 }
00109         }
00110         else
00111         {
00112                 // WARNING.  Not unique.  XAngle + ZAngle = atan2(r10,r11)
00113                 xyz[0] = btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4));
00114                 xyz[1] = SIMD_HALF_PI;
00115                 xyz[2] = 0.0;
00116         }
00117         return false;
00118 }
00119 
00121 
00122 int btRotationalLimitMotor::testLimitValue(btScalar test_value)
00123 {
00124         if(m_loLimit>m_hiLimit)
00125         {
00126                 m_currentLimit = 0;//Free from violation
00127                 return 0;
00128         }
00129         if (test_value < m_loLimit)
00130         {
00131                 m_currentLimit = 1;//low limit violation
00132                 m_currentLimitError =  test_value - m_loLimit;
00133                 if(m_currentLimitError>SIMD_PI) 
00134                         m_currentLimitError-=SIMD_2_PI;
00135                 else if(m_currentLimitError<-SIMD_PI) 
00136                         m_currentLimitError+=SIMD_2_PI;
00137                 return 1;
00138         }
00139         else if (test_value> m_hiLimit)
00140         {
00141                 m_currentLimit = 2;//High limit violation
00142                 m_currentLimitError = test_value - m_hiLimit;
00143                 if(m_currentLimitError>SIMD_PI) 
00144                         m_currentLimitError-=SIMD_2_PI;
00145                 else if(m_currentLimitError<-SIMD_PI) 
00146                         m_currentLimitError+=SIMD_2_PI;
00147                 return 2;
00148         };
00149 
00150         m_currentLimit = 0;//Free from violation
00151         return 0;
00152 
00153 }
00154 
00155 
00156 
00157 btScalar btRotationalLimitMotor::solveAngularLimits(
00158         btScalar timeStep,btVector3& axis,btScalar jacDiagABInv,
00159         btRigidBody * body0, btRigidBody * body1 )
00160 {
00161         if (needApplyTorques()==false) return 0.0f;
00162 
00163         btScalar target_velocity = m_targetVelocity;
00164         btScalar maxMotorForce = m_maxMotorForce;
00165 
00166         //current error correction
00167         if (m_currentLimit!=0)
00168         {
00169                 target_velocity = -m_stopERP*m_currentLimitError/(timeStep);
00170                 maxMotorForce = m_maxLimitForce;
00171         }
00172 
00173         maxMotorForce *= timeStep;
00174 
00175         // current velocity difference
00176 
00177         btVector3 angVelA;
00178         body0->internalGetAngularVelocity(angVelA);
00179         btVector3 angVelB;
00180         body1->internalGetAngularVelocity(angVelB);
00181 
00182         btVector3 vel_diff;
00183         vel_diff = angVelA-angVelB;
00184 
00185 
00186 
00187         btScalar rel_vel = axis.dot(vel_diff);
00188 
00189         // correction velocity
00190         btScalar motor_relvel = m_limitSoftness*(target_velocity  - m_damping*rel_vel);
00191 
00192 
00193         if ( motor_relvel < SIMD_EPSILON && motor_relvel > -SIMD_EPSILON  )
00194         {
00195                 return 0.0f;//no need for applying force
00196         }
00197 
00198 
00199         // correction impulse
00200         btScalar unclippedMotorImpulse = (1+m_bounce)*motor_relvel*jacDiagABInv;
00201 
00202         // clip correction impulse
00203         btScalar clippedMotorImpulse;
00204 
00206         if (unclippedMotorImpulse>0.0f)
00207         {
00208                 clippedMotorImpulse =  unclippedMotorImpulse > maxMotorForce? maxMotorForce: unclippedMotorImpulse;
00209         }
00210         else
00211         {
00212                 clippedMotorImpulse =  unclippedMotorImpulse < -maxMotorForce ? -maxMotorForce: unclippedMotorImpulse;
00213         }
00214 
00215 
00216         // sort with accumulated impulses
00217         btScalar        lo = btScalar(-BT_LARGE_FLOAT);
00218         btScalar        hi = btScalar(BT_LARGE_FLOAT);
00219 
00220         btScalar oldaccumImpulse = m_accumulatedImpulse;
00221         btScalar sum = oldaccumImpulse + clippedMotorImpulse;
00222         m_accumulatedImpulse = sum > hi ? btScalar(0.) : sum < lo ? btScalar(0.) : sum;
00223 
00224         clippedMotorImpulse = m_accumulatedImpulse - oldaccumImpulse;
00225 
00226         btVector3 motorImp = clippedMotorImpulse * axis;
00227 
00228         //body0->applyTorqueImpulse(motorImp);
00229         //body1->applyTorqueImpulse(-motorImp);
00230 
00231         body0->internalApplyImpulse(btVector3(0,0,0), body0->getInvInertiaTensorWorld()*axis,clippedMotorImpulse);
00232         body1->internalApplyImpulse(btVector3(0,0,0), body1->getInvInertiaTensorWorld()*axis,-clippedMotorImpulse);
00233 
00234 
00235         return clippedMotorImpulse;
00236 
00237 
00238 }
00239 
00241 
00242 
00243 
00244 
00246 
00247 
00248 int btTranslationalLimitMotor::testLimitValue(int limitIndex, btScalar test_value)
00249 {
00250         btScalar loLimit = m_lowerLimit[limitIndex];
00251         btScalar hiLimit = m_upperLimit[limitIndex];
00252         if(loLimit > hiLimit)
00253         {
00254                 m_currentLimit[limitIndex] = 0;//Free from violation
00255                 m_currentLimitError[limitIndex] = btScalar(0.f);
00256                 return 0;
00257         }
00258 
00259         if (test_value < loLimit)
00260         {
00261                 m_currentLimit[limitIndex] = 2;//low limit violation
00262                 m_currentLimitError[limitIndex] =  test_value - loLimit;
00263                 return 2;
00264         }
00265         else if (test_value> hiLimit)
00266         {
00267                 m_currentLimit[limitIndex] = 1;//High limit violation
00268                 m_currentLimitError[limitIndex] = test_value - hiLimit;
00269                 return 1;
00270         };
00271 
00272         m_currentLimit[limitIndex] = 0;//Free from violation
00273         m_currentLimitError[limitIndex] = btScalar(0.f);
00274         return 0;
00275 }
00276 
00277 
00278 
00279 btScalar btTranslationalLimitMotor::solveLinearAxis(
00280         btScalar timeStep,
00281         btScalar jacDiagABInv,
00282         btRigidBody& body1,const btVector3 &pointInA,
00283         btRigidBody& body2,const btVector3 &pointInB,
00284         int limit_index,
00285         const btVector3 & axis_normal_on_a,
00286         const btVector3 & anchorPos)
00287 {
00288 
00290         //    btVector3 rel_pos1 = pointInA - body1.getCenterOfMassPosition();
00291         //    btVector3 rel_pos2 = pointInB - body2.getCenterOfMassPosition();
00292         btVector3 rel_pos1 = anchorPos - body1.getCenterOfMassPosition();
00293         btVector3 rel_pos2 = anchorPos - body2.getCenterOfMassPosition();
00294 
00295         btVector3 vel1;
00296         body1.internalGetVelocityInLocalPointObsolete(rel_pos1,vel1);
00297         btVector3 vel2;
00298         body2.internalGetVelocityInLocalPointObsolete(rel_pos2,vel2);
00299         btVector3 vel = vel1 - vel2;
00300 
00301         btScalar rel_vel = axis_normal_on_a.dot(vel);
00302 
00303 
00304 
00306 
00307         //positional error (zeroth order error)
00308         btScalar depth = -(pointInA - pointInB).dot(axis_normal_on_a);
00309         btScalar        lo = btScalar(-BT_LARGE_FLOAT);
00310         btScalar        hi = btScalar(BT_LARGE_FLOAT);
00311 
00312         btScalar minLimit = m_lowerLimit[limit_index];
00313         btScalar maxLimit = m_upperLimit[limit_index];
00314 
00315         //handle the limits
00316         if (minLimit < maxLimit)
00317         {
00318                 {
00319                         if (depth > maxLimit)
00320                         {
00321                                 depth -= maxLimit;
00322                                 lo = btScalar(0.);
00323 
00324                         }
00325                         else
00326                         {
00327                                 if (depth < minLimit)
00328                                 {
00329                                         depth -= minLimit;
00330                                         hi = btScalar(0.);
00331                                 }
00332                                 else
00333                                 {
00334                                         return 0.0f;
00335                                 }
00336                         }
00337                 }
00338         }
00339 
00340         btScalar normalImpulse= m_limitSoftness*(m_restitution*depth/timeStep - m_damping*rel_vel) * jacDiagABInv;
00341 
00342 
00343 
00344 
00345         btScalar oldNormalImpulse = m_accumulatedImpulse[limit_index];
00346         btScalar sum = oldNormalImpulse + normalImpulse;
00347         m_accumulatedImpulse[limit_index] = sum > hi ? btScalar(0.) : sum < lo ? btScalar(0.) : sum;
00348         normalImpulse = m_accumulatedImpulse[limit_index] - oldNormalImpulse;
00349 
00350         btVector3 impulse_vector = axis_normal_on_a * normalImpulse;
00351         //body1.applyImpulse( impulse_vector, rel_pos1);
00352         //body2.applyImpulse(-impulse_vector, rel_pos2);
00353 
00354         btVector3 ftorqueAxis1 = rel_pos1.cross(axis_normal_on_a);
00355         btVector3 ftorqueAxis2 = rel_pos2.cross(axis_normal_on_a);
00356         body1.internalApplyImpulse(axis_normal_on_a*body1.getInvMass(), body1.getInvInertiaTensorWorld()*ftorqueAxis1,normalImpulse);
00357         body2.internalApplyImpulse(axis_normal_on_a*body2.getInvMass(), body2.getInvInertiaTensorWorld()*ftorqueAxis2,-normalImpulse);
00358 
00359 
00360 
00361 
00362         return normalImpulse;
00363 }
00364 
00366 
00367 void btGeneric6DofConstraint::calculateAngleInfo()
00368 {
00369         btMatrix3x3 relative_frame = m_calculatedTransformA.getBasis().inverse()*m_calculatedTransformB.getBasis();
00370         matrixToEulerXYZ(relative_frame,m_calculatedAxisAngleDiff);
00371         // in euler angle mode we do not actually constrain the angular velocity
00372         // along the axes axis[0] and axis[2] (although we do use axis[1]) :
00373         //
00374         //    to get                    constrain w2-w1 along           ...not
00375         //    ------                    ---------------------           ------
00376         //    d(angle[0])/dt = 0        ax[1] x ax[2]                   ax[0]
00377         //    d(angle[1])/dt = 0        ax[1]
00378         //    d(angle[2])/dt = 0        ax[0] x ax[1]                   ax[2]
00379         //
00380         // constraining w2-w1 along an axis 'a' means that a'*(w2-w1)=0.
00381         // to prove the result for angle[0], write the expression for angle[0] from
00382         // GetInfo1 then take the derivative. to prove this for angle[2] it is
00383         // easier to take the euler rate expression for d(angle[2])/dt with respect
00384         // to the components of w and set that to 0.
00385         btVector3 axis0 = m_calculatedTransformB.getBasis().getColumn(0);
00386         btVector3 axis2 = m_calculatedTransformA.getBasis().getColumn(2);
00387 
00388         m_calculatedAxis[1] = axis2.cross(axis0);
00389         m_calculatedAxis[0] = m_calculatedAxis[1].cross(axis2);
00390         m_calculatedAxis[2] = axis0.cross(m_calculatedAxis[1]);
00391 
00392         m_calculatedAxis[0].normalize();
00393         m_calculatedAxis[1].normalize();
00394         m_calculatedAxis[2].normalize();
00395 
00396 }
00397 
00398 void btGeneric6DofConstraint::calculateTransforms()
00399 {
00400         calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform());
00401 }
00402 
00403 void btGeneric6DofConstraint::calculateTransforms(const btTransform& transA,const btTransform& transB)
00404 {
00405         m_calculatedTransformA = transA * m_frameInA;
00406         m_calculatedTransformB = transB * m_frameInB;
00407         calculateLinearInfo();
00408         calculateAngleInfo();
00409         if(m_useOffsetForConstraintFrame)
00410         {       //  get weight factors depending on masses
00411                 btScalar miA = getRigidBodyA().getInvMass();
00412                 btScalar miB = getRigidBodyB().getInvMass();
00413                 m_hasStaticBody = (miA < SIMD_EPSILON) || (miB < SIMD_EPSILON);
00414                 btScalar miS = miA + miB;
00415                 if(miS > btScalar(0.f))
00416                 {
00417                         m_factA = miB / miS;
00418                 }
00419                 else 
00420                 {
00421                         m_factA = btScalar(0.5f);
00422                 }
00423                 m_factB = btScalar(1.0f) - m_factA;
00424         }
00425 }
00426 
00427 
00428 
00429 void btGeneric6DofConstraint::buildLinearJacobian(
00430         btJacobianEntry & jacLinear,const btVector3 & normalWorld,
00431         const btVector3 & pivotAInW,const btVector3 & pivotBInW)
00432 {
00433         new (&jacLinear) btJacobianEntry(
00434         m_rbA.getCenterOfMassTransform().getBasis().transpose(),
00435         m_rbB.getCenterOfMassTransform().getBasis().transpose(),
00436         pivotAInW - m_rbA.getCenterOfMassPosition(),
00437         pivotBInW - m_rbB.getCenterOfMassPosition(),
00438         normalWorld,
00439         m_rbA.getInvInertiaDiagLocal(),
00440         m_rbA.getInvMass(),
00441         m_rbB.getInvInertiaDiagLocal(),
00442         m_rbB.getInvMass());
00443 }
00444 
00445 
00446 
00447 void btGeneric6DofConstraint::buildAngularJacobian(
00448         btJacobianEntry & jacAngular,const btVector3 & jointAxisW)
00449 {
00450          new (&jacAngular)      btJacobianEntry(jointAxisW,
00451                                       m_rbA.getCenterOfMassTransform().getBasis().transpose(),
00452                                       m_rbB.getCenterOfMassTransform().getBasis().transpose(),
00453                                       m_rbA.getInvInertiaDiagLocal(),
00454                                       m_rbB.getInvInertiaDiagLocal());
00455 
00456 }
00457 
00458 
00459 
00460 bool btGeneric6DofConstraint::testAngularLimitMotor(int axis_index)
00461 {
00462         btScalar angle = m_calculatedAxisAngleDiff[axis_index];
00463         angle = btAdjustAngleToLimits(angle, m_angularLimits[axis_index].m_loLimit, m_angularLimits[axis_index].m_hiLimit);
00464         m_angularLimits[axis_index].m_currentPosition = angle;
00465         //test limits
00466         m_angularLimits[axis_index].testLimitValue(angle);
00467         return m_angularLimits[axis_index].needApplyTorques();
00468 }
00469 
00470 
00471 
00472 void btGeneric6DofConstraint::buildJacobian()
00473 {
00474 #ifndef __SPU__
00475         if (m_useSolveConstraintObsolete)
00476         {
00477 
00478                 // Clear accumulated impulses for the next simulation step
00479                 m_linearLimits.m_accumulatedImpulse.setValue(btScalar(0.), btScalar(0.), btScalar(0.));
00480                 int i;
00481                 for(i = 0; i < 3; i++)
00482                 {
00483                         m_angularLimits[i].m_accumulatedImpulse = btScalar(0.);
00484                 }
00485                 //calculates transform
00486                 calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform());
00487 
00488                 //  const btVector3& pivotAInW = m_calculatedTransformA.getOrigin();
00489                 //  const btVector3& pivotBInW = m_calculatedTransformB.getOrigin();
00490                 calcAnchorPos();
00491                 btVector3 pivotAInW = m_AnchorPos;
00492                 btVector3 pivotBInW = m_AnchorPos;
00493 
00494                 // not used here
00495                 //    btVector3 rel_pos1 = pivotAInW - m_rbA.getCenterOfMassPosition();
00496                 //    btVector3 rel_pos2 = pivotBInW - m_rbB.getCenterOfMassPosition();
00497 
00498                 btVector3 normalWorld;
00499                 //linear part
00500                 for (i=0;i<3;i++)
00501                 {
00502                         if (m_linearLimits.isLimited(i))
00503                         {
00504                                 if (m_useLinearReferenceFrameA)
00505                                         normalWorld = m_calculatedTransformA.getBasis().getColumn(i);
00506                                 else
00507                                         normalWorld = m_calculatedTransformB.getBasis().getColumn(i);
00508 
00509                                 buildLinearJacobian(
00510                                         m_jacLinear[i],normalWorld ,
00511                                         pivotAInW,pivotBInW);
00512 
00513                         }
00514                 }
00515 
00516                 // angular part
00517                 for (i=0;i<3;i++)
00518                 {
00519                         //calculates error angle
00520                         if (testAngularLimitMotor(i))
00521                         {
00522                                 normalWorld = this->getAxis(i);
00523                                 // Create angular atom
00524                                 buildAngularJacobian(m_jacAng[i],normalWorld);
00525                         }
00526                 }
00527 
00528         }
00529 #endif //__SPU__
00530 
00531 }
00532 
00533 
00534 void btGeneric6DofConstraint::getInfo1 (btConstraintInfo1* info)
00535 {
00536         if (m_useSolveConstraintObsolete)
00537         {
00538                 info->m_numConstraintRows = 0;
00539                 info->nub = 0;
00540         } else
00541         {
00542                 //prepare constraint
00543                 calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform());
00544                 info->m_numConstraintRows = 0;
00545                 info->nub = 6;
00546                 int i;
00547                 //test linear limits
00548                 for(i = 0; i < 3; i++)
00549                 {
00550                         if(m_linearLimits.needApplyForce(i))
00551                         {
00552                                 info->m_numConstraintRows++;
00553                                 info->nub--;
00554                         }
00555                 }
00556                 //test angular limits
00557                 for (i=0;i<3 ;i++ )
00558                 {
00559                         if(testAngularLimitMotor(i))
00560                         {
00561                                 info->m_numConstraintRows++;
00562                                 info->nub--;
00563                         }
00564                 }
00565         }
00566 }
00567 
00568 void btGeneric6DofConstraint::getInfo1NonVirtual (btConstraintInfo1* info)
00569 {
00570         if (m_useSolveConstraintObsolete)
00571         {
00572                 info->m_numConstraintRows = 0;
00573                 info->nub = 0;
00574         } else
00575         {
00576                 //pre-allocate all 6
00577                 info->m_numConstraintRows = 6;
00578                 info->nub = 0;
00579         }
00580 }
00581 
00582 
00583 void btGeneric6DofConstraint::getInfo2 (btConstraintInfo2* info)
00584 {
00585         btAssert(!m_useSolveConstraintObsolete);
00586 
00587         const btTransform& transA = m_rbA.getCenterOfMassTransform();
00588         const btTransform& transB = m_rbB.getCenterOfMassTransform();
00589         const btVector3& linVelA = m_rbA.getLinearVelocity();
00590         const btVector3& linVelB = m_rbB.getLinearVelocity();
00591         const btVector3& angVelA = m_rbA.getAngularVelocity();
00592         const btVector3& angVelB = m_rbB.getAngularVelocity();
00593 
00594         if(m_useOffsetForConstraintFrame)
00595         { // for stability better to solve angular limits first
00596                 int row = setAngularLimits(info, 0,transA,transB,linVelA,linVelB,angVelA,angVelB);
00597                 setLinearLimits(info, row, transA,transB,linVelA,linVelB,angVelA,angVelB);
00598         }
00599         else
00600         { // leave old version for compatibility
00601                 int row = setLinearLimits(info, 0, transA,transB,linVelA,linVelB,angVelA,angVelB);
00602                 setAngularLimits(info, row,transA,transB,linVelA,linVelB,angVelA,angVelB);
00603         }
00604 
00605 }
00606 
00607 
00608 void btGeneric6DofConstraint::getInfo2NonVirtual (btConstraintInfo2* info, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB)
00609 {
00610         
00611         btAssert(!m_useSolveConstraintObsolete);
00612         //prepare constraint
00613         calculateTransforms(transA,transB);
00614 
00615         int i;
00616         for (i=0;i<3 ;i++ )
00617         {
00618                 testAngularLimitMotor(i);
00619         }
00620 
00621         if(m_useOffsetForConstraintFrame)
00622         { // for stability better to solve angular limits first
00623                 int row = setAngularLimits(info, 0,transA,transB,linVelA,linVelB,angVelA,angVelB);
00624                 setLinearLimits(info, row, transA,transB,linVelA,linVelB,angVelA,angVelB);
00625         }
00626         else
00627         { // leave old version for compatibility
00628                 int row = setLinearLimits(info, 0, transA,transB,linVelA,linVelB,angVelA,angVelB);
00629                 setAngularLimits(info, row,transA,transB,linVelA,linVelB,angVelA,angVelB);
00630         }
00631 }
00632 
00633 
00634 
00635 int btGeneric6DofConstraint::setLinearLimits(btConstraintInfo2* info, int row, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB)
00636 {
00637 //      int row = 0;
00638         //solve linear limits
00639         btRotationalLimitMotor limot;
00640         for (int i=0;i<3 ;i++ )
00641         {
00642                 if(m_linearLimits.needApplyForce(i))
00643                 { // re-use rotational motor code
00644                         limot.m_bounce = btScalar(0.f);
00645                         limot.m_currentLimit = m_linearLimits.m_currentLimit[i];
00646                         limot.m_currentPosition = m_linearLimits.m_currentLinearDiff[i];
00647                         limot.m_currentLimitError  = m_linearLimits.m_currentLimitError[i];
00648                         limot.m_damping  = m_linearLimits.m_damping;
00649                         limot.m_enableMotor  = m_linearLimits.m_enableMotor[i];
00650                         limot.m_hiLimit  = m_linearLimits.m_upperLimit[i];
00651                         limot.m_limitSoftness  = m_linearLimits.m_limitSoftness;
00652                         limot.m_loLimit  = m_linearLimits.m_lowerLimit[i];
00653                         limot.m_maxLimitForce  = btScalar(0.f);
00654                         limot.m_maxMotorForce  = m_linearLimits.m_maxMotorForce[i];
00655                         limot.m_targetVelocity  = m_linearLimits.m_targetVelocity[i];
00656                         btVector3 axis = m_calculatedTransformA.getBasis().getColumn(i);
00657                         int flags = m_flags >> (i * BT_6DOF_FLAGS_AXIS_SHIFT);
00658                         limot.m_normalCFM       = (flags & BT_6DOF_FLAGS_CFM_NORM) ? m_linearLimits.m_normalCFM[i] : info->cfm[0];
00659                         limot.m_stopCFM         = (flags & BT_6DOF_FLAGS_CFM_STOP) ? m_linearLimits.m_stopCFM[i] : info->cfm[0];
00660                         limot.m_stopERP         = (flags & BT_6DOF_FLAGS_ERP_STOP) ? m_linearLimits.m_stopERP[i] : info->erp;
00661                         if(m_useOffsetForConstraintFrame)
00662                         {
00663                                 int indx1 = (i + 1) % 3;
00664                                 int indx2 = (i + 2) % 3;
00665                                 int rotAllowed = 1; // rotations around orthos to current axis
00666                                 if(m_angularLimits[indx1].m_currentLimit && m_angularLimits[indx2].m_currentLimit)
00667                                 {
00668                                         rotAllowed = 0;
00669                                 }
00670                                 row += get_limit_motor_info2(&limot, transA,transB,linVelA,linVelB,angVelA,angVelB, info, row, axis, 0, rotAllowed);
00671                         }
00672                         else
00673                         {
00674                                 row += get_limit_motor_info2(&limot, transA,transB,linVelA,linVelB,angVelA,angVelB, info, row, axis, 0);
00675                         }
00676                 }
00677         }
00678         return row;
00679 }
00680 
00681 
00682 
00683 int btGeneric6DofConstraint::setAngularLimits(btConstraintInfo2 *info, int row_offset, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB)
00684 {
00685         btGeneric6DofConstraint * d6constraint = this;
00686         int row = row_offset;
00687         //solve angular limits
00688         for (int i=0;i<3 ;i++ )
00689         {
00690                 if(d6constraint->getRotationalLimitMotor(i)->needApplyTorques())
00691                 {
00692                         btVector3 axis = d6constraint->getAxis(i);
00693                         int flags = m_flags >> ((i + 3) * BT_6DOF_FLAGS_AXIS_SHIFT);
00694                         if(!(flags & BT_6DOF_FLAGS_CFM_NORM))
00695                         {
00696                                 m_angularLimits[i].m_normalCFM = info->cfm[0];
00697                         }
00698                         if(!(flags & BT_6DOF_FLAGS_CFM_STOP))
00699                         {
00700                                 m_angularLimits[i].m_stopCFM = info->cfm[0];
00701                         }
00702                         if(!(flags & BT_6DOF_FLAGS_ERP_STOP))
00703                         {
00704                                 m_angularLimits[i].m_stopERP = info->erp;
00705                         }
00706                         row += get_limit_motor_info2(d6constraint->getRotationalLimitMotor(i),
00707                                                                                                 transA,transB,linVelA,linVelB,angVelA,angVelB, info,row,axis,1);
00708                 }
00709         }
00710 
00711         return row;
00712 }
00713 
00714 
00715 
00716 
00717 void    btGeneric6DofConstraint::updateRHS(btScalar     timeStep)
00718 {
00719         (void)timeStep;
00720 
00721 }
00722 
00723 
00724 void btGeneric6DofConstraint::setFrames(const btTransform& frameA, const btTransform& frameB)
00725 {
00726         m_frameInA = frameA;
00727         m_frameInB = frameB;
00728         buildJacobian();
00729         calculateTransforms();
00730 }
00731 
00732 
00733 
00734 btVector3 btGeneric6DofConstraint::getAxis(int axis_index) const
00735 {
00736         return m_calculatedAxis[axis_index];
00737 }
00738 
00739 
00740 btScalar        btGeneric6DofConstraint::getRelativePivotPosition(int axisIndex) const
00741 {
00742         return m_calculatedLinearDiff[axisIndex];
00743 }
00744 
00745 
00746 btScalar btGeneric6DofConstraint::getAngle(int axisIndex) const
00747 {
00748         return m_calculatedAxisAngleDiff[axisIndex];
00749 }
00750 
00751 
00752 
00753 void btGeneric6DofConstraint::calcAnchorPos(void)
00754 {
00755         btScalar imA = m_rbA.getInvMass();
00756         btScalar imB = m_rbB.getInvMass();
00757         btScalar weight;
00758         if(imB == btScalar(0.0))
00759         {
00760                 weight = btScalar(1.0);
00761         }
00762         else
00763         {
00764                 weight = imA / (imA + imB);
00765         }
00766         const btVector3& pA = m_calculatedTransformA.getOrigin();
00767         const btVector3& pB = m_calculatedTransformB.getOrigin();
00768         m_AnchorPos = pA * weight + pB * (btScalar(1.0) - weight);
00769         return;
00770 }
00771 
00772 
00773 
00774 void btGeneric6DofConstraint::calculateLinearInfo()
00775 {
00776         m_calculatedLinearDiff = m_calculatedTransformB.getOrigin() - m_calculatedTransformA.getOrigin();
00777         m_calculatedLinearDiff = m_calculatedTransformA.getBasis().inverse() * m_calculatedLinearDiff;
00778         for(int i = 0; i < 3; i++)
00779         {
00780                 m_linearLimits.m_currentLinearDiff[i] = m_calculatedLinearDiff[i];
00781                 m_linearLimits.testLimitValue(i, m_calculatedLinearDiff[i]);
00782         }
00783 }
00784 
00785 
00786 
00787 int btGeneric6DofConstraint::get_limit_motor_info2(
00788         btRotationalLimitMotor * limot,
00789         const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB,
00790         btConstraintInfo2 *info, int row, btVector3& ax1, int rotational,int rotAllowed)
00791 {
00792     int srow = row * info->rowskip;
00793     int powered = limot->m_enableMotor;
00794     int limit = limot->m_currentLimit;
00795     if (powered || limit)
00796     {   // if the joint is powered, or has joint limits, add in the extra row
00797         btScalar *J1 = rotational ? info->m_J1angularAxis : info->m_J1linearAxis;
00798         btScalar *J2 = rotational ? info->m_J2angularAxis : 0;
00799         J1[srow+0] = ax1[0];
00800         J1[srow+1] = ax1[1];
00801         J1[srow+2] = ax1[2];
00802         if(rotational)
00803         {
00804             J2[srow+0] = -ax1[0];
00805             J2[srow+1] = -ax1[1];
00806             J2[srow+2] = -ax1[2];
00807         }
00808         if((!rotational))
00809         {
00810                         if (m_useOffsetForConstraintFrame)
00811                         {
00812                                 btVector3 tmpA, tmpB, relA, relB;
00813                                 // get vector from bodyB to frameB in WCS
00814                                 relB = m_calculatedTransformB.getOrigin() - transB.getOrigin();
00815                                 // get its projection to constraint axis
00816                                 btVector3 projB = ax1 * relB.dot(ax1);
00817                                 // get vector directed from bodyB to constraint axis (and orthogonal to it)
00818                                 btVector3 orthoB = relB - projB;
00819                                 // same for bodyA
00820                                 relA = m_calculatedTransformA.getOrigin() - transA.getOrigin();
00821                                 btVector3 projA = ax1 * relA.dot(ax1);
00822                                 btVector3 orthoA = relA - projA;
00823                                 // get desired offset between frames A and B along constraint axis
00824                                 btScalar desiredOffs = limot->m_currentPosition - limot->m_currentLimitError;
00825                                 // desired vector from projection of center of bodyA to projection of center of bodyB to constraint axis
00826                                 btVector3 totalDist = projA + ax1 * desiredOffs - projB;
00827                                 // get offset vectors relA and relB
00828                                 relA = orthoA + totalDist * m_factA;
00829                                 relB = orthoB - totalDist * m_factB;
00830                                 tmpA = relA.cross(ax1);
00831                                 tmpB = relB.cross(ax1);
00832                                 if(m_hasStaticBody && (!rotAllowed))
00833                                 {
00834                                         tmpA *= m_factA;
00835                                         tmpB *= m_factB;
00836                                 }
00837                                 int i;
00838                                 for (i=0; i<3; i++) info->m_J1angularAxis[srow+i] = tmpA[i];
00839                                 for (i=0; i<3; i++) info->m_J2angularAxis[srow+i] = -tmpB[i];
00840                         } else
00841                         {
00842                                 btVector3 ltd;  // Linear Torque Decoupling vector
00843                                 btVector3 c = m_calculatedTransformB.getOrigin() - transA.getOrigin();
00844                                 ltd = c.cross(ax1);
00845                                 info->m_J1angularAxis[srow+0] = ltd[0];
00846                                 info->m_J1angularAxis[srow+1] = ltd[1];
00847                                 info->m_J1angularAxis[srow+2] = ltd[2];
00848 
00849                                 c = m_calculatedTransformB.getOrigin() - transB.getOrigin();
00850                                 ltd = -c.cross(ax1);
00851                                 info->m_J2angularAxis[srow+0] = ltd[0];
00852                                 info->m_J2angularAxis[srow+1] = ltd[1];
00853                                 info->m_J2angularAxis[srow+2] = ltd[2];
00854                         }
00855         }
00856         // if we're limited low and high simultaneously, the joint motor is
00857         // ineffective
00858         if (limit && (limot->m_loLimit == limot->m_hiLimit)) powered = 0;
00859         info->m_constraintError[srow] = btScalar(0.f);
00860         if (powered)
00861         {
00862                         info->cfm[srow] = limot->m_normalCFM;
00863             if(!limit)
00864             {
00865                                 btScalar tag_vel = rotational ? limot->m_targetVelocity : -limot->m_targetVelocity;
00866 
00867                                 btScalar mot_fact = getMotorFactor(     limot->m_currentPosition, 
00868                                                                                                         limot->m_loLimit,
00869                                                                                                         limot->m_hiLimit, 
00870                                                                                                         tag_vel, 
00871                                                                                                         info->fps * limot->m_stopERP);
00872                                 info->m_constraintError[srow] += mot_fact * limot->m_targetVelocity;
00873                 info->m_lowerLimit[srow] = -limot->m_maxMotorForce;
00874                 info->m_upperLimit[srow] = limot->m_maxMotorForce;
00875             }
00876         }
00877         if(limit)
00878         {
00879             btScalar k = info->fps * limot->m_stopERP;
00880                         if(!rotational)
00881                         {
00882                                 info->m_constraintError[srow] += k * limot->m_currentLimitError;
00883                         }
00884                         else
00885                         {
00886                                 info->m_constraintError[srow] += -k * limot->m_currentLimitError;
00887                         }
00888                         info->cfm[srow] = limot->m_stopCFM;
00889             if (limot->m_loLimit == limot->m_hiLimit)
00890             {   // limited low and high simultaneously
00891                 info->m_lowerLimit[srow] = -SIMD_INFINITY;
00892                 info->m_upperLimit[srow] = SIMD_INFINITY;
00893             }
00894             else
00895             {
00896                 if (limit == 1)
00897                 {
00898                     info->m_lowerLimit[srow] = 0;
00899                     info->m_upperLimit[srow] = SIMD_INFINITY;
00900                 }
00901                 else
00902                 {
00903                     info->m_lowerLimit[srow] = -SIMD_INFINITY;
00904                     info->m_upperLimit[srow] = 0;
00905                 }
00906                 // deal with bounce
00907                 if (limot->m_bounce > 0)
00908                 {
00909                     // calculate joint velocity
00910                     btScalar vel;
00911                     if (rotational)
00912                     {
00913                         vel = angVelA.dot(ax1);
00914 //make sure that if no body -> angVelB == zero vec
00915 //                        if (body1)
00916                             vel -= angVelB.dot(ax1);
00917                     }
00918                     else
00919                     {
00920                         vel = linVelA.dot(ax1);
00921 //make sure that if no body -> angVelB == zero vec
00922 //                        if (body1)
00923                             vel -= linVelB.dot(ax1);
00924                     }
00925                     // only apply bounce if the velocity is incoming, and if the
00926                     // resulting c[] exceeds what we already have.
00927                     if (limit == 1)
00928                     {
00929                         if (vel < 0)
00930                         {
00931                             btScalar newc = -limot->m_bounce* vel;
00932                             if (newc > info->m_constraintError[srow]) 
00933                                                                 info->m_constraintError[srow] = newc;
00934                         }
00935                     }
00936                     else
00937                     {
00938                         if (vel > 0)
00939                         {
00940                             btScalar newc = -limot->m_bounce * vel;
00941                             if (newc < info->m_constraintError[srow]) 
00942                                                                 info->m_constraintError[srow] = newc;
00943                         }
00944                     }
00945                 }
00946             }
00947         }
00948         return 1;
00949     }
00950     else return 0;
00951 }
00952 
00953 
00954 
00955 
00956 
00957 
00960 void btGeneric6DofConstraint::setParam(int num, btScalar value, int axis)
00961 {
00962         if((axis >= 0) && (axis < 3))
00963         {
00964                 switch(num)
00965                 {
00966                         case BT_CONSTRAINT_STOP_ERP : 
00967                                 m_linearLimits.m_stopERP[axis] = value;
00968                                 m_flags |= BT_6DOF_FLAGS_ERP_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT);
00969                                 break;
00970                         case BT_CONSTRAINT_STOP_CFM : 
00971                                 m_linearLimits.m_stopCFM[axis] = value;
00972                                 m_flags |= BT_6DOF_FLAGS_CFM_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT);
00973                                 break;
00974                         case BT_CONSTRAINT_CFM : 
00975                                 m_linearLimits.m_normalCFM[axis] = value;
00976                                 m_flags |= BT_6DOF_FLAGS_CFM_NORM << (axis * BT_6DOF_FLAGS_AXIS_SHIFT);
00977                                 break;
00978                         default : 
00979                                 btAssertConstrParams(0);
00980                 }
00981         }
00982         else if((axis >=3) && (axis < 6))
00983         {
00984                 switch(num)
00985                 {
00986                         case BT_CONSTRAINT_STOP_ERP : 
00987                                 m_angularLimits[axis - 3].m_stopERP = value;
00988                                 m_flags |= BT_6DOF_FLAGS_ERP_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT);
00989                                 break;
00990                         case BT_CONSTRAINT_STOP_CFM : 
00991                                 m_angularLimits[axis - 3].m_stopCFM = value;
00992                                 m_flags |= BT_6DOF_FLAGS_CFM_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT);
00993                                 break;
00994                         case BT_CONSTRAINT_CFM : 
00995                                 m_angularLimits[axis - 3].m_normalCFM = value;
00996                                 m_flags |= BT_6DOF_FLAGS_CFM_NORM << (axis * BT_6DOF_FLAGS_AXIS_SHIFT);
00997                                 break;
00998                         default : 
00999                                 btAssertConstrParams(0);
01000                 }
01001         }
01002         else
01003         {
01004                 btAssertConstrParams(0);
01005         }
01006 }
01007 
01009 btScalar btGeneric6DofConstraint::getParam(int num, int axis) const 
01010 {
01011         btScalar retVal = 0;
01012         if((axis >= 0) && (axis < 3))
01013         {
01014                 switch(num)
01015                 {
01016                         case BT_CONSTRAINT_STOP_ERP : 
01017                                 btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT)));
01018                                 retVal = m_linearLimits.m_stopERP[axis];
01019                                 break;
01020                         case BT_CONSTRAINT_STOP_CFM : 
01021                                 btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT)));
01022                                 retVal = m_linearLimits.m_stopCFM[axis];
01023                                 break;
01024                         case BT_CONSTRAINT_CFM : 
01025                                 btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_NORM << (axis * BT_6DOF_FLAGS_AXIS_SHIFT)));
01026                                 retVal = m_linearLimits.m_normalCFM[axis];
01027                                 break;
01028                         default : 
01029                                 btAssertConstrParams(0);
01030                 }
01031         }
01032         else if((axis >=3) && (axis < 6))
01033         {
01034                 switch(num)
01035                 {
01036                         case BT_CONSTRAINT_STOP_ERP : 
01037                                 btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT)));
01038                                 retVal = m_angularLimits[axis - 3].m_stopERP;
01039                                 break;
01040                         case BT_CONSTRAINT_STOP_CFM : 
01041                                 btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT)));
01042                                 retVal = m_angularLimits[axis - 3].m_stopCFM;
01043                                 break;
01044                         case BT_CONSTRAINT_CFM : 
01045                                 btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_NORM << (axis * BT_6DOF_FLAGS_AXIS_SHIFT)));
01046                                 retVal = m_angularLimits[axis - 3].m_normalCFM;
01047                                 break;
01048                         default : 
01049                                 btAssertConstrParams(0);
01050                 }
01051         }
01052         else
01053         {
01054                 btAssertConstrParams(0);
01055         }
01056         return retVal;
01057 }
01058 
01059  
01060 
01061 void btGeneric6DofConstraint::setAxis(const btVector3& axis1,const btVector3& axis2)
01062 {
01063         btVector3 zAxis = axis1.normalized();
01064         btVector3 yAxis = axis2.normalized();
01065         btVector3 xAxis = yAxis.cross(zAxis); // we want right coordinate system
01066         
01067         btTransform frameInW;
01068         frameInW.setIdentity();
01069         frameInW.getBasis().setValue(   xAxis[0], yAxis[0], zAxis[0],   
01070                                         xAxis[1], yAxis[1], zAxis[1],
01071                                        xAxis[2], yAxis[2], zAxis[2]);
01072         
01073         // now get constraint frame in local coordinate systems
01074         m_frameInA = m_rbA.getCenterOfMassTransform().inverse() * frameInW;
01075         m_frameInB = m_rbB.getCenterOfMassTransform().inverse() * frameInW;
01076         
01077         calculateTransforms();
01078 }