1 /*
2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
4 
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:
10 
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.
14 */
15 
16 
17 #include "btHingeConstraint.h"
18 #include "BulletDynamics/Dynamics/btRigidBody.h"
19 #include "LinearMath/btTransformUtil.h"
20 #include "LinearMath/btMinMax.h"
21 #include <new>
22 #include "btSolverBody.h"
23 
24 
25 
26 //#define HINGE_USE_OBSOLETE_SOLVER false
27 #define HINGE_USE_OBSOLETE_SOLVER false
28 
29 #define HINGE_USE_FRAME_OFFSET true
30 
31 #ifndef __SPU__
32 
33 
34 
35 
36 
btHingeConstraint(btRigidBody & rbA,btRigidBody & rbB,const btVector3 & pivotInA,const btVector3 & pivotInB,const btVector3 & axisInA,const btVector3 & axisInB,bool useReferenceFrameA)37 btHingeConstraint::btHingeConstraint(btRigidBody& rbA,btRigidBody& rbB, const btVector3& pivotInA,const btVector3& pivotInB,
38 									 const btVector3& axisInA,const btVector3& axisInB, bool useReferenceFrameA)
39 									 :btTypedConstraint(HINGE_CONSTRAINT_TYPE, rbA,rbB),
40 #ifdef _BT_USE_CENTER_LIMIT_
41 									 m_limit(),
42 #endif
43 									 m_angularOnly(false),
44 									 m_enableAngularMotor(false),
45 									 m_useSolveConstraintObsolete(HINGE_USE_OBSOLETE_SOLVER),
46 									 m_useOffsetForConstraintFrame(HINGE_USE_FRAME_OFFSET),
47 									 m_useReferenceFrameA(useReferenceFrameA),
48 									 m_flags(0),
49 									 m_normalCFM(0),
50 									 m_normalERP(0),
51 									 m_stopCFM(0),
52 									 m_stopERP(0)
53 {
54 	m_rbAFrame.getOrigin() = pivotInA;
55 
56 	// since no frame is given, assume this to be zero angle and just pick rb transform axis
57 	btVector3 rbAxisA1 = rbA.getCenterOfMassTransform().getBasis().getColumn(0);
58 
59 	btVector3 rbAxisA2;
60 	btScalar projection = axisInA.dot(rbAxisA1);
61 	if (projection >= 1.0f - SIMD_EPSILON) {
62 		rbAxisA1 = -rbA.getCenterOfMassTransform().getBasis().getColumn(2);
63 		rbAxisA2 = rbA.getCenterOfMassTransform().getBasis().getColumn(1);
64 	} else if (projection <= -1.0f + SIMD_EPSILON) {
65 		rbAxisA1 = rbA.getCenterOfMassTransform().getBasis().getColumn(2);
66 		rbAxisA2 = rbA.getCenterOfMassTransform().getBasis().getColumn(1);
67 	} else {
68 		rbAxisA2 = axisInA.cross(rbAxisA1);
69 		rbAxisA1 = rbAxisA2.cross(axisInA);
70 	}
71 
72 	m_rbAFrame.getBasis().setValue( rbAxisA1.getX(),rbAxisA2.getX(),axisInA.getX(),
73 									rbAxisA1.getY(),rbAxisA2.getY(),axisInA.getY(),
74 									rbAxisA1.getZ(),rbAxisA2.getZ(),axisInA.getZ() );
75 
76 	btQuaternion rotationArc = shortestArcQuat(axisInA,axisInB);
77 	btVector3 rbAxisB1 =  quatRotate(rotationArc,rbAxisA1);
78 	btVector3 rbAxisB2 =  axisInB.cross(rbAxisB1);
79 
80 	m_rbBFrame.getOrigin() = pivotInB;
81 	m_rbBFrame.getBasis().setValue( rbAxisB1.getX(),rbAxisB2.getX(),axisInB.getX(),
82 									rbAxisB1.getY(),rbAxisB2.getY(),axisInB.getY(),
83 									rbAxisB1.getZ(),rbAxisB2.getZ(),axisInB.getZ() );
84 
85 #ifndef	_BT_USE_CENTER_LIMIT_
86 	//start with free
87 	m_lowerLimit = btScalar(1.0f);
88 	m_upperLimit = btScalar(-1.0f);
89 	m_biasFactor = 0.3f;
90 	m_relaxationFactor = 1.0f;
91 	m_limitSoftness = 0.9f;
92 	m_solveLimit = false;
93 #endif
94 	m_referenceSign = m_useReferenceFrameA ? btScalar(-1.f) : btScalar(1.f);
95 }
96 
97 
98 
btHingeConstraint(btRigidBody & rbA,const btVector3 & pivotInA,const btVector3 & axisInA,bool useReferenceFrameA)99 btHingeConstraint::btHingeConstraint(btRigidBody& rbA,const btVector3& pivotInA,const btVector3& axisInA, bool useReferenceFrameA)
100 :btTypedConstraint(HINGE_CONSTRAINT_TYPE, rbA),
101 #ifdef _BT_USE_CENTER_LIMIT_
102 m_limit(),
103 #endif
104 m_angularOnly(false), m_enableAngularMotor(false),
105 m_useSolveConstraintObsolete(HINGE_USE_OBSOLETE_SOLVER),
106 m_useOffsetForConstraintFrame(HINGE_USE_FRAME_OFFSET),
107 m_useReferenceFrameA(useReferenceFrameA),
108 m_flags(0),
109 m_normalCFM(0),
110 m_normalERP(0),
111 m_stopCFM(0),
112 m_stopERP(0)
113 {
114 
115 	// since no frame is given, assume this to be zero angle and just pick rb transform axis
116 	// fixed axis in worldspace
117 	btVector3 rbAxisA1, rbAxisA2;
118 	btPlaneSpace1(axisInA, rbAxisA1, rbAxisA2);
119 
120 	m_rbAFrame.getOrigin() = pivotInA;
121 	m_rbAFrame.getBasis().setValue( rbAxisA1.getX(),rbAxisA2.getX(),axisInA.getX(),
122 									rbAxisA1.getY(),rbAxisA2.getY(),axisInA.getY(),
123 									rbAxisA1.getZ(),rbAxisA2.getZ(),axisInA.getZ() );
124 
125 	btVector3 axisInB = rbA.getCenterOfMassTransform().getBasis() * axisInA;
126 
127 	btQuaternion rotationArc = shortestArcQuat(axisInA,axisInB);
128 	btVector3 rbAxisB1 =  quatRotate(rotationArc,rbAxisA1);
129 	btVector3 rbAxisB2 = axisInB.cross(rbAxisB1);
130 
131 
132 	m_rbBFrame.getOrigin() = rbA.getCenterOfMassTransform()(pivotInA);
133 	m_rbBFrame.getBasis().setValue( rbAxisB1.getX(),rbAxisB2.getX(),axisInB.getX(),
134 									rbAxisB1.getY(),rbAxisB2.getY(),axisInB.getY(),
135 									rbAxisB1.getZ(),rbAxisB2.getZ(),axisInB.getZ() );
136 
137 #ifndef	_BT_USE_CENTER_LIMIT_
138 	//start with free
139 	m_lowerLimit = btScalar(1.0f);
140 	m_upperLimit = btScalar(-1.0f);
141 	m_biasFactor = 0.3f;
142 	m_relaxationFactor = 1.0f;
143 	m_limitSoftness = 0.9f;
144 	m_solveLimit = false;
145 #endif
146 	m_referenceSign = m_useReferenceFrameA ? btScalar(-1.f) : btScalar(1.f);
147 }
148 
149 
150 
btHingeConstraint(btRigidBody & rbA,btRigidBody & rbB,const btTransform & rbAFrame,const btTransform & rbBFrame,bool useReferenceFrameA)151 btHingeConstraint::btHingeConstraint(btRigidBody& rbA,btRigidBody& rbB,
152 								     const btTransform& rbAFrame, const btTransform& rbBFrame, bool useReferenceFrameA)
153 :btTypedConstraint(HINGE_CONSTRAINT_TYPE, rbA,rbB),m_rbAFrame(rbAFrame),m_rbBFrame(rbBFrame),
154 #ifdef _BT_USE_CENTER_LIMIT_
155 m_limit(),
156 #endif
157 m_angularOnly(false),
158 m_enableAngularMotor(false),
159 m_useSolveConstraintObsolete(HINGE_USE_OBSOLETE_SOLVER),
160 m_useOffsetForConstraintFrame(HINGE_USE_FRAME_OFFSET),
161 m_useReferenceFrameA(useReferenceFrameA),
162 m_flags(0),
163 m_normalCFM(0),
164 m_normalERP(0),
165 m_stopCFM(0),
166 m_stopERP(0)
167 {
168 #ifndef	_BT_USE_CENTER_LIMIT_
169 	//start with free
170 	m_lowerLimit = btScalar(1.0f);
171 	m_upperLimit = btScalar(-1.0f);
172 	m_biasFactor = 0.3f;
173 	m_relaxationFactor = 1.0f;
174 	m_limitSoftness = 0.9f;
175 	m_solveLimit = false;
176 #endif
177 	m_referenceSign = m_useReferenceFrameA ? btScalar(-1.f) : btScalar(1.f);
178 }
179 
180 
181 
btHingeConstraint(btRigidBody & rbA,const btTransform & rbAFrame,bool useReferenceFrameA)182 btHingeConstraint::btHingeConstraint(btRigidBody& rbA, const btTransform& rbAFrame, bool useReferenceFrameA)
183 :btTypedConstraint(HINGE_CONSTRAINT_TYPE, rbA),m_rbAFrame(rbAFrame),m_rbBFrame(rbAFrame),
184 #ifdef _BT_USE_CENTER_LIMIT_
185 m_limit(),
186 #endif
187 m_angularOnly(false),
188 m_enableAngularMotor(false),
189 m_useSolveConstraintObsolete(HINGE_USE_OBSOLETE_SOLVER),
190 m_useOffsetForConstraintFrame(HINGE_USE_FRAME_OFFSET),
191 m_useReferenceFrameA(useReferenceFrameA),
192 m_flags(0),
193 m_normalCFM(0),
194 m_normalERP(0),
195 m_stopCFM(0),
196 m_stopERP(0)
197 {
198 	///not providing rigidbody B means implicitly using worldspace for body B
199 
200 	m_rbBFrame.getOrigin() = m_rbA.getCenterOfMassTransform()(m_rbAFrame.getOrigin());
201 #ifndef	_BT_USE_CENTER_LIMIT_
202 	//start with free
203 	m_lowerLimit = btScalar(1.0f);
204 	m_upperLimit = btScalar(-1.0f);
205 	m_biasFactor = 0.3f;
206 	m_relaxationFactor = 1.0f;
207 	m_limitSoftness = 0.9f;
208 	m_solveLimit = false;
209 #endif
210 	m_referenceSign = m_useReferenceFrameA ? btScalar(-1.f) : btScalar(1.f);
211 }
212 
213 
214 
buildJacobian()215 void	btHingeConstraint::buildJacobian()
216 {
217 	if (m_useSolveConstraintObsolete)
218 	{
219 		m_appliedImpulse = btScalar(0.);
220 		m_accMotorImpulse = btScalar(0.);
221 
222 		if (!m_angularOnly)
223 		{
224 			btVector3 pivotAInW = m_rbA.getCenterOfMassTransform()*m_rbAFrame.getOrigin();
225 			btVector3 pivotBInW = m_rbB.getCenterOfMassTransform()*m_rbBFrame.getOrigin();
226 			btVector3 relPos = pivotBInW - pivotAInW;
227 
228 			btVector3 normal[3];
229 			if (relPos.length2() > SIMD_EPSILON)
230 			{
231 				normal[0] = relPos.normalized();
232 			}
233 			else
234 			{
235 				normal[0].setValue(btScalar(1.0),0,0);
236 			}
237 
238 			btPlaneSpace1(normal[0], normal[1], normal[2]);
239 
240 			for (int i=0;i<3;i++)
241 			{
242 				new (&m_jac[i]) btJacobianEntry(
243 				m_rbA.getCenterOfMassTransform().getBasis().transpose(),
244 				m_rbB.getCenterOfMassTransform().getBasis().transpose(),
245 				pivotAInW - m_rbA.getCenterOfMassPosition(),
246 				pivotBInW - m_rbB.getCenterOfMassPosition(),
247 				normal[i],
248 				m_rbA.getInvInertiaDiagLocal(),
249 				m_rbA.getInvMass(),
250 				m_rbB.getInvInertiaDiagLocal(),
251 				m_rbB.getInvMass());
252 			}
253 		}
254 
255 		//calculate two perpendicular jointAxis, orthogonal to hingeAxis
256 		//these two jointAxis require equal angular velocities for both bodies
257 
258 		//this is unused for now, it's a todo
259 		btVector3 jointAxis0local;
260 		btVector3 jointAxis1local;
261 
262 		btPlaneSpace1(m_rbAFrame.getBasis().getColumn(2),jointAxis0local,jointAxis1local);
263 
264 		btVector3 jointAxis0 = getRigidBodyA().getCenterOfMassTransform().getBasis() * jointAxis0local;
265 		btVector3 jointAxis1 = getRigidBodyA().getCenterOfMassTransform().getBasis() * jointAxis1local;
266 		btVector3 hingeAxisWorld = getRigidBodyA().getCenterOfMassTransform().getBasis() * m_rbAFrame.getBasis().getColumn(2);
267 
268 		new (&m_jacAng[0])	btJacobianEntry(jointAxis0,
269 			m_rbA.getCenterOfMassTransform().getBasis().transpose(),
270 			m_rbB.getCenterOfMassTransform().getBasis().transpose(),
271 			m_rbA.getInvInertiaDiagLocal(),
272 			m_rbB.getInvInertiaDiagLocal());
273 
274 		new (&m_jacAng[1])	btJacobianEntry(jointAxis1,
275 			m_rbA.getCenterOfMassTransform().getBasis().transpose(),
276 			m_rbB.getCenterOfMassTransform().getBasis().transpose(),
277 			m_rbA.getInvInertiaDiagLocal(),
278 			m_rbB.getInvInertiaDiagLocal());
279 
280 		new (&m_jacAng[2])	btJacobianEntry(hingeAxisWorld,
281 			m_rbA.getCenterOfMassTransform().getBasis().transpose(),
282 			m_rbB.getCenterOfMassTransform().getBasis().transpose(),
283 			m_rbA.getInvInertiaDiagLocal(),
284 			m_rbB.getInvInertiaDiagLocal());
285 
286 			// clear accumulator
287 			m_accLimitImpulse = btScalar(0.);
288 
289 			// test angular limit
290 			testLimit(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform());
291 
292 		//Compute K = J*W*J' for hinge axis
293 		btVector3 axisA =  getRigidBodyA().getCenterOfMassTransform().getBasis() *  m_rbAFrame.getBasis().getColumn(2);
294 		m_kHinge =   1.0f / (getRigidBodyA().computeAngularImpulseDenominator(axisA) +
295 							 getRigidBodyB().computeAngularImpulseDenominator(axisA));
296 
297 	}
298 }
299 
300 
301 #endif //__SPU__
302 
303 
btNormalizeAnglePositive(btScalar angle)304 static inline btScalar btNormalizeAnglePositive(btScalar angle)
305 {
306   return btFmod(btFmod(angle, btScalar(2.0*SIMD_PI)) + btScalar(2.0*SIMD_PI), btScalar(2.0*SIMD_PI));
307 }
308 
309 
310 
btShortestAngularDistance(btScalar accAngle,btScalar curAngle)311 static btScalar btShortestAngularDistance(btScalar accAngle, btScalar curAngle)
312 {
313 	btScalar result = btNormalizeAngle(btNormalizeAnglePositive(btNormalizeAnglePositive(curAngle) -
314 	btNormalizeAnglePositive(accAngle)));
315 	return result;
316 }
317 
btShortestAngleUpdate(btScalar accAngle,btScalar curAngle)318 static btScalar btShortestAngleUpdate(btScalar accAngle, btScalar curAngle)
319 {
320 	btScalar tol(0.3);
321 	btScalar result = btShortestAngularDistance(accAngle, curAngle);
322 
323 	  if (btFabs(result) > tol)
324 		return curAngle;
325 	  else
326 		return accAngle + result;
327 
328 	return curAngle;
329 }
330 
331 
getAccumulatedHingeAngle()332 btScalar btHingeAccumulatedAngleConstraint::getAccumulatedHingeAngle()
333 {
334 	btScalar hingeAngle = getHingeAngle();
335 	m_accumulatedAngle = btShortestAngleUpdate(m_accumulatedAngle,hingeAngle);
336 	return m_accumulatedAngle;
337 }
setAccumulatedHingeAngle(btScalar accAngle)338 void	btHingeAccumulatedAngleConstraint::setAccumulatedHingeAngle(btScalar accAngle)
339 {
340 	m_accumulatedAngle  = accAngle;
341 }
342 
getInfo1(btConstraintInfo1 * info)343 void btHingeAccumulatedAngleConstraint::getInfo1(btConstraintInfo1* info)
344 {
345 	//update m_accumulatedAngle
346 	btScalar curHingeAngle = getHingeAngle();
347 	m_accumulatedAngle = btShortestAngleUpdate(m_accumulatedAngle,curHingeAngle);
348 
349 	btHingeConstraint::getInfo1(info);
350 
351 }
352 
353 
getInfo1(btConstraintInfo1 * info)354 void btHingeConstraint::getInfo1(btConstraintInfo1* info)
355 {
356 
357 
358 	if (m_useSolveConstraintObsolete)
359 	{
360 		info->m_numConstraintRows = 0;
361 		info->nub = 0;
362 	}
363 	else
364 	{
365 		info->m_numConstraintRows = 5; // Fixed 3 linear + 2 angular
366 		info->nub = 1;
367 		//always add the row, to avoid computation (data is not available yet)
368 		//prepare constraint
369 		testLimit(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform());
370 		if(getSolveLimit() || getEnableAngularMotor())
371 		{
372 			info->m_numConstraintRows++; // limit 3rd anguar as well
373 			info->nub--;
374 		}
375 
376 	}
377 }
378 
getInfo1NonVirtual(btConstraintInfo1 * info)379 void btHingeConstraint::getInfo1NonVirtual(btConstraintInfo1* info)
380 {
381 	if (m_useSolveConstraintObsolete)
382 	{
383 		info->m_numConstraintRows = 0;
384 		info->nub = 0;
385 	}
386 	else
387 	{
388 		//always add the 'limit' row, to avoid computation (data is not available yet)
389 		info->m_numConstraintRows = 6; // Fixed 3 linear + 2 angular
390 		info->nub = 0;
391 	}
392 }
393 
getInfo2(btConstraintInfo2 * info)394 void btHingeConstraint::getInfo2 (btConstraintInfo2* info)
395 {
396 	if(m_useOffsetForConstraintFrame)
397 	{
398 		getInfo2InternalUsingFrameOffset(info, m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform(),m_rbA.getAngularVelocity(),m_rbB.getAngularVelocity());
399 	}
400 	else
401 	{
402 		getInfo2Internal(info, m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform(),m_rbA.getAngularVelocity(),m_rbB.getAngularVelocity());
403 	}
404 }
405 
406 
getInfo2NonVirtual(btConstraintInfo2 * info,const btTransform & transA,const btTransform & transB,const btVector3 & angVelA,const btVector3 & angVelB)407 void	btHingeConstraint::getInfo2NonVirtual (btConstraintInfo2* info,const btTransform& transA,const btTransform& transB,const btVector3& angVelA,const btVector3& angVelB)
408 {
409 	///the regular (virtual) implementation getInfo2 already performs 'testLimit' during getInfo1, so we need to do it now
410 	testLimit(transA,transB);
411 
412 	getInfo2Internal(info,transA,transB,angVelA,angVelB);
413 }
414 
415 
getInfo2Internal(btConstraintInfo2 * info,const btTransform & transA,const btTransform & transB,const btVector3 & angVelA,const btVector3 & angVelB)416 void btHingeConstraint::getInfo2Internal(btConstraintInfo2* info, const btTransform& transA,const btTransform& transB,const btVector3& angVelA,const btVector3& angVelB)
417 {
418 
419 	btAssert(!m_useSolveConstraintObsolete);
420 	int i, skip = info->rowskip;
421 	// transforms in world space
422 	btTransform trA = transA*m_rbAFrame;
423 	btTransform trB = transB*m_rbBFrame;
424 	// pivot point
425 	btVector3 pivotAInW = trA.getOrigin();
426 	btVector3 pivotBInW = trB.getOrigin();
427 #if 0
428 	if (0)
429 	{
430 		for (i=0;i<6;i++)
431 		{
432 			info->m_J1linearAxis[i*skip]=0;
433 			info->m_J1linearAxis[i*skip+1]=0;
434 			info->m_J1linearAxis[i*skip+2]=0;
435 
436 			info->m_J1angularAxis[i*skip]=0;
437 			info->m_J1angularAxis[i*skip+1]=0;
438 			info->m_J1angularAxis[i*skip+2]=0;
439 
440 			info->m_J2linearAxis[i*skip]=0;
441 			info->m_J2linearAxis[i*skip+1]=0;
442 			info->m_J2linearAxis[i*skip+2]=0;
443 
444 			info->m_J2angularAxis[i*skip]=0;
445 			info->m_J2angularAxis[i*skip+1]=0;
446 			info->m_J2angularAxis[i*skip+2]=0;
447 
448 			info->m_constraintError[i*skip]=0.f;
449 		}
450 	}
451 #endif //#if 0
452 	// linear (all fixed)
453 
454 	if (!m_angularOnly)
455 	{
456 		info->m_J1linearAxis[0] = 1;
457 		info->m_J1linearAxis[skip + 1] = 1;
458 		info->m_J1linearAxis[2 * skip + 2] = 1;
459 
460 		info->m_J2linearAxis[0] = -1;
461 		info->m_J2linearAxis[skip + 1] = -1;
462 		info->m_J2linearAxis[2 * skip + 2] = -1;
463 	}
464 
465 
466 
467 
468 	btVector3 a1 = pivotAInW - transA.getOrigin();
469 	{
470 		btVector3* angular0 = (btVector3*)(info->m_J1angularAxis);
471 		btVector3* angular1 = (btVector3*)(info->m_J1angularAxis + skip);
472 		btVector3* angular2 = (btVector3*)(info->m_J1angularAxis + 2 * skip);
473 		btVector3 a1neg = -a1;
474 		a1neg.getSkewSymmetricMatrix(angular0,angular1,angular2);
475 	}
476 	btVector3 a2 = pivotBInW - transB.getOrigin();
477 	{
478 		btVector3* angular0 = (btVector3*)(info->m_J2angularAxis);
479 		btVector3* angular1 = (btVector3*)(info->m_J2angularAxis + skip);
480 		btVector3* angular2 = (btVector3*)(info->m_J2angularAxis + 2 * skip);
481 		a2.getSkewSymmetricMatrix(angular0,angular1,angular2);
482 	}
483 	// linear RHS
484 	btScalar normalErp = (m_flags & BT_HINGE_FLAGS_ERP_NORM) ? m_normalERP : info->erp;
485 
486     btScalar k = info->fps * normalErp;
487 	if (!m_angularOnly)
488 	{
489 		for(i = 0; i < 3; i++)
490 		{
491 			info->m_constraintError[i * skip] = k * (pivotBInW[i] - pivotAInW[i]);
492 		}
493 	}
494 	// make rotations around X and Y equal
495 	// the hinge axis should be the only unconstrained
496 	// rotational axis, the angular velocity of the two bodies perpendicular to
497 	// the hinge axis should be equal. thus the constraint equations are
498 	//    p*w1 - p*w2 = 0
499 	//    q*w1 - q*w2 = 0
500 	// where p and q are unit vectors normal to the hinge axis, and w1 and w2
501 	// are the angular velocity vectors of the two bodies.
502 	// get hinge axis (Z)
503 	btVector3 ax1 = trA.getBasis().getColumn(2);
504 	// get 2 orthos to hinge axis (X, Y)
505 	btVector3 p = trA.getBasis().getColumn(0);
506 	btVector3 q = trA.getBasis().getColumn(1);
507 	// set the two hinge angular rows
508     int s3 = 3 * info->rowskip;
509     int s4 = 4 * info->rowskip;
510 
511 	info->m_J1angularAxis[s3 + 0] = p[0];
512 	info->m_J1angularAxis[s3 + 1] = p[1];
513 	info->m_J1angularAxis[s3 + 2] = p[2];
514 	info->m_J1angularAxis[s4 + 0] = q[0];
515 	info->m_J1angularAxis[s4 + 1] = q[1];
516 	info->m_J1angularAxis[s4 + 2] = q[2];
517 
518 	info->m_J2angularAxis[s3 + 0] = -p[0];
519 	info->m_J2angularAxis[s3 + 1] = -p[1];
520 	info->m_J2angularAxis[s3 + 2] = -p[2];
521 	info->m_J2angularAxis[s4 + 0] = -q[0];
522 	info->m_J2angularAxis[s4 + 1] = -q[1];
523 	info->m_J2angularAxis[s4 + 2] = -q[2];
524     // compute the right hand side of the constraint equation. set relative
525     // body velocities along p and q to bring the hinge back into alignment.
526     // if ax1,ax2 are the unit length hinge axes as computed from body1 and
527     // body2, we need to rotate both bodies along the axis u = (ax1 x ax2).
528     // if `theta' is the angle between ax1 and ax2, we need an angular velocity
529     // along u to cover angle erp*theta in one step :
530     //   |angular_velocity| = angle/time = erp*theta / stepsize
531     //                      = (erp*fps) * theta
532     //    angular_velocity  = |angular_velocity| * (ax1 x ax2) / |ax1 x ax2|
533     //                      = (erp*fps) * theta * (ax1 x ax2) / sin(theta)
534     // ...as ax1 and ax2 are unit length. if theta is smallish,
535     // theta ~= sin(theta), so
536     //    angular_velocity  = (erp*fps) * (ax1 x ax2)
537     // ax1 x ax2 is in the plane space of ax1, so we project the angular
538     // velocity to p and q to find the right hand side.
539     btVector3 ax2 = trB.getBasis().getColumn(2);
540 	btVector3 u = ax1.cross(ax2);
541 	info->m_constraintError[s3] = k * u.dot(p);
542 	info->m_constraintError[s4] = k * u.dot(q);
543 	// check angular limits
544 	int nrow = 4; // last filled row
545 	int srow;
546 	btScalar limit_err = btScalar(0.0);
547 	int limit = 0;
548 	if(getSolveLimit())
549 	{
550 #ifdef	_BT_USE_CENTER_LIMIT_
551 	limit_err = m_limit.getCorrection() * m_referenceSign;
552 #else
553 	limit_err = m_correction * m_referenceSign;
554 #endif
555 	limit = (limit_err > btScalar(0.0)) ? 1 : 2;
556 
557 	}
558 	// if the hinge has joint limits or motor, add in the extra row
559 	int powered = 0;
560 	if(getEnableAngularMotor())
561 	{
562 		powered = 1;
563 	}
564 	if(limit || powered)
565 	{
566 		nrow++;
567 		srow = nrow * info->rowskip;
568 		info->m_J1angularAxis[srow+0] = ax1[0];
569 		info->m_J1angularAxis[srow+1] = ax1[1];
570 		info->m_J1angularAxis[srow+2] = ax1[2];
571 
572 		info->m_J2angularAxis[srow+0] = -ax1[0];
573 		info->m_J2angularAxis[srow+1] = -ax1[1];
574 		info->m_J2angularAxis[srow+2] = -ax1[2];
575 
576 		btScalar lostop = getLowerLimit();
577 		btScalar histop = getUpperLimit();
578 		if(limit && (lostop == histop))
579 		{  // the joint motor is ineffective
580 			powered = 0;
581 		}
582 		info->m_constraintError[srow] = btScalar(0.0f);
583 		btScalar currERP = (m_flags & BT_HINGE_FLAGS_ERP_STOP) ? m_stopERP : normalErp;
584 		if(powered)
585 		{
586 			if(m_flags & BT_HINGE_FLAGS_CFM_NORM)
587 			{
588 				info->cfm[srow] = m_normalCFM;
589 			}
590 			btScalar mot_fact = getMotorFactor(m_hingeAngle, lostop, histop, m_motorTargetVelocity, info->fps * currERP);
591 			info->m_constraintError[srow] += mot_fact * m_motorTargetVelocity * m_referenceSign;
592 			info->m_lowerLimit[srow] = - m_maxMotorImpulse;
593 			info->m_upperLimit[srow] =   m_maxMotorImpulse;
594 		}
595 		if(limit)
596 		{
597 			k = info->fps * currERP;
598 			info->m_constraintError[srow] += k * limit_err;
599 			if(m_flags & BT_HINGE_FLAGS_CFM_STOP)
600 			{
601 				info->cfm[srow] = m_stopCFM;
602 			}
603 			if(lostop == histop)
604 			{
605 				// limited low and high simultaneously
606 				info->m_lowerLimit[srow] = -SIMD_INFINITY;
607 				info->m_upperLimit[srow] = SIMD_INFINITY;
608 			}
609 			else if(limit == 1)
610 			{ // low limit
611 				info->m_lowerLimit[srow] = 0;
612 				info->m_upperLimit[srow] = SIMD_INFINITY;
613 			}
614 			else
615 			{ // high limit
616 				info->m_lowerLimit[srow] = -SIMD_INFINITY;
617 				info->m_upperLimit[srow] = 0;
618 			}
619 			// bounce (we'll use slider parameter abs(1.0 - m_dampingLimAng) for that)
620 #ifdef	_BT_USE_CENTER_LIMIT_
621 			btScalar bounce = m_limit.getRelaxationFactor();
622 #else
623 			btScalar bounce = m_relaxationFactor;
624 #endif
625 			if(bounce > btScalar(0.0))
626 			{
627 				btScalar vel = angVelA.dot(ax1);
628 				vel -= angVelB.dot(ax1);
629 				// only apply bounce if the velocity is incoming, and if the
630 				// resulting c[] exceeds what we already have.
631 				if(limit == 1)
632 				{	// low limit
633 					if(vel < 0)
634 					{
635 						btScalar newc = -bounce * vel;
636 						if(newc > info->m_constraintError[srow])
637 						{
638 							info->m_constraintError[srow] = newc;
639 						}
640 					}
641 				}
642 				else
643 				{	// high limit - all those computations are reversed
644 					if(vel > 0)
645 					{
646 						btScalar newc = -bounce * vel;
647 						if(newc < info->m_constraintError[srow])
648 						{
649 							info->m_constraintError[srow] = newc;
650 						}
651 					}
652 				}
653 			}
654 #ifdef	_BT_USE_CENTER_LIMIT_
655 			info->m_constraintError[srow] *= m_limit.getBiasFactor();
656 #else
657 			info->m_constraintError[srow] *= m_biasFactor;
658 #endif
659 		} // if(limit)
660 	} // if angular limit or powered
661 }
662 
663 
setFrames(const btTransform & frameA,const btTransform & frameB)664 void btHingeConstraint::setFrames(const btTransform & frameA, const btTransform & frameB)
665 {
666 	m_rbAFrame = frameA;
667 	m_rbBFrame = frameB;
668 	buildJacobian();
669 }
670 
671 
updateRHS(btScalar timeStep)672 void	btHingeConstraint::updateRHS(btScalar	timeStep)
673 {
674 	(void)timeStep;
675 
676 }
677 
678 
679 
680 
getHingeAngle()681 btScalar btHingeConstraint::getHingeAngle()
682 {
683 	return getHingeAngle(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform());
684 }
685 
getHingeAngle(const btTransform & transA,const btTransform & transB)686 btScalar btHingeConstraint::getHingeAngle(const btTransform& transA,const btTransform& transB)
687 {
688 	const btVector3 refAxis0  = transA.getBasis() * m_rbAFrame.getBasis().getColumn(0);
689 	const btVector3 refAxis1  = transA.getBasis() * m_rbAFrame.getBasis().getColumn(1);
690 	const btVector3 swingAxis = transB.getBasis() * m_rbBFrame.getBasis().getColumn(1);
691 //	btScalar angle = btAtan2Fast(swingAxis.dot(refAxis0), swingAxis.dot(refAxis1));
692 	btScalar angle = btAtan2(swingAxis.dot(refAxis0), swingAxis.dot(refAxis1));
693 	return m_referenceSign * angle;
694 }
695 
696 
697 
testLimit(const btTransform & transA,const btTransform & transB)698 void btHingeConstraint::testLimit(const btTransform& transA,const btTransform& transB)
699 {
700 	// Compute limit information
701 	m_hingeAngle = getHingeAngle(transA,transB);
702 #ifdef	_BT_USE_CENTER_LIMIT_
703 	m_limit.test(m_hingeAngle);
704 #else
705 	m_correction = btScalar(0.);
706 	m_limitSign = btScalar(0.);
707 	m_solveLimit = false;
708 	if (m_lowerLimit <= m_upperLimit)
709 	{
710 		m_hingeAngle = btAdjustAngleToLimits(m_hingeAngle, m_lowerLimit, m_upperLimit);
711 		if (m_hingeAngle <= m_lowerLimit)
712 		{
713 			m_correction = (m_lowerLimit - m_hingeAngle);
714 			m_limitSign = 1.0f;
715 			m_solveLimit = true;
716 		}
717 		else if (m_hingeAngle >= m_upperLimit)
718 		{
719 			m_correction = m_upperLimit - m_hingeAngle;
720 			m_limitSign = -1.0f;
721 			m_solveLimit = true;
722 		}
723 	}
724 #endif
725 	return;
726 }
727 
728 
729 static btVector3 vHinge(0, 0, btScalar(1));
730 
setMotorTarget(const btQuaternion & qAinB,btScalar dt)731 void btHingeConstraint::setMotorTarget(const btQuaternion& qAinB, btScalar dt)
732 {
733 	// convert target from body to constraint space
734 	btQuaternion qConstraint = m_rbBFrame.getRotation().inverse() * qAinB * m_rbAFrame.getRotation();
735 	qConstraint.normalize();
736 
737 	// extract "pure" hinge component
738 	btVector3 vNoHinge = quatRotate(qConstraint, vHinge); vNoHinge.normalize();
739 	btQuaternion qNoHinge = shortestArcQuat(vHinge, vNoHinge);
740 	btQuaternion qHinge = qNoHinge.inverse() * qConstraint;
741 	qHinge.normalize();
742 
743 	// compute angular target, clamped to limits
744 	btScalar targetAngle = qHinge.getAngle();
745 	if (targetAngle > SIMD_PI) // long way around. flip quat and recalculate.
746 	{
747 		qHinge = -(qHinge);
748 		targetAngle = qHinge.getAngle();
749 	}
750 	if (qHinge.getZ() < 0)
751 		targetAngle = -targetAngle;
752 
753 	setMotorTarget(targetAngle, dt);
754 }
755 
setMotorTarget(btScalar targetAngle,btScalar dt)756 void btHingeConstraint::setMotorTarget(btScalar targetAngle, btScalar dt)
757 {
758 #ifdef	_BT_USE_CENTER_LIMIT_
759 	m_limit.fit(targetAngle);
760 #else
761 	if (m_lowerLimit < m_upperLimit)
762 	{
763 		if (targetAngle < m_lowerLimit)
764 			targetAngle = m_lowerLimit;
765 		else if (targetAngle > m_upperLimit)
766 			targetAngle = m_upperLimit;
767 	}
768 #endif
769 	// compute angular velocity
770 	btScalar curAngle  = getHingeAngle(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform());
771 	btScalar dAngle = targetAngle - curAngle;
772 	m_motorTargetVelocity = dAngle / dt;
773 }
774 
775 
776 
getInfo2InternalUsingFrameOffset(btConstraintInfo2 * info,const btTransform & transA,const btTransform & transB,const btVector3 & angVelA,const btVector3 & angVelB)777 void btHingeConstraint::getInfo2InternalUsingFrameOffset(btConstraintInfo2* info, const btTransform& transA,const btTransform& transB,const btVector3& angVelA,const btVector3& angVelB)
778 {
779 	btAssert(!m_useSolveConstraintObsolete);
780 	int i, s = info->rowskip;
781 	// transforms in world space
782 	btTransform trA = transA*m_rbAFrame;
783 	btTransform trB = transB*m_rbBFrame;
784 	// pivot point
785 //	btVector3 pivotAInW = trA.getOrigin();
786 //	btVector3 pivotBInW = trB.getOrigin();
787 #if 1
788 	// difference between frames in WCS
789 	btVector3 ofs = trB.getOrigin() - trA.getOrigin();
790 	// now get weight factors depending on masses
791 	btScalar miA = getRigidBodyA().getInvMass();
792 	btScalar miB = getRigidBodyB().getInvMass();
793 	bool hasStaticBody = (miA < SIMD_EPSILON) || (miB < SIMD_EPSILON);
794 	btScalar miS = miA + miB;
795 	btScalar factA, factB;
796 	if(miS > btScalar(0.f))
797 	{
798 		factA = miB / miS;
799 	}
800 	else
801 	{
802 		factA = btScalar(0.5f);
803 	}
804 	factB = btScalar(1.0f) - factA;
805 	// get the desired direction of hinge axis
806 	// as weighted sum of Z-orthos of frameA and frameB in WCS
807 	btVector3 ax1A = trA.getBasis().getColumn(2);
808 	btVector3 ax1B = trB.getBasis().getColumn(2);
809 	btVector3 ax1 = ax1A * factA + ax1B * factB;
810 	ax1.normalize();
811 	// fill first 3 rows
812 	// we want: velA + wA x relA == velB + wB x relB
813 	btTransform bodyA_trans = transA;
814 	btTransform bodyB_trans = transB;
815 	int s0 = 0;
816 	int s1 = s;
817 	int s2 = s * 2;
818 	int nrow = 2; // last filled row
819 	btVector3 tmpA, tmpB, relA, relB, p, q;
820 	// get vector from bodyB to frameB in WCS
821 	relB = trB.getOrigin() - bodyB_trans.getOrigin();
822 	// get its projection to hinge axis
823 	btVector3 projB = ax1 * relB.dot(ax1);
824 	// get vector directed from bodyB to hinge axis (and orthogonal to it)
825 	btVector3 orthoB = relB - projB;
826 	// same for bodyA
827 	relA = trA.getOrigin() - bodyA_trans.getOrigin();
828 	btVector3 projA = ax1 * relA.dot(ax1);
829 	btVector3 orthoA = relA - projA;
830 	btVector3 totalDist = projA - projB;
831 	// get offset vectors relA and relB
832 	relA = orthoA + totalDist * factA;
833 	relB = orthoB - totalDist * factB;
834 	// now choose average ortho to hinge axis
835 	p = orthoB * factA + orthoA * factB;
836 	btScalar len2 = p.length2();
837 	if(len2 > SIMD_EPSILON)
838 	{
839 		p /= btSqrt(len2);
840 	}
841 	else
842 	{
843 		p = trA.getBasis().getColumn(1);
844 	}
845 	// make one more ortho
846 	q = ax1.cross(p);
847 	// fill three rows
848 	tmpA = relA.cross(p);
849 	tmpB = relB.cross(p);
850     for (i=0; i<3; i++) info->m_J1angularAxis[s0+i] = tmpA[i];
851     for (i=0; i<3; i++) info->m_J2angularAxis[s0+i] = -tmpB[i];
852 	tmpA = relA.cross(q);
853 	tmpB = relB.cross(q);
854 	if(hasStaticBody && getSolveLimit())
855 	{ // to make constraint between static and dynamic objects more rigid
856 		// remove wA (or wB) from equation if angular limit is hit
857 		tmpB *= factB;
858 		tmpA *= factA;
859 	}
860 	for (i=0; i<3; i++) info->m_J1angularAxis[s1+i] = tmpA[i];
861     for (i=0; i<3; i++) info->m_J2angularAxis[s1+i] = -tmpB[i];
862 	tmpA = relA.cross(ax1);
863 	tmpB = relB.cross(ax1);
864 	if(hasStaticBody)
865 	{ // to make constraint between static and dynamic objects more rigid
866 		// remove wA (or wB) from equation
867 		tmpB *= factB;
868 		tmpA *= factA;
869 	}
870 	for (i=0; i<3; i++) info->m_J1angularAxis[s2+i] = tmpA[i];
871     for (i=0; i<3; i++) info->m_J2angularAxis[s2+i] = -tmpB[i];
872 
873 	btScalar normalErp = (m_flags & BT_HINGE_FLAGS_ERP_NORM)? m_normalERP : info->erp;
874 	btScalar k = info->fps * normalErp;
875 
876 	if (!m_angularOnly)
877 	{
878 		for (i=0; i<3; i++) info->m_J1linearAxis[s0+i] = p[i];
879 		for (i=0; i<3; i++) info->m_J1linearAxis[s1+i] = q[i];
880 		for (i=0; i<3; i++) info->m_J1linearAxis[s2+i] = ax1[i];
881 
882 		for (i=0; i<3; i++) info->m_J2linearAxis[s0+i] = -p[i];
883 		for (i=0; i<3; i++) info->m_J2linearAxis[s1+i] = -q[i];
884 		for (i=0; i<3; i++) info->m_J2linearAxis[s2+i] = -ax1[i];
885 
886 	// compute three elements of right hand side
887 
888 		btScalar rhs = k * p.dot(ofs);
889 		info->m_constraintError[s0] = rhs;
890 		rhs = k * q.dot(ofs);
891 		info->m_constraintError[s1] = rhs;
892 		rhs = k * ax1.dot(ofs);
893 		info->m_constraintError[s2] = rhs;
894 	}
895 	// the hinge axis should be the only unconstrained
896 	// rotational axis, the angular velocity of the two bodies perpendicular to
897 	// the hinge axis should be equal. thus the constraint equations are
898 	//    p*w1 - p*w2 = 0
899 	//    q*w1 - q*w2 = 0
900 	// where p and q are unit vectors normal to the hinge axis, and w1 and w2
901 	// are the angular velocity vectors of the two bodies.
902 	int s3 = 3 * s;
903 	int s4 = 4 * s;
904 	info->m_J1angularAxis[s3 + 0] = p[0];
905 	info->m_J1angularAxis[s3 + 1] = p[1];
906 	info->m_J1angularAxis[s3 + 2] = p[2];
907 	info->m_J1angularAxis[s4 + 0] = q[0];
908 	info->m_J1angularAxis[s4 + 1] = q[1];
909 	info->m_J1angularAxis[s4 + 2] = q[2];
910 
911 	info->m_J2angularAxis[s3 + 0] = -p[0];
912 	info->m_J2angularAxis[s3 + 1] = -p[1];
913 	info->m_J2angularAxis[s3 + 2] = -p[2];
914 	info->m_J2angularAxis[s4 + 0] = -q[0];
915 	info->m_J2angularAxis[s4 + 1] = -q[1];
916 	info->m_J2angularAxis[s4 + 2] = -q[2];
917 	// compute the right hand side of the constraint equation. set relative
918 	// body velocities along p and q to bring the hinge back into alignment.
919 	// if ax1A,ax1B are the unit length hinge axes as computed from bodyA and
920 	// bodyB, we need to rotate both bodies along the axis u = (ax1 x ax2).
921 	// if "theta" is the angle between ax1 and ax2, we need an angular velocity
922 	// along u to cover angle erp*theta in one step :
923 	//   |angular_velocity| = angle/time = erp*theta / stepsize
924 	//                      = (erp*fps) * theta
925 	//    angular_velocity  = |angular_velocity| * (ax1 x ax2) / |ax1 x ax2|
926 	//                      = (erp*fps) * theta * (ax1 x ax2) / sin(theta)
927 	// ...as ax1 and ax2 are unit length. if theta is smallish,
928 	// theta ~= sin(theta), so
929 	//    angular_velocity  = (erp*fps) * (ax1 x ax2)
930 	// ax1 x ax2 is in the plane space of ax1, so we project the angular
931 	// velocity to p and q to find the right hand side.
932 	k = info->fps * normalErp;//??
933 
934 	btVector3 u = ax1A.cross(ax1B);
935 	info->m_constraintError[s3] = k * u.dot(p);
936 	info->m_constraintError[s4] = k * u.dot(q);
937 #endif
938 	// check angular limits
939 	nrow = 4; // last filled row
940 	int srow;
941 	btScalar limit_err = btScalar(0.0);
942 	int limit = 0;
943 	if(getSolveLimit())
944 	{
945 #ifdef	_BT_USE_CENTER_LIMIT_
946 	limit_err = m_limit.getCorrection() * m_referenceSign;
947 #else
948 	limit_err = m_correction * m_referenceSign;
949 #endif
950 	limit = (limit_err > btScalar(0.0)) ? 1 : 2;
951 
952 	}
953 	// if the hinge has joint limits or motor, add in the extra row
954 	int powered = 0;
955 	if(getEnableAngularMotor())
956 	{
957 		powered = 1;
958 	}
959 	if(limit || powered)
960 	{
961 		nrow++;
962 		srow = nrow * info->rowskip;
963 		info->m_J1angularAxis[srow+0] = ax1[0];
964 		info->m_J1angularAxis[srow+1] = ax1[1];
965 		info->m_J1angularAxis[srow+2] = ax1[2];
966 
967 		info->m_J2angularAxis[srow+0] = -ax1[0];
968 		info->m_J2angularAxis[srow+1] = -ax1[1];
969 		info->m_J2angularAxis[srow+2] = -ax1[2];
970 
971 		btScalar lostop = getLowerLimit();
972 		btScalar histop = getUpperLimit();
973 		if(limit && (lostop == histop))
974 		{  // the joint motor is ineffective
975 			powered = 0;
976 		}
977 		info->m_constraintError[srow] = btScalar(0.0f);
978 		btScalar currERP = (m_flags & BT_HINGE_FLAGS_ERP_STOP) ? m_stopERP : normalErp;
979 		if(powered)
980 		{
981 			if(m_flags & BT_HINGE_FLAGS_CFM_NORM)
982 			{
983 				info->cfm[srow] = m_normalCFM;
984 			}
985 			btScalar mot_fact = getMotorFactor(m_hingeAngle, lostop, histop, m_motorTargetVelocity, info->fps * currERP);
986 			info->m_constraintError[srow] += mot_fact * m_motorTargetVelocity * m_referenceSign;
987 			info->m_lowerLimit[srow] = - m_maxMotorImpulse;
988 			info->m_upperLimit[srow] =   m_maxMotorImpulse;
989 		}
990 		if(limit)
991 		{
992 			k = info->fps * currERP;
993 			info->m_constraintError[srow] += k * limit_err;
994 			if(m_flags & BT_HINGE_FLAGS_CFM_STOP)
995 			{
996 				info->cfm[srow] = m_stopCFM;
997 			}
998 			if(lostop == histop)
999 			{
1000 				// limited low and high simultaneously
1001 				info->m_lowerLimit[srow] = -SIMD_INFINITY;
1002 				info->m_upperLimit[srow] = SIMD_INFINITY;
1003 			}
1004 			else if(limit == 1)
1005 			{ // low limit
1006 				info->m_lowerLimit[srow] = 0;
1007 				info->m_upperLimit[srow] = SIMD_INFINITY;
1008 			}
1009 			else
1010 			{ // high limit
1011 				info->m_lowerLimit[srow] = -SIMD_INFINITY;
1012 				info->m_upperLimit[srow] = 0;
1013 			}
1014 			// bounce (we'll use slider parameter abs(1.0 - m_dampingLimAng) for that)
1015 #ifdef	_BT_USE_CENTER_LIMIT_
1016 			btScalar bounce = m_limit.getRelaxationFactor();
1017 #else
1018 			btScalar bounce = m_relaxationFactor;
1019 #endif
1020 			if(bounce > btScalar(0.0))
1021 			{
1022 				btScalar vel = angVelA.dot(ax1);
1023 				vel -= angVelB.dot(ax1);
1024 				// only apply bounce if the velocity is incoming, and if the
1025 				// resulting c[] exceeds what we already have.
1026 				if(limit == 1)
1027 				{	// low limit
1028 					if(vel < 0)
1029 					{
1030 						btScalar newc = -bounce * vel;
1031 						if(newc > info->m_constraintError[srow])
1032 						{
1033 							info->m_constraintError[srow] = newc;
1034 						}
1035 					}
1036 				}
1037 				else
1038 				{	// high limit - all those computations are reversed
1039 					if(vel > 0)
1040 					{
1041 						btScalar newc = -bounce * vel;
1042 						if(newc < info->m_constraintError[srow])
1043 						{
1044 							info->m_constraintError[srow] = newc;
1045 						}
1046 					}
1047 				}
1048 			}
1049 #ifdef	_BT_USE_CENTER_LIMIT_
1050 			info->m_constraintError[srow] *= m_limit.getBiasFactor();
1051 #else
1052 			info->m_constraintError[srow] *= m_biasFactor;
1053 #endif
1054 		} // if(limit)
1055 	} // if angular limit or powered
1056 }
1057 
1058 
1059 ///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5).
1060 ///If no axis is provided, it uses the default axis for this constraint.
setParam(int num,btScalar value,int axis)1061 void btHingeConstraint::setParam(int num, btScalar value, int axis)
1062 {
1063 	if((axis == -1) || (axis == 5))
1064 	{
1065 		switch(num)
1066 		{
1067 			case BT_CONSTRAINT_STOP_ERP :
1068 				m_stopERP = value;
1069 				m_flags |= BT_HINGE_FLAGS_ERP_STOP;
1070 				break;
1071 			case BT_CONSTRAINT_STOP_CFM :
1072 				m_stopCFM = value;
1073 				m_flags |= BT_HINGE_FLAGS_CFM_STOP;
1074 				break;
1075 			case BT_CONSTRAINT_CFM :
1076 				m_normalCFM = value;
1077 				m_flags |= BT_HINGE_FLAGS_CFM_NORM;
1078 				break;
1079 			case BT_CONSTRAINT_ERP:
1080 				m_normalERP = value;
1081 				m_flags |= BT_HINGE_FLAGS_ERP_NORM;
1082 				break;
1083 			default :
1084 				btAssertConstrParams(0);
1085 		}
1086 	}
1087 	else
1088 	{
1089 		btAssertConstrParams(0);
1090 	}
1091 }
1092 
1093 ///return the local value of parameter
getParam(int num,int axis) const1094 btScalar btHingeConstraint::getParam(int num, int axis) const
1095 {
1096 	btScalar retVal = 0;
1097 	if((axis == -1) || (axis == 5))
1098 	{
1099 		switch(num)
1100 		{
1101 			case BT_CONSTRAINT_STOP_ERP :
1102 				btAssertConstrParams(m_flags & BT_HINGE_FLAGS_ERP_STOP);
1103 				retVal = m_stopERP;
1104 				break;
1105 			case BT_CONSTRAINT_STOP_CFM :
1106 				btAssertConstrParams(m_flags & BT_HINGE_FLAGS_CFM_STOP);
1107 				retVal = m_stopCFM;
1108 				break;
1109 			case BT_CONSTRAINT_CFM :
1110 				btAssertConstrParams(m_flags & BT_HINGE_FLAGS_CFM_NORM);
1111 				retVal = m_normalCFM;
1112 				break;
1113 			case BT_CONSTRAINT_ERP:
1114 				btAssertConstrParams(m_flags & BT_HINGE_FLAGS_ERP_NORM);
1115 				retVal = m_normalERP;
1116 				break;
1117 			default :
1118 				btAssertConstrParams(0);
1119 		}
1120 	}
1121 	else
1122 	{
1123 		btAssertConstrParams(0);
1124 	}
1125 	return retVal;
1126 }
1127 
1128 
1129