btGeneric6DofSpring2Constraint.cpp 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189
  1. /*
  2. Bullet Continuous Collision Detection and Physics Library
  3. Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
  4. This software is provided 'as-is', without any express or implied warranty.
  5. In no event will the authors be held liable for any damages arising from the use of this software.
  6. Permission is granted to anyone to use this software for any purpose,
  7. including commercial applications, and to alter it and redistribute it freely,
  8. subject to the following restrictions:
  9. 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.
  10. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  11. 3. This notice may not be removed or altered from any source distribution.
  12. */
  13. /*
  14. 2014 May: btGeneric6DofSpring2Constraint is created from the original (2.82.2712) btGeneric6DofConstraint by Gabor Puhr and Tamas Umenhoffer
  15. Pros:
  16. - Much more accurate and stable in a lot of situation. (Especially when a sleeping chain of RBs connected with 6dof2 is pulled)
  17. - Stable and accurate spring with minimal energy loss that works with all of the solvers. (latter is not true for the original 6dof spring)
  18. - Servo motor functionality
  19. - Much more accurate bouncing. 0 really means zero bouncing (not true for the original 6odf) and there is only a minimal energy loss when the value is 1 (because of the solvers' precision)
  20. - Rotation order for the Euler system can be set. (One axis' freedom is still limited to pi/2)
  21. Cons:
  22. - It is slower than the original 6dof. There is no exact ratio, but half speed is a good estimation. (with PGS)
  23. - At bouncing the correct velocity is calculated, but not the correct position. (it is because of the solver can correct position or velocity, but not both.)
  24. */
  25. /// 2009 March: btGeneric6DofConstraint refactored by Roman Ponomarev
  26. /// Added support for generic constraint solver through getInfo1/getInfo2 methods
  27. /*
  28. 2007-09-09
  29. btGeneric6DofConstraint Refactored by Francisco Le?n
  30. email: [email protected]
  31. http://gimpact.sf.net
  32. */
  33. #include "btGeneric6DofSpring2Constraint.h"
  34. #include "BulletDynamics/Dynamics/btRigidBody.h"
  35. #include "LinearMath/btTransformUtil.h"
  36. #include <new>
  37. btGeneric6DofSpring2Constraint::btGeneric6DofSpring2Constraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB, RotateOrder rotOrder)
  38. : btTypedConstraint(D6_SPRING_2_CONSTRAINT_TYPE, rbA, rbB)
  39. , m_frameInA(frameInA)
  40. , m_frameInB(frameInB)
  41. , m_rotateOrder(rotOrder)
  42. , m_flags(0)
  43. {
  44. calculateTransforms();
  45. }
  46. btGeneric6DofSpring2Constraint::btGeneric6DofSpring2Constraint(btRigidBody& rbB, const btTransform& frameInB, RotateOrder rotOrder)
  47. : btTypedConstraint(D6_SPRING_2_CONSTRAINT_TYPE, getFixedBody(), rbB)
  48. , m_frameInB(frameInB)
  49. , m_rotateOrder(rotOrder)
  50. , m_flags(0)
  51. {
  52. ///not providing rigidbody A means implicitly using worldspace for body A
  53. m_frameInA = rbB.getCenterOfMassTransform() * m_frameInB;
  54. calculateTransforms();
  55. }
  56. btScalar btGeneric6DofSpring2Constraint::btGetMatrixElem(const btMatrix3x3& mat, int index)
  57. {
  58. int i = index%3;
  59. int j = index/3;
  60. return mat[i][j];
  61. }
  62. // MatrixToEulerXYZ from http://www.geometrictools.com/LibFoundation/Mathematics/Wm4Matrix3.inl.html
  63. bool btGeneric6DofSpring2Constraint::matrixToEulerXYZ(const btMatrix3x3& mat,btVector3& xyz)
  64. {
  65. // rot = cy*cz -cy*sz sy
  66. // cz*sx*sy+cx*sz cx*cz-sx*sy*sz -cy*sx
  67. // -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy
  68. btScalar fi = btGetMatrixElem(mat,2);
  69. if (fi < btScalar(1.0f))
  70. {
  71. if (fi > btScalar(-1.0f))
  72. {
  73. xyz[0] = btAtan2(-btGetMatrixElem(mat,5),btGetMatrixElem(mat,8));
  74. xyz[1] = btAsin(btGetMatrixElem(mat,2));
  75. xyz[2] = btAtan2(-btGetMatrixElem(mat,1),btGetMatrixElem(mat,0));
  76. return true;
  77. }
  78. else
  79. {
  80. // WARNING. Not unique. XA - ZA = -atan2(r10,r11)
  81. xyz[0] = -btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4));
  82. xyz[1] = -SIMD_HALF_PI;
  83. xyz[2] = btScalar(0.0);
  84. return false;
  85. }
  86. }
  87. else
  88. {
  89. // WARNING. Not unique. XAngle + ZAngle = atan2(r10,r11)
  90. xyz[0] = btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4));
  91. xyz[1] = SIMD_HALF_PI;
  92. xyz[2] = 0.0;
  93. }
  94. return false;
  95. }
  96. bool btGeneric6DofSpring2Constraint::matrixToEulerXZY(const btMatrix3x3& mat,btVector3& xyz)
  97. {
  98. // rot = cy*cz -sz sy*cz
  99. // cy*cx*sz+sx*sy cx*cz sy*cx*sz-cy*sx
  100. // cy*sx*sz-cx*sy sx*cz sy*sx*sz+cx*cy
  101. btScalar fi = btGetMatrixElem(mat,1);
  102. if (fi < btScalar(1.0f))
  103. {
  104. if (fi > btScalar(-1.0f))
  105. {
  106. xyz[0] = btAtan2(btGetMatrixElem(mat,7),btGetMatrixElem(mat,4));
  107. xyz[1] = btAtan2(btGetMatrixElem(mat,2),btGetMatrixElem(mat,0));
  108. xyz[2] = btAsin(-btGetMatrixElem(mat,1));
  109. return true;
  110. }
  111. else
  112. {
  113. xyz[0] = -btAtan2(-btGetMatrixElem(mat,6),btGetMatrixElem(mat,8));
  114. xyz[1] = btScalar(0.0);
  115. xyz[2] = SIMD_HALF_PI;
  116. return false;
  117. }
  118. }
  119. else
  120. {
  121. xyz[0] = btAtan2(-btGetMatrixElem(mat,6),btGetMatrixElem(mat,8));
  122. xyz[1] = 0.0;
  123. xyz[2] = -SIMD_HALF_PI;
  124. }
  125. return false;
  126. }
  127. bool btGeneric6DofSpring2Constraint::matrixToEulerYXZ(const btMatrix3x3& mat,btVector3& xyz)
  128. {
  129. // rot = cy*cz+sy*sx*sz cz*sy*sx-cy*sz cx*sy
  130. // cx*sz cx*cz -sx
  131. // cy*sx*sz-cz*sy sy*sz+cy*cz*sx cy*cx
  132. btScalar fi = btGetMatrixElem(mat,5);
  133. if (fi < btScalar(1.0f))
  134. {
  135. if (fi > btScalar(-1.0f))
  136. {
  137. xyz[0] = btAsin(-btGetMatrixElem(mat,5));
  138. xyz[1] = btAtan2(btGetMatrixElem(mat,2),btGetMatrixElem(mat,8));
  139. xyz[2] = btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4));
  140. return true;
  141. }
  142. else
  143. {
  144. xyz[0] = SIMD_HALF_PI;
  145. xyz[1] = -btAtan2(-btGetMatrixElem(mat,1),btGetMatrixElem(mat,0));
  146. xyz[2] = btScalar(0.0);
  147. return false;
  148. }
  149. }
  150. else
  151. {
  152. xyz[0] = -SIMD_HALF_PI;
  153. xyz[1] = btAtan2(-btGetMatrixElem(mat,1),btGetMatrixElem(mat,0));
  154. xyz[2] = 0.0;
  155. }
  156. return false;
  157. }
  158. bool btGeneric6DofSpring2Constraint::matrixToEulerYZX(const btMatrix3x3& mat,btVector3& xyz)
  159. {
  160. // rot = cy*cz sy*sx-cy*cx*sz cx*sy+cy*sz*sx
  161. // sz cz*cx -cz*sx
  162. // -cz*sy cy*sx+cx*sy*sz cy*cx-sy*sz*sx
  163. btScalar fi = btGetMatrixElem(mat,3);
  164. if (fi < btScalar(1.0f))
  165. {
  166. if (fi > btScalar(-1.0f))
  167. {
  168. xyz[0] = btAtan2(-btGetMatrixElem(mat,5),btGetMatrixElem(mat,4));
  169. xyz[1] = btAtan2(-btGetMatrixElem(mat,6),btGetMatrixElem(mat,0));
  170. xyz[2] = btAsin(btGetMatrixElem(mat,3));
  171. return true;
  172. }
  173. else
  174. {
  175. xyz[0] = btScalar(0.0);
  176. xyz[1] = -btAtan2(btGetMatrixElem(mat,7),btGetMatrixElem(mat,8));
  177. xyz[2] = -SIMD_HALF_PI;
  178. return false;
  179. }
  180. }
  181. else
  182. {
  183. xyz[0] = btScalar(0.0);
  184. xyz[1] = btAtan2(btGetMatrixElem(mat,7),btGetMatrixElem(mat,8));
  185. xyz[2] = SIMD_HALF_PI;
  186. }
  187. return false;
  188. }
  189. bool btGeneric6DofSpring2Constraint::matrixToEulerZXY(const btMatrix3x3& mat,btVector3& xyz)
  190. {
  191. // rot = cz*cy-sz*sx*sy -cx*sz cz*sy+cy*sz*sx
  192. // cy*sz+cz*sx*sy cz*cx sz*sy-cz*xy*sx
  193. // -cx*sy sx cx*cy
  194. btScalar fi = btGetMatrixElem(mat,7);
  195. if (fi < btScalar(1.0f))
  196. {
  197. if (fi > btScalar(-1.0f))
  198. {
  199. xyz[0] = btAsin(btGetMatrixElem(mat,7));
  200. xyz[1] = btAtan2(-btGetMatrixElem(mat,6),btGetMatrixElem(mat,8));
  201. xyz[2] = btAtan2(-btGetMatrixElem(mat,1),btGetMatrixElem(mat,4));
  202. return true;
  203. }
  204. else
  205. {
  206. xyz[0] = -SIMD_HALF_PI;
  207. xyz[1] = btScalar(0.0);
  208. xyz[2] = -btAtan2(btGetMatrixElem(mat,2),btGetMatrixElem(mat,0));
  209. return false;
  210. }
  211. }
  212. else
  213. {
  214. xyz[0] = SIMD_HALF_PI;
  215. xyz[1] = btScalar(0.0);
  216. xyz[2] = btAtan2(btGetMatrixElem(mat,2),btGetMatrixElem(mat,0));
  217. }
  218. return false;
  219. }
  220. bool btGeneric6DofSpring2Constraint::matrixToEulerZYX(const btMatrix3x3& mat,btVector3& xyz)
  221. {
  222. // rot = cz*cy cz*sy*sx-cx*sz sz*sx+cz*cx*sy
  223. // cy*sz cz*cx+sz*sy*sx cx*sz*sy-cz*sx
  224. // -sy cy*sx cy*cx
  225. btScalar fi = btGetMatrixElem(mat,6);
  226. if (fi < btScalar(1.0f))
  227. {
  228. if (fi > btScalar(-1.0f))
  229. {
  230. xyz[0] = btAtan2(btGetMatrixElem(mat,7), btGetMatrixElem(mat,8));
  231. xyz[1] = btAsin(-btGetMatrixElem(mat,6));
  232. xyz[2] = btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,0));
  233. return true;
  234. }
  235. else
  236. {
  237. xyz[0] = btScalar(0.0);
  238. xyz[1] = SIMD_HALF_PI;
  239. xyz[2] = -btAtan2(btGetMatrixElem(mat,1),btGetMatrixElem(mat,2));
  240. return false;
  241. }
  242. }
  243. else
  244. {
  245. xyz[0] = btScalar(0.0);
  246. xyz[1] = -SIMD_HALF_PI;
  247. xyz[2] = btAtan2(-btGetMatrixElem(mat,1),-btGetMatrixElem(mat,2));
  248. }
  249. return false;
  250. }
  251. void btGeneric6DofSpring2Constraint::calculateAngleInfo()
  252. {
  253. btMatrix3x3 relative_frame = m_calculatedTransformA.getBasis().inverse()*m_calculatedTransformB.getBasis();
  254. switch (m_rotateOrder)
  255. {
  256. case RO_XYZ : matrixToEulerXYZ(relative_frame,m_calculatedAxisAngleDiff); break;
  257. case RO_XZY : matrixToEulerXZY(relative_frame,m_calculatedAxisAngleDiff); break;
  258. case RO_YXZ : matrixToEulerYXZ(relative_frame,m_calculatedAxisAngleDiff); break;
  259. case RO_YZX : matrixToEulerYZX(relative_frame,m_calculatedAxisAngleDiff); break;
  260. case RO_ZXY : matrixToEulerZXY(relative_frame,m_calculatedAxisAngleDiff); break;
  261. case RO_ZYX : matrixToEulerZYX(relative_frame,m_calculatedAxisAngleDiff); break;
  262. default : btAssert(false);
  263. }
  264. // in euler angle mode we do not actually constrain the angular velocity
  265. // along the axes axis[0] and axis[2] (although we do use axis[1]) :
  266. //
  267. // to get constrain w2-w1 along ...not
  268. // ------ --------------------- ------
  269. // d(angle[0])/dt = 0 ax[1] x ax[2] ax[0]
  270. // d(angle[1])/dt = 0 ax[1]
  271. // d(angle[2])/dt = 0 ax[0] x ax[1] ax[2]
  272. //
  273. // constraining w2-w1 along an axis 'a' means that a'*(w2-w1)=0.
  274. // to prove the result for angle[0], write the expression for angle[0] from
  275. // GetInfo1 then take the derivative. to prove this for angle[2] it is
  276. // easier to take the euler rate expression for d(angle[2])/dt with respect
  277. // to the components of w and set that to 0.
  278. switch (m_rotateOrder)
  279. {
  280. case RO_XYZ :
  281. {
  282. //Is this the "line of nodes" calculation choosing planes YZ (B coordinate system) and xy (A coordinate system)? (http://en.wikipedia.org/wiki/Euler_angles)
  283. //The two planes are non-homologous, so this is a Tait–Bryan angle formalism and not a proper Euler
  284. //Extrinsic rotations are equal to the reversed order intrinsic rotations so the above xyz extrinsic rotations (axes are fixed) are the same as the zy'x" intrinsic rotations (axes are refreshed after each rotation)
  285. //that is why xy and YZ planes are chosen (this will describe a zy'x" intrinsic rotation) (see the figure on the left at http://en.wikipedia.org/wiki/Euler_angles under Tait–Bryan angles)
  286. // x' = Nperp = N.cross(axis2)
  287. // y' = N = axis2.cross(axis0)
  288. // z' = z
  289. //
  290. // x" = X
  291. // y" = y'
  292. // z" = ??
  293. //in other words:
  294. //first rotate around z
  295. //second rotate around y'= z.cross(X)
  296. //third rotate around x" = X
  297. //Original XYZ extrinsic rotation order.
  298. //Planes: xy and YZ normals: z, X. Plane intersection (N) is z.cross(X)
  299. btVector3 axis0 = m_calculatedTransformB.getBasis().getColumn(0);
  300. btVector3 axis2 = m_calculatedTransformA.getBasis().getColumn(2);
  301. m_calculatedAxis[1] = axis2.cross(axis0);
  302. m_calculatedAxis[0] = m_calculatedAxis[1].cross(axis2);
  303. m_calculatedAxis[2] = axis0.cross(m_calculatedAxis[1]);
  304. break;
  305. }
  306. case RO_XZY :
  307. {
  308. //planes: xz,ZY normals: y, X
  309. //first rotate around y
  310. //second rotate around z'= y.cross(X)
  311. //third rotate around x" = X
  312. btVector3 axis0 = m_calculatedTransformB.getBasis().getColumn(0);
  313. btVector3 axis1 = m_calculatedTransformA.getBasis().getColumn(1);
  314. m_calculatedAxis[2] = axis0.cross(axis1);
  315. m_calculatedAxis[0] = axis1.cross(m_calculatedAxis[2]);
  316. m_calculatedAxis[1] = m_calculatedAxis[2].cross(axis0);
  317. break;
  318. }
  319. case RO_YXZ :
  320. {
  321. //planes: yx,XZ normals: z, Y
  322. //first rotate around z
  323. //second rotate around x'= z.cross(Y)
  324. //third rotate around y" = Y
  325. btVector3 axis1 = m_calculatedTransformB.getBasis().getColumn(1);
  326. btVector3 axis2 = m_calculatedTransformA.getBasis().getColumn(2);
  327. m_calculatedAxis[0] = axis1.cross(axis2);
  328. m_calculatedAxis[1] = axis2.cross(m_calculatedAxis[0]);
  329. m_calculatedAxis[2] = m_calculatedAxis[0].cross(axis1);
  330. break;
  331. }
  332. case RO_YZX :
  333. {
  334. //planes: yz,ZX normals: x, Y
  335. //first rotate around x
  336. //second rotate around z'= x.cross(Y)
  337. //third rotate around y" = Y
  338. btVector3 axis0 = m_calculatedTransformA.getBasis().getColumn(0);
  339. btVector3 axis1 = m_calculatedTransformB.getBasis().getColumn(1);
  340. m_calculatedAxis[2] = axis0.cross(axis1);
  341. m_calculatedAxis[0] = axis1.cross(m_calculatedAxis[2]);
  342. m_calculatedAxis[1] = m_calculatedAxis[2].cross(axis0);
  343. break;
  344. }
  345. case RO_ZXY :
  346. {
  347. //planes: zx,XY normals: y, Z
  348. //first rotate around y
  349. //second rotate around x'= y.cross(Z)
  350. //third rotate around z" = Z
  351. btVector3 axis1 = m_calculatedTransformA.getBasis().getColumn(1);
  352. btVector3 axis2 = m_calculatedTransformB.getBasis().getColumn(2);
  353. m_calculatedAxis[0] = axis1.cross(axis2);
  354. m_calculatedAxis[1] = axis2.cross(m_calculatedAxis[0]);
  355. m_calculatedAxis[2] = m_calculatedAxis[0].cross(axis1);
  356. break;
  357. }
  358. case RO_ZYX :
  359. {
  360. //planes: zy,YX normals: x, Z
  361. //first rotate around x
  362. //second rotate around y' = x.cross(Z)
  363. //third rotate around z" = Z
  364. btVector3 axis0 = m_calculatedTransformA.getBasis().getColumn(0);
  365. btVector3 axis2 = m_calculatedTransformB.getBasis().getColumn(2);
  366. m_calculatedAxis[1] = axis2.cross(axis0);
  367. m_calculatedAxis[0] = m_calculatedAxis[1].cross(axis2);
  368. m_calculatedAxis[2] = axis0.cross(m_calculatedAxis[1]);
  369. break;
  370. }
  371. default:
  372. btAssert(false);
  373. }
  374. m_calculatedAxis[0].normalize();
  375. m_calculatedAxis[1].normalize();
  376. m_calculatedAxis[2].normalize();
  377. }
  378. void btGeneric6DofSpring2Constraint::calculateTransforms()
  379. {
  380. calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform());
  381. }
  382. void btGeneric6DofSpring2Constraint::calculateTransforms(const btTransform& transA,const btTransform& transB)
  383. {
  384. m_calculatedTransformA = transA * m_frameInA;
  385. m_calculatedTransformB = transB * m_frameInB;
  386. calculateLinearInfo();
  387. calculateAngleInfo();
  388. btScalar miA = getRigidBodyA().getInvMass();
  389. btScalar miB = getRigidBodyB().getInvMass();
  390. m_hasStaticBody = (miA < SIMD_EPSILON) || (miB < SIMD_EPSILON);
  391. btScalar miS = miA + miB;
  392. if(miS > btScalar(0.f))
  393. {
  394. m_factA = miB / miS;
  395. }
  396. else
  397. {
  398. m_factA = btScalar(0.5f);
  399. }
  400. m_factB = btScalar(1.0f) - m_factA;
  401. }
  402. void btGeneric6DofSpring2Constraint::testAngularLimitMotor(int axis_index)
  403. {
  404. btScalar angle = m_calculatedAxisAngleDiff[axis_index];
  405. angle = btAdjustAngleToLimits(angle, m_angularLimits[axis_index].m_loLimit, m_angularLimits[axis_index].m_hiLimit);
  406. m_angularLimits[axis_index].m_currentPosition = angle;
  407. m_angularLimits[axis_index].testLimitValue(angle);
  408. }
  409. void btGeneric6DofSpring2Constraint::getInfo1 (btConstraintInfo1* info)
  410. {
  411. //prepare constraint
  412. calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform());
  413. info->m_numConstraintRows = 0;
  414. info->nub = 0;
  415. int i;
  416. //test linear limits
  417. for(i = 0; i < 3; i++)
  418. {
  419. if (m_linearLimits.m_currentLimit[i]==4) info->m_numConstraintRows += 2;
  420. else if (m_linearLimits.m_currentLimit[i]!=0) info->m_numConstraintRows += 1;
  421. if (m_linearLimits.m_enableMotor[i] ) info->m_numConstraintRows += 1;
  422. if (m_linearLimits.m_enableSpring[i]) info->m_numConstraintRows += 1;
  423. }
  424. //test angular limits
  425. for (i=0;i<3 ;i++ )
  426. {
  427. testAngularLimitMotor(i);
  428. if (m_angularLimits[i].m_currentLimit==4) info->m_numConstraintRows += 2;
  429. else if (m_angularLimits[i].m_currentLimit!=0) info->m_numConstraintRows += 1;
  430. if (m_angularLimits[i].m_enableMotor ) info->m_numConstraintRows += 1;
  431. if (m_angularLimits[i].m_enableSpring) info->m_numConstraintRows += 1;
  432. }
  433. }
  434. void btGeneric6DofSpring2Constraint::getInfo2 (btConstraintInfo2* info)
  435. {
  436. const btTransform& transA = m_rbA.getCenterOfMassTransform();
  437. const btTransform& transB = m_rbB.getCenterOfMassTransform();
  438. const btVector3& linVelA = m_rbA.getLinearVelocity();
  439. const btVector3& linVelB = m_rbB.getLinearVelocity();
  440. const btVector3& angVelA = m_rbA.getAngularVelocity();
  441. const btVector3& angVelB = m_rbB.getAngularVelocity();
  442. // for stability better to solve angular limits first
  443. int row = setAngularLimits(info, 0,transA,transB,linVelA,linVelB,angVelA,angVelB);
  444. setLinearLimits(info, row, transA,transB,linVelA,linVelB,angVelA,angVelB);
  445. }
  446. int btGeneric6DofSpring2Constraint::setLinearLimits(btConstraintInfo2* info, int row, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB)
  447. {
  448. //solve linear limits
  449. btRotationalLimitMotor2 limot;
  450. for (int i=0;i<3 ;i++ )
  451. {
  452. if(m_linearLimits.m_currentLimit[i] || m_linearLimits.m_enableMotor[i] || m_linearLimits.m_enableSpring[i])
  453. { // re-use rotational motor code
  454. limot.m_bounce = m_linearLimits.m_bounce[i];
  455. limot.m_currentLimit = m_linearLimits.m_currentLimit[i];
  456. limot.m_currentPosition = m_linearLimits.m_currentLinearDiff[i];
  457. limot.m_currentLimitError = m_linearLimits.m_currentLimitError[i];
  458. limot.m_currentLimitErrorHi = m_linearLimits.m_currentLimitErrorHi[i];
  459. limot.m_enableMotor = m_linearLimits.m_enableMotor[i];
  460. limot.m_servoMotor = m_linearLimits.m_servoMotor[i];
  461. limot.m_servoTarget = m_linearLimits.m_servoTarget[i];
  462. limot.m_enableSpring = m_linearLimits.m_enableSpring[i];
  463. limot.m_springStiffness = m_linearLimits.m_springStiffness[i];
  464. limot.m_springStiffnessLimited = m_linearLimits.m_springStiffnessLimited[i];
  465. limot.m_springDamping = m_linearLimits.m_springDamping[i];
  466. limot.m_springDampingLimited = m_linearLimits.m_springDampingLimited[i];
  467. limot.m_equilibriumPoint = m_linearLimits.m_equilibriumPoint[i];
  468. limot.m_hiLimit = m_linearLimits.m_upperLimit[i];
  469. limot.m_loLimit = m_linearLimits.m_lowerLimit[i];
  470. limot.m_maxMotorForce = m_linearLimits.m_maxMotorForce[i];
  471. limot.m_targetVelocity = m_linearLimits.m_targetVelocity[i];
  472. btVector3 axis = m_calculatedTransformA.getBasis().getColumn(i);
  473. int flags = m_flags >> (i * BT_6DOF_FLAGS_AXIS_SHIFT2);
  474. limot.m_stopCFM = (flags & BT_6DOF_FLAGS_CFM_STOP2) ? m_linearLimits.m_stopCFM[i] : info->cfm[0];
  475. limot.m_stopERP = (flags & BT_6DOF_FLAGS_ERP_STOP2) ? m_linearLimits.m_stopERP[i] : info->erp;
  476. limot.m_motorCFM = (flags & BT_6DOF_FLAGS_CFM_MOTO2) ? m_linearLimits.m_motorCFM[i] : info->cfm[0];
  477. limot.m_motorERP = (flags & BT_6DOF_FLAGS_ERP_MOTO2) ? m_linearLimits.m_motorERP[i] : info->erp;
  478. //rotAllowed is a bit of a magic from the original 6dof. The calculation of it here is something that imitates the original behavior as much as possible.
  479. int indx1 = (i + 1) % 3;
  480. int indx2 = (i + 2) % 3;
  481. int rotAllowed = 1; // rotations around orthos to current axis (it is used only when one of the body is static)
  482. #define D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION 1.0e-3
  483. bool indx1Violated = m_angularLimits[indx1].m_currentLimit == 1 ||
  484. m_angularLimits[indx1].m_currentLimit == 2 ||
  485. ( m_angularLimits[indx1].m_currentLimit == 3 && ( m_angularLimits[indx1].m_currentLimitError < -D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION || m_angularLimits[indx1].m_currentLimitError > D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION ) ) ||
  486. ( m_angularLimits[indx1].m_currentLimit == 4 && ( m_angularLimits[indx1].m_currentLimitError < -D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION || m_angularLimits[indx1].m_currentLimitErrorHi > D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION ) );
  487. bool indx2Violated = m_angularLimits[indx2].m_currentLimit == 1 ||
  488. m_angularLimits[indx2].m_currentLimit == 2 ||
  489. ( m_angularLimits[indx2].m_currentLimit == 3 && ( m_angularLimits[indx2].m_currentLimitError < -D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION || m_angularLimits[indx2].m_currentLimitError > D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION ) ) ||
  490. ( m_angularLimits[indx2].m_currentLimit == 4 && ( m_angularLimits[indx2].m_currentLimitError < -D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION || m_angularLimits[indx2].m_currentLimitErrorHi > D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION ) );
  491. if( indx1Violated && indx2Violated )
  492. {
  493. rotAllowed = 0;
  494. }
  495. row += get_limit_motor_info2(&limot, transA,transB,linVelA,linVelB,angVelA,angVelB, info, row, axis, 0, rotAllowed);
  496. }
  497. }
  498. return row;
  499. }
  500. int btGeneric6DofSpring2Constraint::setAngularLimits(btConstraintInfo2 *info, int row_offset, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB)
  501. {
  502. int row = row_offset;
  503. //order of rotational constraint rows
  504. int cIdx[] = {0, 1, 2};
  505. switch(m_rotateOrder)
  506. {
  507. case RO_XYZ : cIdx[0] = 0; cIdx[1] = 1; cIdx[2] = 2; break;
  508. case RO_XZY : cIdx[0] = 0; cIdx[1] = 2; cIdx[2] = 1; break;
  509. case RO_YXZ : cIdx[0] = 1; cIdx[1] = 0; cIdx[2] = 2; break;
  510. case RO_YZX : cIdx[0] = 1; cIdx[1] = 2; cIdx[2] = 0; break;
  511. case RO_ZXY : cIdx[0] = 2; cIdx[1] = 0; cIdx[2] = 1; break;
  512. case RO_ZYX : cIdx[0] = 2; cIdx[1] = 1; cIdx[2] = 0; break;
  513. default : btAssert(false);
  514. }
  515. for (int ii = 0; ii < 3 ; ii++ )
  516. {
  517. int i = cIdx[ii];
  518. if(m_angularLimits[i].m_currentLimit || m_angularLimits[i].m_enableMotor || m_angularLimits[i].m_enableSpring)
  519. {
  520. btVector3 axis = getAxis(i);
  521. int flags = m_flags >> ((i + 3) * BT_6DOF_FLAGS_AXIS_SHIFT2);
  522. if(!(flags & BT_6DOF_FLAGS_CFM_STOP2))
  523. {
  524. m_angularLimits[i].m_stopCFM = info->cfm[0];
  525. }
  526. if(!(flags & BT_6DOF_FLAGS_ERP_STOP2))
  527. {
  528. m_angularLimits[i].m_stopERP = info->erp;
  529. }
  530. if(!(flags & BT_6DOF_FLAGS_CFM_MOTO2))
  531. {
  532. m_angularLimits[i].m_motorCFM = info->cfm[0];
  533. }
  534. if(!(flags & BT_6DOF_FLAGS_ERP_MOTO2))
  535. {
  536. m_angularLimits[i].m_motorERP = info->erp;
  537. }
  538. row += get_limit_motor_info2(&m_angularLimits[i],transA,transB,linVelA,linVelB,angVelA,angVelB, info,row,axis,1);
  539. }
  540. }
  541. return row;
  542. }
  543. void btGeneric6DofSpring2Constraint::setFrames(const btTransform& frameA, const btTransform& frameB)
  544. {
  545. m_frameInA = frameA;
  546. m_frameInB = frameB;
  547. buildJacobian();
  548. calculateTransforms();
  549. }
  550. void btGeneric6DofSpring2Constraint::calculateLinearInfo()
  551. {
  552. m_calculatedLinearDiff = m_calculatedTransformB.getOrigin() - m_calculatedTransformA.getOrigin();
  553. m_calculatedLinearDiff = m_calculatedTransformA.getBasis().inverse() * m_calculatedLinearDiff;
  554. for(int i = 0; i < 3; i++)
  555. {
  556. m_linearLimits.m_currentLinearDiff[i] = m_calculatedLinearDiff[i];
  557. m_linearLimits.testLimitValue(i, m_calculatedLinearDiff[i]);
  558. }
  559. }
  560. void btGeneric6DofSpring2Constraint::calculateJacobi(btRotationalLimitMotor2 * limot, const btTransform& transA,const btTransform& transB, btConstraintInfo2 *info, int srow, btVector3& ax1, int rotational, int rotAllowed)
  561. {
  562. btScalar *J1 = rotational ? info->m_J1angularAxis : info->m_J1linearAxis;
  563. btScalar *J2 = rotational ? info->m_J2angularAxis : info->m_J2linearAxis;
  564. J1[srow+0] = ax1[0];
  565. J1[srow+1] = ax1[1];
  566. J1[srow+2] = ax1[2];
  567. J2[srow+0] = -ax1[0];
  568. J2[srow+1] = -ax1[1];
  569. J2[srow+2] = -ax1[2];
  570. if(!rotational)
  571. {
  572. btVector3 tmpA, tmpB, relA, relB;
  573. // get vector from bodyB to frameB in WCS
  574. relB = m_calculatedTransformB.getOrigin() - transB.getOrigin();
  575. // same for bodyA
  576. relA = m_calculatedTransformA.getOrigin() - transA.getOrigin();
  577. tmpA = relA.cross(ax1);
  578. tmpB = relB.cross(ax1);
  579. if(m_hasStaticBody && (!rotAllowed))
  580. {
  581. tmpA *= m_factA;
  582. tmpB *= m_factB;
  583. }
  584. int i;
  585. for (i=0; i<3; i++) info->m_J1angularAxis[srow+i] = tmpA[i];
  586. for (i=0; i<3; i++) info->m_J2angularAxis[srow+i] = -tmpB[i];
  587. }
  588. }
  589. int btGeneric6DofSpring2Constraint::get_limit_motor_info2(
  590. btRotationalLimitMotor2 * limot,
  591. const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB,
  592. btConstraintInfo2 *info, int row, btVector3& ax1, int rotational,int rotAllowed)
  593. {
  594. int count = 0;
  595. int srow = row * info->rowskip;
  596. if (limot->m_currentLimit==4)
  597. {
  598. btScalar vel = rotational ? angVelA.dot(ax1) - angVelB.dot(ax1) : linVelA.dot(ax1) - linVelB.dot(ax1);
  599. calculateJacobi(limot,transA,transB,info,srow,ax1,rotational,rotAllowed);
  600. info->m_constraintError[srow] = info->fps * limot->m_stopERP * limot->m_currentLimitError * (rotational ? -1 : 1);
  601. if (rotational) {
  602. if (info->m_constraintError[srow]-vel*limot->m_stopERP > 0) {
  603. btScalar bounceerror = -limot->m_bounce* vel;
  604. if (bounceerror > info->m_constraintError[srow]) info->m_constraintError[srow] = bounceerror;
  605. }
  606. } else {
  607. if (info->m_constraintError[srow]-vel*limot->m_stopERP < 0) {
  608. btScalar bounceerror = -limot->m_bounce* vel;
  609. if (bounceerror < info->m_constraintError[srow]) info->m_constraintError[srow] = bounceerror;
  610. }
  611. }
  612. info->m_lowerLimit[srow] = rotational ? 0 : -SIMD_INFINITY;
  613. info->m_upperLimit[srow] = rotational ? SIMD_INFINITY : 0;
  614. info->cfm[srow] = limot->m_stopCFM;
  615. srow += info->rowskip;
  616. ++count;
  617. calculateJacobi(limot,transA,transB,info,srow,ax1,rotational,rotAllowed);
  618. info->m_constraintError[srow] = info->fps * limot->m_stopERP * limot->m_currentLimitErrorHi * (rotational ? -1 : 1);
  619. if (rotational) {
  620. if (info->m_constraintError[srow]-vel*limot->m_stopERP < 0) {
  621. btScalar bounceerror = -limot->m_bounce* vel;
  622. if (bounceerror < info->m_constraintError[srow]) info->m_constraintError[srow] = bounceerror;
  623. }
  624. } else {
  625. if (info->m_constraintError[srow]-vel*limot->m_stopERP > 0) {
  626. btScalar bounceerror = -limot->m_bounce* vel;
  627. if (bounceerror > info->m_constraintError[srow]) info->m_constraintError[srow] = bounceerror;
  628. }
  629. }
  630. info->m_lowerLimit[srow] = rotational ? -SIMD_INFINITY : 0;
  631. info->m_upperLimit[srow] = rotational ? 0 : SIMD_INFINITY;
  632. info->cfm[srow] = limot->m_stopCFM;
  633. srow += info->rowskip;
  634. ++count;
  635. } else
  636. if (limot->m_currentLimit==3)
  637. {
  638. calculateJacobi(limot,transA,transB,info,srow,ax1,rotational,rotAllowed);
  639. info->m_constraintError[srow] = info->fps * limot->m_stopERP * limot->m_currentLimitError * (rotational ? -1 : 1);
  640. info->m_lowerLimit[srow] = -SIMD_INFINITY;
  641. info->m_upperLimit[srow] = SIMD_INFINITY;
  642. info->cfm[srow] = limot->m_stopCFM;
  643. srow += info->rowskip;
  644. ++count;
  645. }
  646. if (limot->m_enableMotor && !limot->m_servoMotor)
  647. {
  648. calculateJacobi(limot,transA,transB,info,srow,ax1,rotational,rotAllowed);
  649. btScalar tag_vel = rotational ? limot->m_targetVelocity : -limot->m_targetVelocity;
  650. btScalar mot_fact = getMotorFactor(limot->m_currentPosition,
  651. limot->m_loLimit,
  652. limot->m_hiLimit,
  653. tag_vel,
  654. info->fps * limot->m_motorERP);
  655. info->m_constraintError[srow] = mot_fact * limot->m_targetVelocity;
  656. info->m_lowerLimit[srow] = -limot->m_maxMotorForce / info->fps;
  657. info->m_upperLimit[srow] = limot->m_maxMotorForce / info->fps;
  658. info->cfm[srow] = limot->m_motorCFM;
  659. srow += info->rowskip;
  660. ++count;
  661. }
  662. if (limot->m_enableMotor && limot->m_servoMotor)
  663. {
  664. btScalar error = limot->m_currentPosition - limot->m_servoTarget;
  665. btScalar curServoTarget = limot->m_servoTarget;
  666. if (rotational)
  667. {
  668. if (error > SIMD_PI)
  669. {
  670. error -= SIMD_2_PI;
  671. curServoTarget +=SIMD_2_PI;
  672. }
  673. if (error < -SIMD_PI)
  674. {
  675. error += SIMD_2_PI;
  676. curServoTarget -=SIMD_2_PI;
  677. }
  678. }
  679. calculateJacobi(limot,transA,transB,info,srow,ax1,rotational,rotAllowed);
  680. btScalar targetvelocity = error<0 ? -limot->m_targetVelocity : limot->m_targetVelocity;
  681. btScalar tag_vel = -targetvelocity;
  682. btScalar mot_fact;
  683. if(error != 0)
  684. {
  685. btScalar lowLimit;
  686. btScalar hiLimit;
  687. if(limot->m_loLimit > limot->m_hiLimit)
  688. {
  689. lowLimit = error > 0 ? curServoTarget : -SIMD_INFINITY;
  690. hiLimit = error < 0 ? curServoTarget : SIMD_INFINITY;
  691. }
  692. else
  693. {
  694. lowLimit = error > 0 && curServoTarget>limot->m_loLimit ? curServoTarget : limot->m_loLimit;
  695. hiLimit = error < 0 && curServoTarget<limot->m_hiLimit ? curServoTarget : limot->m_hiLimit;
  696. }
  697. mot_fact = getMotorFactor(limot->m_currentPosition, lowLimit, hiLimit, tag_vel, info->fps * limot->m_motorERP);
  698. }
  699. else
  700. {
  701. mot_fact = 0;
  702. }
  703. info->m_constraintError[srow] = mot_fact * targetvelocity * (rotational ? -1 : 1);
  704. info->m_lowerLimit[srow] = -limot->m_maxMotorForce / info->fps;
  705. info->m_upperLimit[srow] = limot->m_maxMotorForce / info->fps;
  706. info->cfm[srow] = limot->m_motorCFM;
  707. srow += info->rowskip;
  708. ++count;
  709. }
  710. if (limot->m_enableSpring)
  711. {
  712. btScalar error = limot->m_currentPosition - limot->m_equilibriumPoint;
  713. calculateJacobi(limot,transA,transB,info,srow,ax1,rotational,rotAllowed);
  714. //btScalar cfm = 1.0 / ((1.0/info->fps)*limot->m_springStiffness+ limot->m_springDamping);
  715. //if(cfm > 0.99999)
  716. // cfm = 0.99999;
  717. //btScalar erp = (1.0/info->fps)*limot->m_springStiffness / ((1.0/info->fps)*limot->m_springStiffness + limot->m_springDamping);
  718. //info->m_constraintError[srow] = info->fps * erp * error * (rotational ? -1.0 : 1.0);
  719. //info->m_lowerLimit[srow] = -SIMD_INFINITY;
  720. //info->m_upperLimit[srow] = SIMD_INFINITY;
  721. btScalar dt = BT_ONE / info->fps;
  722. btScalar kd = limot->m_springDamping;
  723. btScalar ks = limot->m_springStiffness;
  724. btScalar vel = rotational ? angVelA.dot(ax1) - angVelB.dot(ax1) : linVelA.dot(ax1) - linVelB.dot(ax1);
  725. // btScalar erp = 0.1;
  726. btScalar cfm = BT_ZERO;
  727. btScalar mA = BT_ONE / m_rbA.getInvMass();
  728. btScalar mB = BT_ONE / m_rbB.getInvMass();
  729. if (rotational) {
  730. btScalar rrA = (m_calculatedTransformA.getOrigin() - transA.getOrigin()).length2();
  731. btScalar rrB = (m_calculatedTransformB.getOrigin() - transB.getOrigin()).length2();
  732. if (m_rbA.getInvMass()) mA = mA * rrA + 1 / (m_rbA.getInvInertiaTensorWorld() * ax1).length();
  733. if (m_rbB.getInvMass()) mB = mB * rrB + 1 / (m_rbB.getInvInertiaTensorWorld() * ax1).length();
  734. }
  735. btScalar m = mA > mB ? mB : mA;
  736. btScalar angularfreq = sqrt(ks / m);
  737. //limit stiffness (the spring should not be sampled faster that the quarter of its angular frequency)
  738. if(limot->m_springStiffnessLimited && 0.25 < angularfreq * dt)
  739. {
  740. ks = BT_ONE / dt / dt / btScalar(16.0) * m;
  741. }
  742. //avoid damping that would blow up the spring
  743. if(limot->m_springDampingLimited && kd * dt > m)
  744. {
  745. kd = m / dt;
  746. }
  747. btScalar fs = ks * error * dt;
  748. btScalar fd = -kd * (vel) * (rotational ? -1 : 1) * dt;
  749. btScalar f = (fs+fd);
  750. // after the spring force affecting the body(es) the new velocity will be
  751. // vel + f / m * (rotational ? -1 : 1)
  752. // so in theory this should be set here for m_constraintError
  753. // (with m_constraintError we set a desired velocity for the affected body(es))
  754. // however in practice any value is fine as long as it is greater then the "proper" velocity,
  755. // because the m_lowerLimit and the m_upperLimit will determinate the strength of the final pulling force
  756. // so it is much simpler (and more robust) just to simply use inf (with the proper sign)
  757. // you may also wonder what if the current velocity (vel) so high that the pulling force will not change its direction (in this iteration)
  758. // will we not request a velocity with the wrong direction ?
  759. // and the answare is not, because in practice during the solving the current velocity is subtracted from the m_constraintError
  760. // so the sign of the force that is really matters
  761. info->m_constraintError[srow] = (rotational ? -1 : 1) * (f < 0 ? -SIMD_INFINITY : SIMD_INFINITY);
  762. btScalar minf = f < fd ? f : fd;
  763. btScalar maxf = f < fd ? fd : f;
  764. if(!rotational)
  765. {
  766. info->m_lowerLimit[srow] = minf > 0 ? 0 : minf;
  767. info->m_upperLimit[srow] = maxf < 0 ? 0 : maxf;
  768. }
  769. else
  770. {
  771. info->m_lowerLimit[srow] = -maxf > 0 ? 0 : -maxf;
  772. info->m_upperLimit[srow] = -minf < 0 ? 0 : -minf;
  773. }
  774. info->cfm[srow] = cfm;
  775. srow += info->rowskip;
  776. ++count;
  777. }
  778. return count;
  779. }
  780. //override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5).
  781. //If no axis is provided, it uses the default axis for this constraint.
  782. void btGeneric6DofSpring2Constraint::setParam(int num, btScalar value, int axis)
  783. {
  784. if((axis >= 0) && (axis < 3))
  785. {
  786. switch(num)
  787. {
  788. case BT_CONSTRAINT_STOP_ERP :
  789. m_linearLimits.m_stopERP[axis] = value;
  790. m_flags |= BT_6DOF_FLAGS_ERP_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2);
  791. break;
  792. case BT_CONSTRAINT_STOP_CFM :
  793. m_linearLimits.m_stopCFM[axis] = value;
  794. m_flags |= BT_6DOF_FLAGS_CFM_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2);
  795. break;
  796. case BT_CONSTRAINT_ERP :
  797. m_linearLimits.m_motorERP[axis] = value;
  798. m_flags |= BT_6DOF_FLAGS_ERP_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2);
  799. break;
  800. case BT_CONSTRAINT_CFM :
  801. m_linearLimits.m_motorCFM[axis] = value;
  802. m_flags |= BT_6DOF_FLAGS_CFM_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2);
  803. break;
  804. default :
  805. btAssertConstrParams(0);
  806. }
  807. }
  808. else if((axis >=3) && (axis < 6))
  809. {
  810. switch(num)
  811. {
  812. case BT_CONSTRAINT_STOP_ERP :
  813. m_angularLimits[axis - 3].m_stopERP = value;
  814. m_flags |= BT_6DOF_FLAGS_ERP_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2);
  815. break;
  816. case BT_CONSTRAINT_STOP_CFM :
  817. m_angularLimits[axis - 3].m_stopCFM = value;
  818. m_flags |= BT_6DOF_FLAGS_CFM_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2);
  819. break;
  820. case BT_CONSTRAINT_ERP :
  821. m_angularLimits[axis - 3].m_motorERP = value;
  822. m_flags |= BT_6DOF_FLAGS_ERP_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2);
  823. break;
  824. case BT_CONSTRAINT_CFM :
  825. m_angularLimits[axis - 3].m_motorCFM = value;
  826. m_flags |= BT_6DOF_FLAGS_CFM_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2);
  827. break;
  828. default :
  829. btAssertConstrParams(0);
  830. }
  831. }
  832. else
  833. {
  834. btAssertConstrParams(0);
  835. }
  836. }
  837. //return the local value of parameter
  838. btScalar btGeneric6DofSpring2Constraint::getParam(int num, int axis) const
  839. {
  840. btScalar retVal = 0;
  841. if((axis >= 0) && (axis < 3))
  842. {
  843. switch(num)
  844. {
  845. case BT_CONSTRAINT_STOP_ERP :
  846. btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2)));
  847. retVal = m_linearLimits.m_stopERP[axis];
  848. break;
  849. case BT_CONSTRAINT_STOP_CFM :
  850. btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2)));
  851. retVal = m_linearLimits.m_stopCFM[axis];
  852. break;
  853. case BT_CONSTRAINT_ERP :
  854. btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2)));
  855. retVal = m_linearLimits.m_motorERP[axis];
  856. break;
  857. case BT_CONSTRAINT_CFM :
  858. btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2)));
  859. retVal = m_linearLimits.m_motorCFM[axis];
  860. break;
  861. default :
  862. btAssertConstrParams(0);
  863. }
  864. }
  865. else if((axis >=3) && (axis < 6))
  866. {
  867. switch(num)
  868. {
  869. case BT_CONSTRAINT_STOP_ERP :
  870. btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2)));
  871. retVal = m_angularLimits[axis - 3].m_stopERP;
  872. break;
  873. case BT_CONSTRAINT_STOP_CFM :
  874. btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2)));
  875. retVal = m_angularLimits[axis - 3].m_stopCFM;
  876. break;
  877. case BT_CONSTRAINT_ERP :
  878. btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2)));
  879. retVal = m_angularLimits[axis - 3].m_motorERP;
  880. break;
  881. case BT_CONSTRAINT_CFM :
  882. btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2)));
  883. retVal = m_angularLimits[axis - 3].m_motorCFM;
  884. break;
  885. default :
  886. btAssertConstrParams(0);
  887. }
  888. }
  889. else
  890. {
  891. btAssertConstrParams(0);
  892. }
  893. return retVal;
  894. }
  895. void btGeneric6DofSpring2Constraint::setAxis(const btVector3& axis1,const btVector3& axis2)
  896. {
  897. btVector3 zAxis = axis1.normalized();
  898. btVector3 yAxis = axis2.normalized();
  899. btVector3 xAxis = yAxis.cross(zAxis); // we want right coordinate system
  900. btTransform frameInW;
  901. frameInW.setIdentity();
  902. frameInW.getBasis().setValue( xAxis[0], yAxis[0], zAxis[0],
  903. xAxis[1], yAxis[1], zAxis[1],
  904. xAxis[2], yAxis[2], zAxis[2]);
  905. // now get constraint frame in local coordinate systems
  906. m_frameInA = m_rbA.getCenterOfMassTransform().inverse() * frameInW;
  907. m_frameInB = m_rbB.getCenterOfMassTransform().inverse() * frameInW;
  908. calculateTransforms();
  909. }
  910. void btGeneric6DofSpring2Constraint::setBounce(int index, btScalar bounce)
  911. {
  912. btAssert((index >= 0) && (index < 6));
  913. if (index<3)
  914. m_linearLimits.m_bounce[index] = bounce;
  915. else
  916. m_angularLimits[index - 3].m_bounce = bounce;
  917. }
  918. void btGeneric6DofSpring2Constraint::enableMotor(int index, bool onOff)
  919. {
  920. btAssert((index >= 0) && (index < 6));
  921. if (index<3)
  922. m_linearLimits.m_enableMotor[index] = onOff;
  923. else
  924. m_angularLimits[index - 3].m_enableMotor = onOff;
  925. }
  926. void btGeneric6DofSpring2Constraint::setServo(int index, bool onOff)
  927. {
  928. btAssert((index >= 0) && (index < 6));
  929. if (index<3)
  930. m_linearLimits.m_servoMotor[index] = onOff;
  931. else
  932. m_angularLimits[index - 3].m_servoMotor = onOff;
  933. }
  934. void btGeneric6DofSpring2Constraint::setTargetVelocity(int index, btScalar velocity)
  935. {
  936. btAssert((index >= 0) && (index < 6));
  937. if (index<3)
  938. m_linearLimits.m_targetVelocity[index] = velocity;
  939. else
  940. m_angularLimits[index - 3].m_targetVelocity = velocity;
  941. }
  942. void btGeneric6DofSpring2Constraint::setServoTarget(int index, btScalar targetOrg)
  943. {
  944. btAssert((index >= 0) && (index < 6));
  945. if (index<3)
  946. {
  947. m_linearLimits.m_servoTarget[index] = targetOrg;
  948. }
  949. else
  950. {
  951. //wrap between -PI and PI, see also
  952. //https://stackoverflow.com/questions/4633177/c-how-to-wrap-a-float-to-the-interval-pi-pi
  953. btScalar target = targetOrg+SIMD_PI;
  954. if (1)
  955. {
  956. btScalar m = target - SIMD_2_PI * floor(target/SIMD_2_PI);
  957. // handle boundary cases resulted from floating-point cut off:
  958. {
  959. if (m>=SIMD_2_PI)
  960. {
  961. target = 0;
  962. } else
  963. {
  964. if (m<0 )
  965. {
  966. if (SIMD_2_PI+m == SIMD_2_PI)
  967. target = 0;
  968. else
  969. target = SIMD_2_PI+m;
  970. }
  971. else
  972. {
  973. target = m;
  974. }
  975. }
  976. }
  977. target -= SIMD_PI;
  978. }
  979. m_angularLimits[index - 3].m_servoTarget = target;
  980. }
  981. }
  982. void btGeneric6DofSpring2Constraint::setMaxMotorForce(int index, btScalar force)
  983. {
  984. btAssert((index >= 0) && (index < 6));
  985. if (index<3)
  986. m_linearLimits.m_maxMotorForce[index] = force;
  987. else
  988. m_angularLimits[index - 3].m_maxMotorForce = force;
  989. }
  990. void btGeneric6DofSpring2Constraint::enableSpring(int index, bool onOff)
  991. {
  992. btAssert((index >= 0) && (index < 6));
  993. if (index<3)
  994. m_linearLimits.m_enableSpring[index] = onOff;
  995. else
  996. m_angularLimits[index - 3] .m_enableSpring = onOff;
  997. }
  998. void btGeneric6DofSpring2Constraint::setStiffness(int index, btScalar stiffness, bool limitIfNeeded)
  999. {
  1000. btAssert((index >= 0) && (index < 6));
  1001. if (index<3) {
  1002. m_linearLimits.m_springStiffness[index] = stiffness;
  1003. m_linearLimits.m_springStiffnessLimited[index] = limitIfNeeded;
  1004. } else {
  1005. m_angularLimits[index - 3].m_springStiffness = stiffness;
  1006. m_angularLimits[index - 3].m_springStiffnessLimited = limitIfNeeded;
  1007. }
  1008. }
  1009. void btGeneric6DofSpring2Constraint::setDamping(int index, btScalar damping, bool limitIfNeeded)
  1010. {
  1011. btAssert((index >= 0) && (index < 6));
  1012. if (index<3) {
  1013. m_linearLimits.m_springDamping[index] = damping;
  1014. m_linearLimits.m_springDampingLimited[index] = limitIfNeeded;
  1015. } else {
  1016. m_angularLimits[index - 3].m_springDamping = damping;
  1017. m_angularLimits[index - 3].m_springDampingLimited = limitIfNeeded;
  1018. }
  1019. }
  1020. void btGeneric6DofSpring2Constraint::setEquilibriumPoint()
  1021. {
  1022. calculateTransforms();
  1023. int i;
  1024. for( i = 0; i < 3; i++)
  1025. m_linearLimits.m_equilibriumPoint[i] = m_calculatedLinearDiff[i];
  1026. for(i = 0; i < 3; i++)
  1027. m_angularLimits[i].m_equilibriumPoint = m_calculatedAxisAngleDiff[i];
  1028. }
  1029. void btGeneric6DofSpring2Constraint::setEquilibriumPoint(int index)
  1030. {
  1031. btAssert((index >= 0) && (index < 6));
  1032. calculateTransforms();
  1033. if (index<3)
  1034. m_linearLimits.m_equilibriumPoint[index] = m_calculatedLinearDiff[index];
  1035. else
  1036. m_angularLimits[index - 3] .m_equilibriumPoint = m_calculatedAxisAngleDiff[index - 3];
  1037. }
  1038. void btGeneric6DofSpring2Constraint::setEquilibriumPoint(int index, btScalar val)
  1039. {
  1040. btAssert((index >= 0) && (index < 6));
  1041. if (index<3)
  1042. m_linearLimits.m_equilibriumPoint[index] = val;
  1043. else
  1044. m_angularLimits[index - 3] .m_equilibriumPoint = val;
  1045. }
  1046. //////////////////////////// btRotationalLimitMotor2 ////////////////////////////////////
  1047. void btRotationalLimitMotor2::testLimitValue(btScalar test_value)
  1048. {
  1049. //we can't normalize the angles here because we would lost the sign that we use later, but it doesn't seem to be a problem
  1050. if(m_loLimit > m_hiLimit) {
  1051. m_currentLimit = 0;
  1052. m_currentLimitError = btScalar(0.f);
  1053. }
  1054. else if(m_loLimit == m_hiLimit) {
  1055. m_currentLimitError = test_value - m_loLimit;
  1056. m_currentLimit = 3;
  1057. } else {
  1058. m_currentLimitError = test_value - m_loLimit;
  1059. m_currentLimitErrorHi = test_value - m_hiLimit;
  1060. m_currentLimit = 4;
  1061. }
  1062. }
  1063. //////////////////////////// btTranslationalLimitMotor2 ////////////////////////////////////
  1064. void btTranslationalLimitMotor2::testLimitValue(int limitIndex, btScalar test_value)
  1065. {
  1066. btScalar loLimit = m_lowerLimit[limitIndex];
  1067. btScalar hiLimit = m_upperLimit[limitIndex];
  1068. if(loLimit > hiLimit) {
  1069. m_currentLimitError[limitIndex] = 0;
  1070. m_currentLimit[limitIndex] = 0;
  1071. }
  1072. else if(loLimit == hiLimit) {
  1073. m_currentLimitError[limitIndex] = test_value - loLimit;
  1074. m_currentLimit[limitIndex] = 3;
  1075. } else {
  1076. m_currentLimitError[limitIndex] = test_value - loLimit;
  1077. m_currentLimitErrorHi[limitIndex] = test_value - hiLimit;
  1078. m_currentLimit[limitIndex] = 4;
  1079. }
  1080. }