Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/physics/src/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp @ 1963

Last change on this file since 1963 was 1963, checked in by rgrieder, 16 years ago

Added Bullet physics engine.

  • Property svn:eol-style set to native
File size: 14.7 KB
Line 
1/*
2Bullet Continuous Collision Detection and Physics Library
3Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
4
5This software is provided 'as-is', without any express or implied warranty.
6In no event will the authors be held liable for any damages arising from the use of this software.
7Permission is granted to anyone to use this software for any purpose,
8including commercial applications, and to alter it and redistribute it freely,
9subject to the following restrictions:
10
111. 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.
122. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
133. This notice may not be removed or altered from any source distribution.
14*/
15/*
162007-09-09
17Refactored by Francisco Le?n
18email: projectileman@yahoo.com
19http://gimpact.sf.net
20*/
21
22
23#include "btGeneric6DofConstraint.h"
24#include "BulletDynamics/Dynamics/btRigidBody.h"
25#include "LinearMath/btTransformUtil.h"
26#include <new>
27
28
29static const btScalar kSign[] = { btScalar(1.0), btScalar(-1.0), btScalar(1.0) };
30static const int kAxisA[] = { 1, 0, 0 };
31static const int kAxisB[] = { 2, 2, 1 };
32#define GENERIC_D6_DISABLE_WARMSTARTING 1
33
34btScalar btGetMatrixElem(const btMatrix3x3& mat, int index);
35btScalar btGetMatrixElem(const btMatrix3x3& mat, int index)
36{
37        int i = index%3;
38        int j = index/3;
39        return mat[i][j];
40}
41
42///MatrixToEulerXYZ from http://www.geometrictools.com/LibFoundation/Mathematics/Wm4Matrix3.inl.html
43bool    matrixToEulerXYZ(const btMatrix3x3& mat,btVector3& xyz);
44bool    matrixToEulerXYZ(const btMatrix3x3& mat,btVector3& xyz)
45{
46//      // rot =  cy*cz          -cy*sz           sy
47//      //        cz*sx*sy+cx*sz  cx*cz-sx*sy*sz -cy*sx
48//      //       -cx*cz*sy+sx*sz  cz*sx+cx*sy*sz  cx*cy
49//
50
51                if (btGetMatrixElem(mat,2) < btScalar(1.0))
52                {
53                        if (btGetMatrixElem(mat,2) > btScalar(-1.0))
54                        {
55                                xyz[0] = btAtan2(-btGetMatrixElem(mat,5),btGetMatrixElem(mat,8));
56                                xyz[1] = btAsin(btGetMatrixElem(mat,2));
57                                xyz[2] = btAtan2(-btGetMatrixElem(mat,1),btGetMatrixElem(mat,0));
58                                return true;
59                        }
60                        else
61                        {
62                                // WARNING.  Not unique.  XA - ZA = -atan2(r10,r11)
63                                xyz[0] = -btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4));
64                                xyz[1] = -SIMD_HALF_PI;
65                                xyz[2] = btScalar(0.0);
66                                return false;
67                        }
68                }
69                else
70                {
71                        // WARNING.  Not unique.  XAngle + ZAngle = atan2(r10,r11)
72                        xyz[0] = btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4));
73                        xyz[1] = SIMD_HALF_PI;
74                        xyz[2] = 0.0;
75
76                }
77
78
79        return false;
80}
81
82
83
84//////////////////////////// btRotationalLimitMotor ////////////////////////////////////
85
86
87int btRotationalLimitMotor::testLimitValue(btScalar test_value)
88{
89        if(m_loLimit>m_hiLimit)
90        {
91                m_currentLimit = 0;//Free from violation
92                return 0;
93        }
94
95        if (test_value < m_loLimit)
96        {
97                m_currentLimit = 1;//low limit violation
98                m_currentLimitError =  test_value - m_loLimit;
99                return 1;
100        }
101        else if (test_value> m_hiLimit)
102        {
103                m_currentLimit = 2;//High limit violation
104                m_currentLimitError = test_value - m_hiLimit;
105                return 2;
106        };
107
108        m_currentLimit = 0;//Free from violation
109        return 0;
110       
111}
112
113
114btScalar btRotationalLimitMotor::solveAngularLimits(
115                btScalar timeStep,btVector3& axis,btScalar jacDiagABInv,
116                btRigidBody * body0, btRigidBody * body1)
117{
118    if (needApplyTorques()==false) return 0.0f;
119
120    btScalar target_velocity = m_targetVelocity;
121    btScalar maxMotorForce = m_maxMotorForce;
122
123        //current error correction
124    if (m_currentLimit!=0)
125    {
126        target_velocity = -m_ERP*m_currentLimitError/(timeStep);
127        maxMotorForce = m_maxLimitForce;
128    }
129
130    maxMotorForce *= timeStep;
131
132    // current velocity difference
133    btVector3 vel_diff = body0->getAngularVelocity();
134    if (body1)
135    {
136        vel_diff -= body1->getAngularVelocity();
137    }
138
139
140
141    btScalar rel_vel = axis.dot(vel_diff);
142
143        // correction velocity
144    btScalar motor_relvel = m_limitSoftness*(target_velocity  - m_damping*rel_vel);
145
146
147    if ( motor_relvel < SIMD_EPSILON && motor_relvel > -SIMD_EPSILON  )
148    {
149        return 0.0f;//no need for applying force
150    }
151
152
153        // correction impulse
154    btScalar unclippedMotorImpulse = (1+m_bounce)*motor_relvel*jacDiagABInv;
155
156        // clip correction impulse
157    btScalar clippedMotorImpulse;
158
159    //todo: should clip against accumulated impulse
160    if (unclippedMotorImpulse>0.0f)
161    {
162        clippedMotorImpulse =  unclippedMotorImpulse > maxMotorForce? maxMotorForce: unclippedMotorImpulse;
163    }
164    else
165    {
166        clippedMotorImpulse =  unclippedMotorImpulse < -maxMotorForce ? -maxMotorForce: unclippedMotorImpulse;
167    }
168
169
170        // sort with accumulated impulses
171    btScalar    lo = btScalar(-1e30);
172    btScalar    hi = btScalar(1e30);
173
174    btScalar oldaccumImpulse = m_accumulatedImpulse;
175    btScalar sum = oldaccumImpulse + clippedMotorImpulse;
176    m_accumulatedImpulse = sum > hi ? btScalar(0.) : sum < lo ? btScalar(0.) : sum;
177
178    clippedMotorImpulse = m_accumulatedImpulse - oldaccumImpulse;
179
180
181
182    btVector3 motorImp = clippedMotorImpulse * axis;
183
184
185    body0->applyTorqueImpulse(motorImp);
186    if (body1) body1->applyTorqueImpulse(-motorImp);
187
188    return clippedMotorImpulse;
189
190
191}
192
193//////////////////////////// End btRotationalLimitMotor ////////////////////////////////////
194
195//////////////////////////// btTranslationalLimitMotor ////////////////////////////////////
196btScalar btTranslationalLimitMotor::solveLinearAxis(
197                btScalar timeStep,
198        btScalar jacDiagABInv,
199        btRigidBody& body1,const btVector3 &pointInA,
200        btRigidBody& body2,const btVector3 &pointInB,
201        int limit_index,
202        const btVector3 & axis_normal_on_a,
203                const btVector3 & anchorPos)
204{
205
206///find relative velocity
207//    btVector3 rel_pos1 = pointInA - body1.getCenterOfMassPosition();
208//    btVector3 rel_pos2 = pointInB - body2.getCenterOfMassPosition();
209    btVector3 rel_pos1 = anchorPos - body1.getCenterOfMassPosition();
210    btVector3 rel_pos2 = anchorPos - body2.getCenterOfMassPosition();
211
212    btVector3 vel1 = body1.getVelocityInLocalPoint(rel_pos1);
213    btVector3 vel2 = body2.getVelocityInLocalPoint(rel_pos2);
214    btVector3 vel = vel1 - vel2;
215
216    btScalar rel_vel = axis_normal_on_a.dot(vel);
217
218
219
220/// apply displacement correction
221
222//positional error (zeroth order error)
223    btScalar depth = -(pointInA - pointInB).dot(axis_normal_on_a);
224    btScalar    lo = btScalar(-1e30);
225    btScalar    hi = btScalar(1e30);
226
227    btScalar minLimit = m_lowerLimit[limit_index];
228    btScalar maxLimit = m_upperLimit[limit_index];
229
230    //handle the limits
231    if (minLimit < maxLimit)
232    {
233        {
234            if (depth > maxLimit)
235            {
236                depth -= maxLimit;
237                lo = btScalar(0.);
238
239            }
240            else
241            {
242                if (depth < minLimit)
243                {
244                    depth -= minLimit;
245                    hi = btScalar(0.);
246                }
247                else
248                {
249                    return 0.0f;
250                }
251            }
252        }
253    }
254
255    btScalar normalImpulse= m_limitSoftness*(m_restitution*depth/timeStep - m_damping*rel_vel) * jacDiagABInv;
256
257
258
259
260    btScalar oldNormalImpulse = m_accumulatedImpulse[limit_index];
261    btScalar sum = oldNormalImpulse + normalImpulse;
262    m_accumulatedImpulse[limit_index] = sum > hi ? btScalar(0.) : sum < lo ? btScalar(0.) : sum;
263    normalImpulse = m_accumulatedImpulse[limit_index] - oldNormalImpulse;
264
265    btVector3 impulse_vector = axis_normal_on_a * normalImpulse;
266    body1.applyImpulse( impulse_vector, rel_pos1);
267    body2.applyImpulse(-impulse_vector, rel_pos2);
268    return normalImpulse;
269}
270
271//////////////////////////// btTranslationalLimitMotor ////////////////////////////////////
272
273
274btGeneric6DofConstraint::btGeneric6DofConstraint()
275        :btTypedConstraint(D6_CONSTRAINT_TYPE),
276                m_useLinearReferenceFrameA(true)
277{
278}
279
280btGeneric6DofConstraint::btGeneric6DofConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB, bool useLinearReferenceFrameA)
281        : btTypedConstraint(D6_CONSTRAINT_TYPE, rbA, rbB)
282        , m_frameInA(frameInA)
283        , m_frameInB(frameInB),
284                m_useLinearReferenceFrameA(useLinearReferenceFrameA)
285{
286
287}
288
289
290
291
292
293void btGeneric6DofConstraint::calculateAngleInfo()
294{
295        btMatrix3x3 relative_frame = m_calculatedTransformA.getBasis().inverse()*m_calculatedTransformB.getBasis();
296
297        matrixToEulerXYZ(relative_frame,m_calculatedAxisAngleDiff);
298
299
300
301        // in euler angle mode we do not actually constrain the angular velocity
302  // along the axes axis[0] and axis[2] (although we do use axis[1]) :
303  //
304  //    to get                  constrain w2-w1 along           ...not
305  //    ------                  ---------------------           ------
306  //    d(angle[0])/dt = 0      ax[1] x ax[2]                   ax[0]
307  //    d(angle[1])/dt = 0      ax[1]
308  //    d(angle[2])/dt = 0      ax[0] x ax[1]                   ax[2]
309  //
310  // constraining w2-w1 along an axis 'a' means that a'*(w2-w1)=0.
311  // to prove the result for angle[0], write the expression for angle[0] from
312  // GetInfo1 then take the derivative. to prove this for angle[2] it is
313  // easier to take the euler rate expression for d(angle[2])/dt with respect
314  // to the components of w and set that to 0.
315
316        btVector3 axis0 = m_calculatedTransformB.getBasis().getColumn(0);
317        btVector3 axis2 = m_calculatedTransformA.getBasis().getColumn(2);
318
319        m_calculatedAxis[1] = axis2.cross(axis0);
320        m_calculatedAxis[0] = m_calculatedAxis[1].cross(axis2);
321        m_calculatedAxis[2] = axis0.cross(m_calculatedAxis[1]);
322
323
324//    if(m_debugDrawer)
325//    {
326//
327//      char buff[300];
328//              sprintf(buff,"\n X: %.2f ; Y: %.2f ; Z: %.2f ",
329//              m_calculatedAxisAngleDiff[0],
330//              m_calculatedAxisAngleDiff[1],
331//              m_calculatedAxisAngleDiff[2]);
332//      m_debugDrawer->reportErrorWarning(buff);
333//    }
334
335}
336
337void btGeneric6DofConstraint::calculateTransforms()
338{
339    m_calculatedTransformA = m_rbA.getCenterOfMassTransform() * m_frameInA;
340    m_calculatedTransformB = m_rbB.getCenterOfMassTransform() * m_frameInB;
341
342    calculateAngleInfo();
343}
344
345
346void btGeneric6DofConstraint::buildLinearJacobian(
347    btJacobianEntry & jacLinear,const btVector3 & normalWorld,
348    const btVector3 & pivotAInW,const btVector3 & pivotBInW)
349{
350    new (&jacLinear) btJacobianEntry(
351        m_rbA.getCenterOfMassTransform().getBasis().transpose(),
352        m_rbB.getCenterOfMassTransform().getBasis().transpose(),
353        pivotAInW - m_rbA.getCenterOfMassPosition(),
354        pivotBInW - m_rbB.getCenterOfMassPosition(),
355        normalWorld,
356        m_rbA.getInvInertiaDiagLocal(),
357        m_rbA.getInvMass(),
358        m_rbB.getInvInertiaDiagLocal(),
359        m_rbB.getInvMass());
360
361}
362
363void btGeneric6DofConstraint::buildAngularJacobian(
364    btJacobianEntry & jacAngular,const btVector3 & jointAxisW)
365{
366    new (&jacAngular)   btJacobianEntry(jointAxisW,
367                                      m_rbA.getCenterOfMassTransform().getBasis().transpose(),
368                                      m_rbB.getCenterOfMassTransform().getBasis().transpose(),
369                                      m_rbA.getInvInertiaDiagLocal(),
370                                      m_rbB.getInvInertiaDiagLocal());
371
372}
373
374bool btGeneric6DofConstraint::testAngularLimitMotor(int axis_index)
375{
376    btScalar angle = m_calculatedAxisAngleDiff[axis_index];
377
378    //test limits
379    m_angularLimits[axis_index].testLimitValue(angle);
380    return m_angularLimits[axis_index].needApplyTorques();
381}
382
383void btGeneric6DofConstraint::buildJacobian()
384{
385
386        // Clear accumulated impulses for the next simulation step
387    m_linearLimits.m_accumulatedImpulse.setValue(btScalar(0.), btScalar(0.), btScalar(0.));
388    int i;
389    for(i = 0; i < 3; i++)
390    {
391        m_angularLimits[i].m_accumulatedImpulse = btScalar(0.);
392    }
393    //calculates transform
394    calculateTransforms();
395
396//  const btVector3& pivotAInW = m_calculatedTransformA.getOrigin();
397//  const btVector3& pivotBInW = m_calculatedTransformB.getOrigin();
398        calcAnchorPos();
399        btVector3 pivotAInW = m_AnchorPos;
400        btVector3 pivotBInW = m_AnchorPos;
401
402// not used here
403//    btVector3 rel_pos1 = pivotAInW - m_rbA.getCenterOfMassPosition();
404//    btVector3 rel_pos2 = pivotBInW - m_rbB.getCenterOfMassPosition();
405
406    btVector3 normalWorld;
407    //linear part
408    for (i=0;i<3;i++)
409    {
410        if (m_linearLimits.isLimited(i))
411        {
412                        if (m_useLinearReferenceFrameA)
413                    normalWorld = m_calculatedTransformA.getBasis().getColumn(i);
414                        else
415                    normalWorld = m_calculatedTransformB.getBasis().getColumn(i);
416
417            buildLinearJacobian(
418                m_jacLinear[i],normalWorld ,
419                pivotAInW,pivotBInW);
420
421        }
422    }
423
424    // angular part
425    for (i=0;i<3;i++)
426    {
427        //calculates error angle
428        if (testAngularLimitMotor(i))
429        {
430            normalWorld = this->getAxis(i);
431            // Create angular atom
432            buildAngularJacobian(m_jacAng[i],normalWorld);
433        }
434    }
435
436
437}
438
439
440void btGeneric6DofConstraint::solveConstraint(btScalar  timeStep)
441{
442    m_timeStep = timeStep;
443
444    //calculateTransforms();
445
446    int i;
447
448    // linear
449
450    btVector3 pointInA = m_calculatedTransformA.getOrigin();
451        btVector3 pointInB = m_calculatedTransformB.getOrigin();
452
453        btScalar jacDiagABInv;
454        btVector3 linear_axis;
455    for (i=0;i<3;i++)
456    {
457        if (m_linearLimits.isLimited(i))
458        {
459            jacDiagABInv = btScalar(1.) / m_jacLinear[i].getDiagonal();
460
461                        if (m_useLinearReferenceFrameA)
462                    linear_axis = m_calculatedTransformA.getBasis().getColumn(i);
463                        else
464                    linear_axis = m_calculatedTransformB.getBasis().getColumn(i);
465
466            m_linearLimits.solveLinearAxis(
467                m_timeStep,
468                jacDiagABInv,
469                m_rbA,pointInA,
470                m_rbB,pointInB,
471                i,linear_axis, m_AnchorPos);
472
473        }
474    }
475
476    // angular
477    btVector3 angular_axis;
478    btScalar angularJacDiagABInv;
479    for (i=0;i<3;i++)
480    {
481        if (m_angularLimits[i].needApplyTorques())
482        {
483
484                        // get axis
485                        angular_axis = getAxis(i);
486
487                        angularJacDiagABInv = btScalar(1.) / m_jacAng[i].getDiagonal();
488
489                        m_angularLimits[i].solveAngularLimits(m_timeStep,angular_axis,angularJacDiagABInv, &m_rbA,&m_rbB);
490        }
491    }
492}
493
494void    btGeneric6DofConstraint::updateRHS(btScalar     timeStep)
495{
496    (void)timeStep;
497
498}
499
500btVector3 btGeneric6DofConstraint::getAxis(int axis_index) const
501{
502    return m_calculatedAxis[axis_index];
503}
504
505btScalar btGeneric6DofConstraint::getAngle(int axis_index) const
506{
507    return m_calculatedAxisAngleDiff[axis_index];
508}
509
510void btGeneric6DofConstraint::calcAnchorPos(void)
511{
512        btScalar imA = m_rbA.getInvMass();
513        btScalar imB = m_rbB.getInvMass();
514        btScalar weight;
515        if(imB == btScalar(0.0))
516        {
517                weight = btScalar(1.0);
518        }
519        else
520        {
521                weight = imA / (imA + imB);
522        }
523        const btVector3& pA = m_calculatedTransformA.getOrigin();
524        const btVector3& pB = m_calculatedTransformB.getOrigin();
525        m_AnchorPos = pA * weight + pB * (btScalar(1.0) - weight);
526        return;
527} // btGeneric6DofConstraint::calcAnchorPos()
528
Note: See TracBrowser for help on using the repository browser.