2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the use of this software.
7 Permission is granted to anyone to use this software for any purpose,
8 including commercial applications, and to alter it and redistribute it freely,
9 subject to the following restrictions:
11 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.
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 3. This notice may not be removed or altered from any source distribution.
17 Refactored by Francisco Le?n
18 email: projectileman@yahoo.com
22 #include "b3Generic6DofConstraint.h"
23 #include "Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h"
25 #include "Bullet3Common/b3TransformUtil.h"
26 #include "Bullet3Common/b3TransformUtil.h"
29 #define D6_USE_OBSOLETE_METHOD false
30 #define D6_USE_FRAME_OFFSET true
32 b3Generic6DofConstraint::b3Generic6DofConstraint(int rbA, int rbB, const b3Transform& frameInA, const b3Transform& frameInB, bool useLinearReferenceFrameA, const b3RigidBodyData* bodies)
33 : b3TypedConstraint(B3_D6_CONSTRAINT_TYPE, rbA, rbB), m_frameInA(frameInA), m_frameInB(frameInB), m_useLinearReferenceFrameA(useLinearReferenceFrameA), m_useOffsetForConstraintFrame(D6_USE_FRAME_OFFSET), m_flags(0)
35 calculateTransforms(bodies);
38 #define GENERIC_D6_DISABLE_WARMSTARTING 1
40 b3Scalar btGetMatrixElem(const b3Matrix3x3& mat, int index);
41 b3Scalar btGetMatrixElem(const b3Matrix3x3& mat, int index)
48 ///MatrixToEulerXYZ from http://www.geometrictools.com/LibFoundation/Mathematics/Wm4Matrix3.inl.html
49 bool matrixToEulerXYZ(const b3Matrix3x3& mat, b3Vector3& xyz);
50 bool matrixToEulerXYZ(const b3Matrix3x3& mat, b3Vector3& xyz)
52 // // rot = cy*cz -cy*sz sy
53 // // cz*sx*sy+cx*sz cx*cz-sx*sy*sz -cy*sx
54 // // -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy
57 b3Scalar fi = btGetMatrixElem(mat, 2);
58 if (fi < b3Scalar(1.0f))
60 if (fi > b3Scalar(-1.0f))
62 xyz[0] = b3Atan2(-btGetMatrixElem(mat, 5), btGetMatrixElem(mat, 8));
63 xyz[1] = b3Asin(btGetMatrixElem(mat, 2));
64 xyz[2] = b3Atan2(-btGetMatrixElem(mat, 1), btGetMatrixElem(mat, 0));
69 // WARNING. Not unique. XA - ZA = -atan2(r10,r11)
70 xyz[0] = -b3Atan2(btGetMatrixElem(mat, 3), btGetMatrixElem(mat, 4));
72 xyz[2] = b3Scalar(0.0);
78 // WARNING. Not unique. XAngle + ZAngle = atan2(r10,r11)
79 xyz[0] = b3Atan2(btGetMatrixElem(mat, 3), btGetMatrixElem(mat, 4));
86 //////////////////////////// b3RotationalLimitMotor ////////////////////////////////////
88 int b3RotationalLimitMotor::testLimitValue(b3Scalar test_value)
90 if (m_loLimit > m_hiLimit)
92 m_currentLimit = 0; //Free from violation
95 if (test_value < m_loLimit)
97 m_currentLimit = 1; //low limit violation
98 m_currentLimitError = test_value - m_loLimit;
99 if (m_currentLimitError > B3_PI)
100 m_currentLimitError -= B3_2_PI;
101 else if (m_currentLimitError < -B3_PI)
102 m_currentLimitError += B3_2_PI;
105 else if (test_value > m_hiLimit)
107 m_currentLimit = 2; //High limit violation
108 m_currentLimitError = test_value - m_hiLimit;
109 if (m_currentLimitError > B3_PI)
110 m_currentLimitError -= B3_2_PI;
111 else if (m_currentLimitError < -B3_PI)
112 m_currentLimitError += B3_2_PI;
116 m_currentLimit = 0; //Free from violation
120 //////////////////////////// End b3RotationalLimitMotor ////////////////////////////////////
122 //////////////////////////// b3TranslationalLimitMotor ////////////////////////////////////
124 int b3TranslationalLimitMotor::testLimitValue(int limitIndex, b3Scalar test_value)
126 b3Scalar loLimit = m_lowerLimit[limitIndex];
127 b3Scalar hiLimit = m_upperLimit[limitIndex];
128 if (loLimit > hiLimit)
130 m_currentLimit[limitIndex] = 0; //Free from violation
131 m_currentLimitError[limitIndex] = b3Scalar(0.f);
135 if (test_value < loLimit)
137 m_currentLimit[limitIndex] = 2; //low limit violation
138 m_currentLimitError[limitIndex] = test_value - loLimit;
141 else if (test_value > hiLimit)
143 m_currentLimit[limitIndex] = 1; //High limit violation
144 m_currentLimitError[limitIndex] = test_value - hiLimit;
148 m_currentLimit[limitIndex] = 0; //Free from violation
149 m_currentLimitError[limitIndex] = b3Scalar(0.f);
153 //////////////////////////// b3TranslationalLimitMotor ////////////////////////////////////
155 void b3Generic6DofConstraint::calculateAngleInfo()
157 b3Matrix3x3 relative_frame = m_calculatedTransformA.getBasis().inverse() * m_calculatedTransformB.getBasis();
158 matrixToEulerXYZ(relative_frame, m_calculatedAxisAngleDiff);
159 // in euler angle mode we do not actually constrain the angular velocity
160 // along the axes axis[0] and axis[2] (although we do use axis[1]) :
162 // to get constrain w2-w1 along ...not
163 // ------ --------------------- ------
164 // d(angle[0])/dt = 0 ax[1] x ax[2] ax[0]
165 // d(angle[1])/dt = 0 ax[1]
166 // d(angle[2])/dt = 0 ax[0] x ax[1] ax[2]
168 // constraining w2-w1 along an axis 'a' means that a'*(w2-w1)=0.
169 // to prove the result for angle[0], write the expression for angle[0] from
170 // GetInfo1 then take the derivative. to prove this for angle[2] it is
171 // easier to take the euler rate expression for d(angle[2])/dt with respect
172 // to the components of w and set that to 0.
173 b3Vector3 axis0 = m_calculatedTransformB.getBasis().getColumn(0);
174 b3Vector3 axis2 = m_calculatedTransformA.getBasis().getColumn(2);
176 m_calculatedAxis[1] = axis2.cross(axis0);
177 m_calculatedAxis[0] = m_calculatedAxis[1].cross(axis2);
178 m_calculatedAxis[2] = axis0.cross(m_calculatedAxis[1]);
180 m_calculatedAxis[0].normalize();
181 m_calculatedAxis[1].normalize();
182 m_calculatedAxis[2].normalize();
185 static b3Transform getCenterOfMassTransform(const b3RigidBodyData& body)
187 b3Transform tr(body.m_quat, body.m_pos);
191 void b3Generic6DofConstraint::calculateTransforms(const b3RigidBodyData* bodies)
195 transA = getCenterOfMassTransform(bodies[m_rbA]);
196 transB = getCenterOfMassTransform(bodies[m_rbB]);
197 calculateTransforms(transA, transB, bodies);
200 void b3Generic6DofConstraint::calculateTransforms(const b3Transform& transA, const b3Transform& transB, const b3RigidBodyData* bodies)
202 m_calculatedTransformA = transA * m_frameInA;
203 m_calculatedTransformB = transB * m_frameInB;
204 calculateLinearInfo();
205 calculateAngleInfo();
206 if (m_useOffsetForConstraintFrame)
207 { // get weight factors depending on masses
208 b3Scalar miA = bodies[m_rbA].m_invMass;
209 b3Scalar miB = bodies[m_rbB].m_invMass;
210 m_hasStaticBody = (miA < B3_EPSILON) || (miB < B3_EPSILON);
211 b3Scalar miS = miA + miB;
212 if (miS > b3Scalar(0.f))
218 m_factA = b3Scalar(0.5f);
220 m_factB = b3Scalar(1.0f) - m_factA;
224 bool b3Generic6DofConstraint::testAngularLimitMotor(int axis_index)
226 b3Scalar angle = m_calculatedAxisAngleDiff[axis_index];
227 angle = b3AdjustAngleToLimits(angle, m_angularLimits[axis_index].m_loLimit, m_angularLimits[axis_index].m_hiLimit);
228 m_angularLimits[axis_index].m_currentPosition = angle;
230 m_angularLimits[axis_index].testLimitValue(angle);
231 return m_angularLimits[axis_index].needApplyTorques();
234 void b3Generic6DofConstraint::getInfo1(b3ConstraintInfo1* info, const b3RigidBodyData* bodies)
237 calculateTransforms(getCenterOfMassTransform(bodies[m_rbA]), getCenterOfMassTransform(bodies[m_rbB]), bodies);
238 info->m_numConstraintRows = 0;
242 for (i = 0; i < 3; i++)
244 if (m_linearLimits.needApplyForce(i))
246 info->m_numConstraintRows++;
250 //test angular limits
251 for (i = 0; i < 3; i++)
253 if (testAngularLimitMotor(i))
255 info->m_numConstraintRows++;
259 // printf("info->m_numConstraintRows=%d\n",info->m_numConstraintRows);
262 void b3Generic6DofConstraint::getInfo1NonVirtual(b3ConstraintInfo1* info, const b3RigidBodyData* bodies)
265 info->m_numConstraintRows = 6;
269 void b3Generic6DofConstraint::getInfo2(b3ConstraintInfo2* info, const b3RigidBodyData* bodies)
271 b3Transform transA = getCenterOfMassTransform(bodies[m_rbA]);
272 b3Transform transB = getCenterOfMassTransform(bodies[m_rbB]);
273 const b3Vector3& linVelA = bodies[m_rbA].m_linVel;
274 const b3Vector3& linVelB = bodies[m_rbB].m_linVel;
275 const b3Vector3& angVelA = bodies[m_rbA].m_angVel;
276 const b3Vector3& angVelB = bodies[m_rbB].m_angVel;
278 if (m_useOffsetForConstraintFrame)
279 { // for stability better to solve angular limits first
280 int row = setAngularLimits(info, 0, transA, transB, linVelA, linVelB, angVelA, angVelB);
281 setLinearLimits(info, row, transA, transB, linVelA, linVelB, angVelA, angVelB);
284 { // leave old version for compatibility
285 int row = setLinearLimits(info, 0, transA, transB, linVelA, linVelB, angVelA, angVelB);
286 setAngularLimits(info, row, transA, transB, linVelA, linVelB, angVelA, angVelB);
290 void b3Generic6DofConstraint::getInfo2NonVirtual(b3ConstraintInfo2* info, const b3Transform& transA, const b3Transform& transB, const b3Vector3& linVelA, const b3Vector3& linVelB, const b3Vector3& angVelA, const b3Vector3& angVelB, const b3RigidBodyData* bodies)
293 calculateTransforms(transA, transB, bodies);
296 for (i = 0; i < 3; i++)
298 testAngularLimitMotor(i);
301 if (m_useOffsetForConstraintFrame)
302 { // for stability better to solve angular limits first
303 int row = setAngularLimits(info, 0, transA, transB, linVelA, linVelB, angVelA, angVelB);
304 setLinearLimits(info, row, transA, transB, linVelA, linVelB, angVelA, angVelB);
307 { // leave old version for compatibility
308 int row = setLinearLimits(info, 0, transA, transB, linVelA, linVelB, angVelA, angVelB);
309 setAngularLimits(info, row, transA, transB, linVelA, linVelB, angVelA, angVelB);
313 int b3Generic6DofConstraint::setLinearLimits(b3ConstraintInfo2* info, int row, const b3Transform& transA, const b3Transform& transB, const b3Vector3& linVelA, const b3Vector3& linVelB, const b3Vector3& angVelA, const b3Vector3& angVelB)
316 //solve linear limits
317 b3RotationalLimitMotor limot;
318 for (int i = 0; i < 3; i++)
320 if (m_linearLimits.needApplyForce(i))
321 { // re-use rotational motor code
322 limot.m_bounce = b3Scalar(0.f);
323 limot.m_currentLimit = m_linearLimits.m_currentLimit[i];
324 limot.m_currentPosition = m_linearLimits.m_currentLinearDiff[i];
325 limot.m_currentLimitError = m_linearLimits.m_currentLimitError[i];
326 limot.m_damping = m_linearLimits.m_damping;
327 limot.m_enableMotor = m_linearLimits.m_enableMotor[i];
328 limot.m_hiLimit = m_linearLimits.m_upperLimit[i];
329 limot.m_limitSoftness = m_linearLimits.m_limitSoftness;
330 limot.m_loLimit = m_linearLimits.m_lowerLimit[i];
331 limot.m_maxLimitForce = b3Scalar(0.f);
332 limot.m_maxMotorForce = m_linearLimits.m_maxMotorForce[i];
333 limot.m_targetVelocity = m_linearLimits.m_targetVelocity[i];
334 b3Vector3 axis = m_calculatedTransformA.getBasis().getColumn(i);
335 int flags = m_flags >> (i * B3_6DOF_FLAGS_AXIS_SHIFT);
336 limot.m_normalCFM = (flags & B3_6DOF_FLAGS_CFM_NORM) ? m_linearLimits.m_normalCFM[i] : info->cfm[0];
337 limot.m_stopCFM = (flags & B3_6DOF_FLAGS_CFM_STOP) ? m_linearLimits.m_stopCFM[i] : info->cfm[0];
338 limot.m_stopERP = (flags & B3_6DOF_FLAGS_ERP_STOP) ? m_linearLimits.m_stopERP[i] : info->erp;
339 if (m_useOffsetForConstraintFrame)
341 int indx1 = (i + 1) % 3;
342 int indx2 = (i + 2) % 3;
343 int rotAllowed = 1; // rotations around orthos to current axis
344 if (m_angularLimits[indx1].m_currentLimit && m_angularLimits[indx2].m_currentLimit)
348 row += get_limit_motor_info2(&limot, transA, transB, linVelA, linVelB, angVelA, angVelB, info, row, axis, 0, rotAllowed);
352 row += get_limit_motor_info2(&limot, transA, transB, linVelA, linVelB, angVelA, angVelB, info, row, axis, 0);
359 int b3Generic6DofConstraint::setAngularLimits(b3ConstraintInfo2* info, int row_offset, const b3Transform& transA, const b3Transform& transB, const b3Vector3& linVelA, const b3Vector3& linVelB, const b3Vector3& angVelA, const b3Vector3& angVelB)
361 b3Generic6DofConstraint* d6constraint = this;
362 int row = row_offset;
363 //solve angular limits
364 for (int i = 0; i < 3; i++)
366 if (d6constraint->getRotationalLimitMotor(i)->needApplyTorques())
368 b3Vector3 axis = d6constraint->getAxis(i);
369 int flags = m_flags >> ((i + 3) * B3_6DOF_FLAGS_AXIS_SHIFT);
370 if (!(flags & B3_6DOF_FLAGS_CFM_NORM))
372 m_angularLimits[i].m_normalCFM = info->cfm[0];
374 if (!(flags & B3_6DOF_FLAGS_CFM_STOP))
376 m_angularLimits[i].m_stopCFM = info->cfm[0];
378 if (!(flags & B3_6DOF_FLAGS_ERP_STOP))
380 m_angularLimits[i].m_stopERP = info->erp;
382 row += get_limit_motor_info2(d6constraint->getRotationalLimitMotor(i),
383 transA, transB, linVelA, linVelB, angVelA, angVelB, info, row, axis, 1);
390 void b3Generic6DofConstraint::updateRHS(b3Scalar timeStep)
395 void b3Generic6DofConstraint::setFrames(const b3Transform& frameA, const b3Transform& frameB, const b3RigidBodyData* bodies)
400 calculateTransforms(bodies);
403 b3Vector3 b3Generic6DofConstraint::getAxis(int axis_index) const
405 return m_calculatedAxis[axis_index];
408 b3Scalar b3Generic6DofConstraint::getRelativePivotPosition(int axisIndex) const
410 return m_calculatedLinearDiff[axisIndex];
413 b3Scalar b3Generic6DofConstraint::getAngle(int axisIndex) const
415 return m_calculatedAxisAngleDiff[axisIndex];
418 void b3Generic6DofConstraint::calcAnchorPos(const b3RigidBodyData* bodies)
420 b3Scalar imA = bodies[m_rbA].m_invMass;
421 b3Scalar imB = bodies[m_rbB].m_invMass;
423 if (imB == b3Scalar(0.0))
425 weight = b3Scalar(1.0);
429 weight = imA / (imA + imB);
431 const b3Vector3& pA = m_calculatedTransformA.getOrigin();
432 const b3Vector3& pB = m_calculatedTransformB.getOrigin();
433 m_AnchorPos = pA * weight + pB * (b3Scalar(1.0) - weight);
437 void b3Generic6DofConstraint::calculateLinearInfo()
439 m_calculatedLinearDiff = m_calculatedTransformB.getOrigin() - m_calculatedTransformA.getOrigin();
440 m_calculatedLinearDiff = m_calculatedTransformA.getBasis().inverse() * m_calculatedLinearDiff;
441 for (int i = 0; i < 3; i++)
443 m_linearLimits.m_currentLinearDiff[i] = m_calculatedLinearDiff[i];
444 m_linearLimits.testLimitValue(i, m_calculatedLinearDiff[i]);
448 int b3Generic6DofConstraint::get_limit_motor_info2(
449 b3RotationalLimitMotor* limot,
450 const b3Transform& transA, const b3Transform& transB, const b3Vector3& linVelA, const b3Vector3& linVelB, const b3Vector3& angVelA, const b3Vector3& angVelB,
451 b3ConstraintInfo2* info, int row, b3Vector3& ax1, int rotational, int rotAllowed)
453 int srow = row * info->rowskip;
454 bool powered = limot->m_enableMotor;
455 int limit = limot->m_currentLimit;
456 if (powered || limit)
457 { // if the joint is powered, or has joint limits, add in the extra row
458 b3Scalar* J1 = rotational ? info->m_J1angularAxis : info->m_J1linearAxis;
459 b3Scalar* J2 = rotational ? info->m_J2angularAxis : info->m_J2linearAxis;
462 J1[srow + 0] = ax1[0];
463 J1[srow + 1] = ax1[1];
464 J1[srow + 2] = ax1[2];
468 J2[srow + 0] = -ax1[0];
469 J2[srow + 1] = -ax1[1];
470 J2[srow + 2] = -ax1[2];
474 if (m_useOffsetForConstraintFrame)
476 b3Vector3 tmpA, tmpB, relA, relB;
477 // get vector from bodyB to frameB in WCS
478 relB = m_calculatedTransformB.getOrigin() - transB.getOrigin();
479 // get its projection to constraint axis
480 b3Vector3 projB = ax1 * relB.dot(ax1);
481 // get vector directed from bodyB to constraint axis (and orthogonal to it)
482 b3Vector3 orthoB = relB - projB;
484 relA = m_calculatedTransformA.getOrigin() - transA.getOrigin();
485 b3Vector3 projA = ax1 * relA.dot(ax1);
486 b3Vector3 orthoA = relA - projA;
487 // get desired offset between frames A and B along constraint axis
488 b3Scalar desiredOffs = limot->m_currentPosition - limot->m_currentLimitError;
489 // desired vector from projection of center of bodyA to projection of center of bodyB to constraint axis
490 b3Vector3 totalDist = projA + ax1 * desiredOffs - projB;
491 // get offset vectors relA and relB
492 relA = orthoA + totalDist * m_factA;
493 relB = orthoB - totalDist * m_factB;
494 tmpA = relA.cross(ax1);
495 tmpB = relB.cross(ax1);
496 if (m_hasStaticBody && (!rotAllowed))
502 for (i = 0; i < 3; i++) info->m_J1angularAxis[srow + i] = tmpA[i];
503 for (i = 0; i < 3; i++) info->m_J2angularAxis[srow + i] = -tmpB[i];
507 b3Vector3 ltd; // Linear Torque Decoupling vector
508 b3Vector3 c = m_calculatedTransformB.getOrigin() - transA.getOrigin();
510 info->m_J1angularAxis[srow + 0] = ltd[0];
511 info->m_J1angularAxis[srow + 1] = ltd[1];
512 info->m_J1angularAxis[srow + 2] = ltd[2];
514 c = m_calculatedTransformB.getOrigin() - transB.getOrigin();
516 info->m_J2angularAxis[srow + 0] = ltd[0];
517 info->m_J2angularAxis[srow + 1] = ltd[1];
518 info->m_J2angularAxis[srow + 2] = ltd[2];
521 // if we're limited low and high simultaneously, the joint motor is
523 if (limit && (limot->m_loLimit == limot->m_hiLimit)) powered = false;
524 info->m_constraintError[srow] = b3Scalar(0.f);
527 info->cfm[srow] = limot->m_normalCFM;
530 b3Scalar tag_vel = rotational ? limot->m_targetVelocity : -limot->m_targetVelocity;
532 b3Scalar mot_fact = getMotorFactor(limot->m_currentPosition,
536 info->fps * limot->m_stopERP);
537 info->m_constraintError[srow] += mot_fact * limot->m_targetVelocity;
538 info->m_lowerLimit[srow] = -limot->m_maxMotorForce / info->fps;
539 info->m_upperLimit[srow] = limot->m_maxMotorForce / info->fps;
544 b3Scalar k = info->fps * limot->m_stopERP;
547 info->m_constraintError[srow] += k * limot->m_currentLimitError;
551 info->m_constraintError[srow] += -k * limot->m_currentLimitError;
553 info->cfm[srow] = limot->m_stopCFM;
554 if (limot->m_loLimit == limot->m_hiLimit)
555 { // limited low and high simultaneously
556 info->m_lowerLimit[srow] = -B3_INFINITY;
557 info->m_upperLimit[srow] = B3_INFINITY;
563 info->m_lowerLimit[srow] = 0;
564 info->m_upperLimit[srow] = B3_INFINITY;
568 info->m_lowerLimit[srow] = -B3_INFINITY;
569 info->m_upperLimit[srow] = 0;
572 if (limot->m_bounce > 0)
574 // calculate joint velocity
578 vel = angVelA.dot(ax1);
579 //make sure that if no body -> angVelB == zero vec
581 vel -= angVelB.dot(ax1);
585 vel = linVelA.dot(ax1);
586 //make sure that if no body -> angVelB == zero vec
588 vel -= linVelB.dot(ax1);
590 // only apply bounce if the velocity is incoming, and if the
591 // resulting c[] exceeds what we already have.
596 b3Scalar newc = -limot->m_bounce * vel;
597 if (newc > info->m_constraintError[srow])
598 info->m_constraintError[srow] = newc;
605 b3Scalar newc = -limot->m_bounce * vel;
606 if (newc < info->m_constraintError[srow])
607 info->m_constraintError[srow] = newc;
619 ///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5).
620 ///If no axis is provided, it uses the default axis for this constraint.
621 void b3Generic6DofConstraint::setParam(int num, b3Scalar value, int axis)
623 if ((axis >= 0) && (axis < 3))
627 case B3_CONSTRAINT_STOP_ERP:
628 m_linearLimits.m_stopERP[axis] = value;
629 m_flags |= B3_6DOF_FLAGS_ERP_STOP << (axis * B3_6DOF_FLAGS_AXIS_SHIFT);
631 case B3_CONSTRAINT_STOP_CFM:
632 m_linearLimits.m_stopCFM[axis] = value;
633 m_flags |= B3_6DOF_FLAGS_CFM_STOP << (axis * B3_6DOF_FLAGS_AXIS_SHIFT);
635 case B3_CONSTRAINT_CFM:
636 m_linearLimits.m_normalCFM[axis] = value;
637 m_flags |= B3_6DOF_FLAGS_CFM_NORM << (axis * B3_6DOF_FLAGS_AXIS_SHIFT);
640 b3AssertConstrParams(0);
643 else if ((axis >= 3) && (axis < 6))
647 case B3_CONSTRAINT_STOP_ERP:
648 m_angularLimits[axis - 3].m_stopERP = value;
649 m_flags |= B3_6DOF_FLAGS_ERP_STOP << (axis * B3_6DOF_FLAGS_AXIS_SHIFT);
651 case B3_CONSTRAINT_STOP_CFM:
652 m_angularLimits[axis - 3].m_stopCFM = value;
653 m_flags |= B3_6DOF_FLAGS_CFM_STOP << (axis * B3_6DOF_FLAGS_AXIS_SHIFT);
655 case B3_CONSTRAINT_CFM:
656 m_angularLimits[axis - 3].m_normalCFM = value;
657 m_flags |= B3_6DOF_FLAGS_CFM_NORM << (axis * B3_6DOF_FLAGS_AXIS_SHIFT);
660 b3AssertConstrParams(0);
665 b3AssertConstrParams(0);
669 ///return the local value of parameter
670 b3Scalar b3Generic6DofConstraint::getParam(int num, int axis) const
673 if ((axis >= 0) && (axis < 3))
677 case B3_CONSTRAINT_STOP_ERP:
678 b3AssertConstrParams(m_flags & (B3_6DOF_FLAGS_ERP_STOP << (axis * B3_6DOF_FLAGS_AXIS_SHIFT)));
679 retVal = m_linearLimits.m_stopERP[axis];
681 case B3_CONSTRAINT_STOP_CFM:
682 b3AssertConstrParams(m_flags & (B3_6DOF_FLAGS_CFM_STOP << (axis * B3_6DOF_FLAGS_AXIS_SHIFT)));
683 retVal = m_linearLimits.m_stopCFM[axis];
685 case B3_CONSTRAINT_CFM:
686 b3AssertConstrParams(m_flags & (B3_6DOF_FLAGS_CFM_NORM << (axis * B3_6DOF_FLAGS_AXIS_SHIFT)));
687 retVal = m_linearLimits.m_normalCFM[axis];
690 b3AssertConstrParams(0);
693 else if ((axis >= 3) && (axis < 6))
697 case B3_CONSTRAINT_STOP_ERP:
698 b3AssertConstrParams(m_flags & (B3_6DOF_FLAGS_ERP_STOP << (axis * B3_6DOF_FLAGS_AXIS_SHIFT)));
699 retVal = m_angularLimits[axis - 3].m_stopERP;
701 case B3_CONSTRAINT_STOP_CFM:
702 b3AssertConstrParams(m_flags & (B3_6DOF_FLAGS_CFM_STOP << (axis * B3_6DOF_FLAGS_AXIS_SHIFT)));
703 retVal = m_angularLimits[axis - 3].m_stopCFM;
705 case B3_CONSTRAINT_CFM:
706 b3AssertConstrParams(m_flags & (B3_6DOF_FLAGS_CFM_NORM << (axis * B3_6DOF_FLAGS_AXIS_SHIFT)));
707 retVal = m_angularLimits[axis - 3].m_normalCFM;
710 b3AssertConstrParams(0);
715 b3AssertConstrParams(0);
720 void b3Generic6DofConstraint::setAxis(const b3Vector3& axis1, const b3Vector3& axis2, const b3RigidBodyData* bodies)
722 b3Vector3 zAxis = axis1.normalized();
723 b3Vector3 yAxis = axis2.normalized();
724 b3Vector3 xAxis = yAxis.cross(zAxis); // we want right coordinate system
726 b3Transform frameInW;
727 frameInW.setIdentity();
728 frameInW.getBasis().setValue(xAxis[0], yAxis[0], zAxis[0],
729 xAxis[1], yAxis[1], zAxis[1],
730 xAxis[2], yAxis[2], zAxis[2]);
732 // now get constraint frame in local coordinate systems
733 m_frameInA = getCenterOfMassTransform(bodies[m_rbA]).inverse() * frameInW;
734 m_frameInB = getCenterOfMassTransform(bodies[m_rbB]).inverse() * frameInW;
736 calculateTransforms(bodies);