joint.cpp 82 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803
  1. /*************************************************************************
  2. * *
  3. * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
  4. * All rights reserved. Email: [email protected] Web: www.q12.org *
  5. * *
  6. * This library is free software; you can redistribute it and/or *
  7. * modify it under the terms of EITHER: *
  8. * (1) The GNU Lesser General Public License as published by the Free *
  9. * Software Foundation; either version 2.1 of the License, or (at *
  10. * your option) any later version. The text of the GNU Lesser *
  11. * General Public License is included with this library in the *
  12. * file LICENSE.TXT. *
  13. * (2) The BSD-style license that is included with this library in *
  14. * the file LICENSE-BSD.TXT. *
  15. * *
  16. * This library is distributed in the hope that it will be useful, *
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
  19. * LICENSE.TXT and LICENSE-BSD.TXT for more details. *
  20. * *
  21. *************************************************************************/
  22. /*
  23. design note: the general principle for giving a joint the option of connecting
  24. to the static environment (i.e. the absolute frame) is to check the second
  25. body (joint->node[1].body), and if it is zero then behave as if its body
  26. transform is the identity.
  27. */
  28. #include <ode/odemath.h>
  29. #include <ode/rotation.h>
  30. #include <ode/matrix.h>
  31. #include "joint.h"
  32. //****************************************************************************
  33. // externs
  34. extern "C" void dBodyAddTorque (dBodyID, dReal fx, dReal fy, dReal fz);
  35. extern "C" void dBodyAddForce (dBodyID, dReal fx, dReal fy, dReal fz);
  36. //****************************************************************************
  37. // utility
  38. // set three "ball-and-socket" rows in the constraint equation, and the
  39. // corresponding right hand side.
  40. static inline void setBall (dxJoint *joint, dxJoint::Info2 *info,
  41. dVector3 anchor1, dVector3 anchor2)
  42. {
  43. // anchor points in global coordinates with respect to body PORs.
  44. dVector3 a1,a2;
  45. int s = info->rowskip;
  46. // set jacobian
  47. info->J1l[0] = 1;
  48. info->J1l[s+1] = 1;
  49. info->J1l[2*s+2] = 1;
  50. dMULTIPLY0_331 (a1,joint->node[0].body->R,anchor1);
  51. dCROSSMAT (info->J1a,a1,s,-,+);
  52. if (joint->node[1].body) {
  53. info->J2l[0] = -1;
  54. info->J2l[s+1] = -1;
  55. info->J2l[2*s+2] = -1;
  56. dMULTIPLY0_331 (a2,joint->node[1].body->R,anchor2);
  57. dCROSSMAT (info->J2a,a2,s,+,-);
  58. }
  59. // set right hand side
  60. dReal k = info->fps * info->erp;
  61. if (joint->node[1].body) {
  62. for (int j=0; j<3; j++) {
  63. info->c[j] = k * (a2[j] + joint->node[1].body->pos[j] -
  64. a1[j] - joint->node[0].body->pos[j]);
  65. }
  66. }
  67. else {
  68. for (int j=0; j<3; j++) {
  69. info->c[j] = k * (anchor2[j] - a1[j] -
  70. joint->node[0].body->pos[j]);
  71. }
  72. }
  73. }
  74. // this is like setBall(), except that `axis' is a unit length vector
  75. // (in global coordinates) that should be used for the first jacobian
  76. // position row (the other two row vectors will be derived from this).
  77. // `erp1' is the erp value to use along the axis.
  78. static inline void setBall2 (dxJoint *joint, dxJoint::Info2 *info,
  79. dVector3 anchor1, dVector3 anchor2,
  80. dVector3 axis, dReal erp1)
  81. {
  82. // anchor points in global coordinates with respect to body PORs.
  83. dVector3 a1,a2;
  84. int i,s = info->rowskip;
  85. // get vectors normal to the axis. in setBall() axis,q1,q2 is [1 0 0],
  86. // [0 1 0] and [0 0 1], which makes everything much easier.
  87. dVector3 q1,q2;
  88. dPlaneSpace (axis,q1,q2);
  89. // set jacobian
  90. for (i=0; i<3; i++) info->J1l[i] = axis[i];
  91. for (i=0; i<3; i++) info->J1l[s+i] = q1[i];
  92. for (i=0; i<3; i++) info->J1l[2*s+i] = q2[i];
  93. dMULTIPLY0_331 (a1,joint->node[0].body->R,anchor1);
  94. dCROSS (info->J1a,=,a1,axis);
  95. dCROSS (info->J1a+s,=,a1,q1);
  96. dCROSS (info->J1a+2*s,=,a1,q2);
  97. if (joint->node[1].body) {
  98. for (i=0; i<3; i++) info->J2l[i] = -axis[i];
  99. for (i=0; i<3; i++) info->J2l[s+i] = -q1[i];
  100. for (i=0; i<3; i++) info->J2l[2*s+i] = -q2[i];
  101. dMULTIPLY0_331 (a2,joint->node[1].body->R,anchor2);
  102. dCROSS (info->J2a,= -,a2,axis);
  103. dCROSS (info->J2a+s,= -,a2,q1);
  104. dCROSS (info->J2a+2*s,= -,a2,q2);
  105. }
  106. // set right hand side - measure error along (axis,q1,q2)
  107. dReal k1 = info->fps * erp1;
  108. dReal k = info->fps * info->erp;
  109. for (i=0; i<3; i++) a1[i] += joint->node[0].body->pos[i];
  110. if (joint->node[1].body) {
  111. for (i=0; i<3; i++) a2[i] += joint->node[1].body->pos[i];
  112. info->c[0] = k1 * (dDOT(axis,a2) - dDOT(axis,a1));
  113. info->c[1] = k * (dDOT(q1,a2) - dDOT(q1,a1));
  114. info->c[2] = k * (dDOT(q2,a2) - dDOT(q2,a1));
  115. }
  116. else {
  117. info->c[0] = k1 * (dDOT(axis,anchor2) - dDOT(axis,a1));
  118. info->c[1] = k * (dDOT(q1,anchor2) - dDOT(q1,a1));
  119. info->c[2] = k * (dDOT(q2,anchor2) - dDOT(q2,a1));
  120. }
  121. }
  122. // set three orientation rows in the constraint equation, and the
  123. // corresponding right hand side.
  124. static void setFixedOrientation(dxJoint *joint, dxJoint::Info2 *info, dQuaternion qrel, int start_row)
  125. {
  126. int s = info->rowskip;
  127. int start_index = start_row * s;
  128. // 3 rows to make body rotations equal
  129. info->J1a[start_index] = 1;
  130. info->J1a[start_index + s + 1] = 1;
  131. info->J1a[start_index + s*2+2] = 1;
  132. if (joint->node[1].body) {
  133. info->J2a[start_index] = -1;
  134. info->J2a[start_index + s+1] = -1;
  135. info->J2a[start_index + s*2+2] = -1;
  136. }
  137. // compute the right hand side. the first three elements will result in
  138. // relative angular velocity of the two bodies - this is set to bring them
  139. // back into alignment. the correcting angular velocity is
  140. // |angular_velocity| = angle/time = erp*theta / stepsize
  141. // = (erp*fps) * theta
  142. // angular_velocity = |angular_velocity| * u
  143. // = (erp*fps) * theta * u
  144. // where rotation along unit length axis u by theta brings body 2's frame
  145. // to qrel with respect to body 1's frame. using a small angle approximation
  146. // for sin(), this gives
  147. // angular_velocity = (erp*fps) * 2 * v
  148. // where the quaternion of the relative rotation between the two bodies is
  149. // q = [cos(theta/2) sin(theta/2)*u] = [s v]
  150. // get qerr = relative rotation (rotation error) between two bodies
  151. dQuaternion qerr,e;
  152. if (joint->node[1].body) {
  153. dQuaternion qq;
  154. dQMultiply1 (qq,joint->node[0].body->q,joint->node[1].body->q);
  155. dQMultiply2 (qerr,qq,qrel);
  156. }
  157. else {
  158. dQMultiply3 (qerr,joint->node[0].body->q,qrel);
  159. }
  160. if (qerr[0] < 0) {
  161. qerr[1] = -qerr[1]; // adjust sign of qerr to make theta small
  162. qerr[2] = -qerr[2];
  163. qerr[3] = -qerr[3];
  164. }
  165. dMULTIPLY0_331 (e,joint->node[0].body->R,qerr+1); // @@@ bad SIMD padding!
  166. dReal k = info->fps * info->erp;
  167. info->c[start_row] = 2*k * e[0];
  168. info->c[start_row+1] = 2*k * e[1];
  169. info->c[start_row+2] = 2*k * e[2];
  170. }
  171. // compute anchor points relative to bodies
  172. static void setAnchors (dxJoint *j, dReal x, dReal y, dReal z,
  173. dVector3 anchor1, dVector3 anchor2)
  174. {
  175. if (j->node[0].body) {
  176. dReal q[4];
  177. q[0] = x - j->node[0].body->pos[0];
  178. q[1] = y - j->node[0].body->pos[1];
  179. q[2] = z - j->node[0].body->pos[2];
  180. q[3] = 0;
  181. dMULTIPLY1_331 (anchor1,j->node[0].body->R,q);
  182. if (j->node[1].body) {
  183. q[0] = x - j->node[1].body->pos[0];
  184. q[1] = y - j->node[1].body->pos[1];
  185. q[2] = z - j->node[1].body->pos[2];
  186. q[3] = 0;
  187. dMULTIPLY1_331 (anchor2,j->node[1].body->R,q);
  188. }
  189. else {
  190. anchor2[0] = x;
  191. anchor2[1] = y;
  192. anchor2[2] = z;
  193. }
  194. }
  195. anchor1[3] = 0;
  196. anchor2[3] = 0;
  197. }
  198. // compute axes relative to bodies. either axis1 or axis2 can be 0.
  199. static void setAxes (dxJoint *j, dReal x, dReal y, dReal z,
  200. dVector3 axis1, dVector3 axis2)
  201. {
  202. if (j->node[0].body) {
  203. dReal q[4];
  204. q[0] = x;
  205. q[1] = y;
  206. q[2] = z;
  207. q[3] = 0;
  208. dNormalize3 (q);
  209. if (axis1) {
  210. dMULTIPLY1_331 (axis1,j->node[0].body->R,q);
  211. axis1[3] = 0;
  212. }
  213. if (axis2) {
  214. if (j->node[1].body) {
  215. dMULTIPLY1_331 (axis2,j->node[1].body->R,q);
  216. }
  217. else {
  218. axis2[0] = x;
  219. axis2[1] = y;
  220. axis2[2] = z;
  221. }
  222. axis2[3] = 0;
  223. }
  224. }
  225. }
  226. static void getAnchor (dxJoint *j, dVector3 result, dVector3 anchor1)
  227. {
  228. if (j->node[0].body) {
  229. dMULTIPLY0_331 (result,j->node[0].body->R,anchor1);
  230. result[0] += j->node[0].body->pos[0];
  231. result[1] += j->node[0].body->pos[1];
  232. result[2] += j->node[0].body->pos[2];
  233. }
  234. }
  235. static void getAnchor2 (dxJoint *j, dVector3 result, dVector3 anchor2)
  236. {
  237. if (j->node[1].body) {
  238. dMULTIPLY0_331 (result,j->node[1].body->R,anchor2);
  239. result[0] += j->node[1].body->pos[0];
  240. result[1] += j->node[1].body->pos[1];
  241. result[2] += j->node[1].body->pos[2];
  242. }
  243. else {
  244. result[0] = anchor2[0];
  245. result[1] = anchor2[1];
  246. result[2] = anchor2[2];
  247. }
  248. }
  249. static void getAxis (dxJoint *j, dVector3 result, dVector3 axis1)
  250. {
  251. if (j->node[0].body) {
  252. dMULTIPLY0_331 (result,j->node[0].body->R,axis1);
  253. }
  254. }
  255. static void getAxis2 (dxJoint *j, dVector3 result, dVector3 axis2)
  256. {
  257. if (j->node[1].body) {
  258. dMULTIPLY0_331 (result,j->node[1].body->R,axis2);
  259. }
  260. else {
  261. result[0] = axis2[0];
  262. result[1] = axis2[1];
  263. result[2] = axis2[2];
  264. }
  265. }
  266. static dReal getHingeAngleFromRelativeQuat (dQuaternion qrel, dVector3 axis)
  267. {
  268. // the angle between the two bodies is extracted from the quaternion that
  269. // represents the relative rotation between them. recall that a quaternion
  270. // q is:
  271. // [s,v] = [ cos(theta/2) , sin(theta/2) * u ]
  272. // where s is a scalar and v is a 3-vector. u is a unit length axis and
  273. // theta is a rotation along that axis. we can get theta/2 by:
  274. // theta/2 = atan2 ( sin(theta/2) , cos(theta/2) )
  275. // but we can't get sin(theta/2) directly, only its absolute value, i.e.:
  276. // |v| = |sin(theta/2)| * |u|
  277. // = |sin(theta/2)|
  278. // using this value will have a strange effect. recall that there are two
  279. // quaternion representations of a given rotation, q and -q. typically as
  280. // a body rotates along the axis it will go through a complete cycle using
  281. // one representation and then the next cycle will use the other
  282. // representation. this corresponds to u pointing in the direction of the
  283. // hinge axis and then in the opposite direction. the result is that theta
  284. // will appear to go "backwards" every other cycle. here is a fix: if u
  285. // points "away" from the direction of the hinge (motor) axis (i.e. more
  286. // than 90 degrees) then use -q instead of q. this represents the same
  287. // rotation, but results in the cos(theta/2) value being sign inverted.
  288. // extract the angle from the quaternion. cost2 = cos(theta/2),
  289. // sint2 = |sin(theta/2)|
  290. dReal cost2 = qrel[0];
  291. dReal sint2 = dSqrt (qrel[1]*qrel[1]+qrel[2]*qrel[2]+qrel[3]*qrel[3]);
  292. dReal theta = (dDOT(qrel+1,axis) >= 0) ? // @@@ padding assumptions
  293. (2 * dAtan2(sint2,cost2)) : // if u points in direction of axis
  294. (2 * dAtan2(sint2,-cost2)); // if u points in opposite direction
  295. // the angle we get will be between 0..2*pi, but we want to return angles
  296. // between -pi..pi
  297. if (theta > M_PI) theta -= 2*M_PI;
  298. // the angle we've just extracted has the wrong sign
  299. theta = -theta;
  300. return theta;
  301. }
  302. // given two bodies (body1,body2), the hinge axis that they are connected by
  303. // w.r.t. body1 (axis), and the initial relative orientation between them
  304. // (q_initial), return the relative rotation angle. the initial relative
  305. // orientation corresponds to an angle of zero. if body2 is 0 then measure the
  306. // angle between body1 and the static frame.
  307. //
  308. // this will not return the correct angle if the bodies rotate along any axis
  309. // other than the given hinge axis.
  310. static dReal getHingeAngle (dxBody *body1, dxBody *body2, dVector3 axis,
  311. dQuaternion q_initial)
  312. {
  313. // get qrel = relative rotation between the two bodies
  314. dQuaternion qrel;
  315. if (body2) {
  316. dQuaternion qq;
  317. dQMultiply1 (qq,body1->q,body2->q);
  318. dQMultiply2 (qrel,qq,q_initial);
  319. }
  320. else {
  321. // pretend body2->q is the identity
  322. dQMultiply3 (qrel,body1->q,q_initial);
  323. }
  324. return getHingeAngleFromRelativeQuat (qrel,axis);
  325. }
  326. //****************************************************************************
  327. // dxJointLimitMotor
  328. void dxJointLimitMotor::init (dxWorld *world)
  329. {
  330. vel = 0;
  331. fmax = 0;
  332. lostop = -dInfinity;
  333. histop = dInfinity;
  334. fudge_factor = 1;
  335. normal_cfm = world->global_cfm;
  336. stop_erp = world->global_erp;
  337. stop_cfm = world->global_cfm;
  338. bounce = 0;
  339. limit = 0;
  340. limit_err = 0;
  341. }
  342. void dxJointLimitMotor::set (int num, dReal value)
  343. {
  344. switch (num) {
  345. case dParamLoStop:
  346. if (value <= histop) lostop = value;
  347. break;
  348. case dParamHiStop:
  349. if (value >= lostop) histop = value;
  350. break;
  351. case dParamVel:
  352. vel = value;
  353. break;
  354. case dParamFMax:
  355. if (value >= 0) fmax = value;
  356. break;
  357. case dParamFudgeFactor:
  358. if (value >= 0 && value <= 1) fudge_factor = value;
  359. break;
  360. case dParamBounce:
  361. bounce = value;
  362. break;
  363. case dParamCFM:
  364. normal_cfm = value;
  365. break;
  366. case dParamStopERP:
  367. stop_erp = value;
  368. break;
  369. case dParamStopCFM:
  370. stop_cfm = value;
  371. break;
  372. }
  373. }
  374. dReal dxJointLimitMotor::get (int num)
  375. {
  376. switch (num) {
  377. case dParamLoStop: return lostop;
  378. case dParamHiStop: return histop;
  379. case dParamVel: return vel;
  380. case dParamFMax: return fmax;
  381. case dParamFudgeFactor: return fudge_factor;
  382. case dParamBounce: return bounce;
  383. case dParamCFM: return normal_cfm;
  384. case dParamStopERP: return stop_erp;
  385. case dParamStopCFM: return stop_cfm;
  386. default: return 0;
  387. }
  388. }
  389. int dxJointLimitMotor::testRotationalLimit (dReal angle)
  390. {
  391. if (angle <= lostop) {
  392. limit = 1;
  393. limit_err = angle - lostop;
  394. return 1;
  395. }
  396. else if (angle >= histop) {
  397. limit = 2;
  398. limit_err = angle - histop;
  399. return 1;
  400. }
  401. else {
  402. limit = 0;
  403. return 0;
  404. }
  405. }
  406. int dxJointLimitMotor::addLimot (dxJoint *joint,
  407. dxJoint::Info2 *info, int row,
  408. dVector3 ax1, int rotational)
  409. {
  410. int srow = row * info->rowskip;
  411. // if the joint is powered, or has joint limits, add in the extra row
  412. int powered = fmax > 0;
  413. if (powered || limit) {
  414. dReal *J1 = rotational ? info->J1a : info->J1l;
  415. dReal *J2 = rotational ? info->J2a : info->J2l;
  416. J1[srow+0] = ax1[0];
  417. J1[srow+1] = ax1[1];
  418. J1[srow+2] = ax1[2];
  419. if (joint->node[1].body) {
  420. J2[srow+0] = -ax1[0];
  421. J2[srow+1] = -ax1[1];
  422. J2[srow+2] = -ax1[2];
  423. }
  424. // linear limot torque decoupling step:
  425. //
  426. // if this is a linear limot (e.g. from a slider), we have to be careful
  427. // that the linear constraint forces (+/- ax1) applied to the two bodies
  428. // do not create a torque couple. in other words, the points that the
  429. // constraint force is applied at must lie along the same ax1 axis.
  430. // a torque couple will result in powered or limited slider-jointed free
  431. // bodies from gaining angular momentum.
  432. // the solution used here is to apply the constraint forces at the point
  433. // halfway between the body centers. there is no penalty (other than an
  434. // extra tiny bit of computation) in doing this adjustment. note that we
  435. // only need to do this if the constraint connects two bodies.
  436. dVector3 ltd; // Linear Torque Decoupling vector (a torque)
  437. if (!rotational && joint->node[1].body) {
  438. dVector3 c;
  439. c[0]=REAL(0.5)*(joint->node[1].body->pos[0]-joint->node[0].body->pos[0]);
  440. c[1]=REAL(0.5)*(joint->node[1].body->pos[1]-joint->node[0].body->pos[1]);
  441. c[2]=REAL(0.5)*(joint->node[1].body->pos[2]-joint->node[0].body->pos[2]);
  442. dCROSS (ltd,=,c,ax1);
  443. info->J1a[srow+0] = ltd[0];
  444. info->J1a[srow+1] = ltd[1];
  445. info->J1a[srow+2] = ltd[2];
  446. info->J2a[srow+0] = ltd[0];
  447. info->J2a[srow+1] = ltd[1];
  448. info->J2a[srow+2] = ltd[2];
  449. }
  450. // if we're limited low and high simultaneously, the joint motor is
  451. // ineffective
  452. if (limit && (lostop == histop)) powered = 0;
  453. if (powered) {
  454. info->cfm[row] = normal_cfm;
  455. if (! limit) {
  456. info->c[row] = vel;
  457. info->lo[row] = -fmax;
  458. info->hi[row] = fmax;
  459. }
  460. else {
  461. // the joint is at a limit, AND is being powered. if the joint is
  462. // being powered into the limit then we apply the maximum motor force
  463. // in that direction, because the motor is working against the
  464. // immovable limit. if the joint is being powered away from the limit
  465. // then we have problems because actually we need *two* lcp
  466. // constraints to handle this case. so we fake it and apply some
  467. // fraction of the maximum force. the fraction to use can be set as
  468. // a fudge factor.
  469. dReal fm = fmax;
  470. if (vel > 0) fm = -fm;
  471. // if we're powering away from the limit, apply the fudge factor
  472. if ((limit==1 && vel > 0) || (limit==2 && vel < 0)) fm *= fudge_factor;
  473. if (rotational) {
  474. dBodyAddTorque (joint->node[0].body,-fm*ax1[0],-fm*ax1[1],
  475. -fm*ax1[2]);
  476. if (joint->node[1].body)
  477. dBodyAddTorque (joint->node[1].body,fm*ax1[0],fm*ax1[1],fm*ax1[2]);
  478. }
  479. else {
  480. dBodyAddForce (joint->node[0].body,-fm*ax1[0],-fm*ax1[1],-fm*ax1[2]);
  481. if (joint->node[1].body) {
  482. dBodyAddForce (joint->node[1].body,fm*ax1[0],fm*ax1[1],fm*ax1[2]);
  483. // linear limot torque decoupling step: refer to above discussion
  484. dBodyAddTorque (joint->node[0].body,-fm*ltd[0],-fm*ltd[1],
  485. -fm*ltd[2]);
  486. dBodyAddTorque (joint->node[1].body,-fm*ltd[0],-fm*ltd[1],
  487. -fm*ltd[2]);
  488. }
  489. }
  490. }
  491. }
  492. if (limit) {
  493. dReal k = info->fps * stop_erp;
  494. info->c[row] = -k * limit_err;
  495. info->cfm[row] = stop_cfm;
  496. if (lostop == histop) {
  497. // limited low and high simultaneously
  498. info->lo[row] = -dInfinity;
  499. info->hi[row] = dInfinity;
  500. }
  501. else {
  502. if (limit == 1) {
  503. // low limit
  504. info->lo[row] = 0;
  505. info->hi[row] = dInfinity;
  506. }
  507. else {
  508. // high limit
  509. info->lo[row] = -dInfinity;
  510. info->hi[row] = 0;
  511. }
  512. // deal with bounce
  513. if (bounce > 0) {
  514. // calculate joint velocity
  515. dReal vel;
  516. if (rotational) {
  517. vel = dDOT(joint->node[0].body->avel,ax1);
  518. if (joint->node[1].body)
  519. vel -= dDOT(joint->node[1].body->avel,ax1);
  520. }
  521. else {
  522. vel = dDOT(joint->node[0].body->lvel,ax1);
  523. if (joint->node[1].body)
  524. vel -= dDOT(joint->node[1].body->lvel,ax1);
  525. }
  526. // only apply bounce if the velocity is incoming, and if the
  527. // resulting c[] exceeds what we already have.
  528. if (limit == 1) {
  529. // low limit
  530. if (vel < 0) {
  531. dReal newc = -bounce * vel;
  532. if (newc > info->c[row]) info->c[row] = newc;
  533. }
  534. }
  535. else {
  536. // high limit - all those computations are reversed
  537. if (vel > 0) {
  538. dReal newc = -bounce * vel;
  539. if (newc < info->c[row]) info->c[row] = newc;
  540. }
  541. }
  542. }
  543. }
  544. }
  545. return 1;
  546. }
  547. else return 0;
  548. }
  549. //****************************************************************************
  550. // ball and socket
  551. static void ballInit (dxJointBall *j)
  552. {
  553. dSetZero (j->anchor1,4);
  554. dSetZero (j->anchor2,4);
  555. }
  556. static void ballGetInfo1 (dxJointBall *j, dxJoint::Info1 *info)
  557. {
  558. info->m = 3;
  559. info->nub = 3;
  560. }
  561. static void ballGetInfo2 (dxJointBall *joint, dxJoint::Info2 *info)
  562. {
  563. setBall (joint,info,joint->anchor1,joint->anchor2);
  564. }
  565. extern "C" void dJointSetBallAnchor (dxJointBall *joint,
  566. dReal x, dReal y, dReal z)
  567. {
  568. dUASSERT(joint,"bad joint argument");
  569. dUASSERT(joint->vtable == &__dball_vtable,"joint is not a ball");
  570. setAnchors (joint,x,y,z,joint->anchor1,joint->anchor2);
  571. }
  572. extern "C" void dJointGetBallAnchor (dxJointBall *joint, dVector3 result)
  573. {
  574. dUASSERT(joint,"bad joint argument");
  575. dUASSERT(result,"bad result argument");
  576. dUASSERT(joint->vtable == &__dball_vtable,"joint is not a ball");
  577. if (joint->flags & dJOINT_REVERSE)
  578. getAnchor2 (joint,result,joint->anchor2);
  579. else
  580. getAnchor (joint,result,joint->anchor1);
  581. }
  582. extern "C" void dJointGetBallAnchor2 (dxJointBall *joint, dVector3 result)
  583. {
  584. dUASSERT(joint,"bad joint argument");
  585. dUASSERT(result,"bad result argument");
  586. dUASSERT(joint->vtable == &__dball_vtable,"joint is not a ball");
  587. if (joint->flags & dJOINT_REVERSE)
  588. getAnchor (joint,result,joint->anchor1);
  589. else
  590. getAnchor2 (joint,result,joint->anchor2);
  591. }
  592. dxJoint::Vtable __dball_vtable = {
  593. sizeof(dxJointBall),
  594. (dxJoint::init_fn*) ballInit,
  595. (dxJoint::getInfo1_fn*) ballGetInfo1,
  596. (dxJoint::getInfo2_fn*) ballGetInfo2,
  597. dJointTypeBall};
  598. //****************************************************************************
  599. // hinge
  600. static void hingeInit (dxJointHinge *j)
  601. {
  602. dSetZero (j->anchor1,4);
  603. dSetZero (j->anchor2,4);
  604. dSetZero (j->axis1,4);
  605. j->axis1[0] = 1;
  606. dSetZero (j->axis2,4);
  607. j->axis2[0] = 1;
  608. dSetZero (j->qrel,4);
  609. j->limot.init (j->world);
  610. }
  611. static void hingeGetInfo1 (dxJointHinge *j, dxJoint::Info1 *info)
  612. {
  613. info->nub = 5;
  614. // see if joint is powered
  615. if (j->limot.fmax > 0)
  616. info->m = 6; // powered hinge needs an extra constraint row
  617. else info->m = 5;
  618. // see if we're at a joint limit.
  619. if ((j->limot.lostop >= -M_PI || j->limot.histop <= M_PI) &&
  620. j->limot.lostop <= j->limot.histop) {
  621. dReal angle = getHingeAngle (j->node[0].body,j->node[1].body,j->axis1,
  622. j->qrel);
  623. if (j->limot.testRotationalLimit (angle)) info->m = 6;
  624. }
  625. }
  626. static void hingeGetInfo2 (dxJointHinge *joint, dxJoint::Info2 *info)
  627. {
  628. // set the three ball-and-socket rows
  629. setBall (joint,info,joint->anchor1,joint->anchor2);
  630. // set the two hinge rows. the hinge axis should be the only unconstrained
  631. // rotational axis, the angular velocity of the two bodies perpendicular to
  632. // the hinge axis should be equal. thus the constraint equations are
  633. // p*w1 - p*w2 = 0
  634. // q*w1 - q*w2 = 0
  635. // where p and q are unit vectors normal to the hinge axis, and w1 and w2
  636. // are the angular velocity vectors of the two bodies.
  637. dVector3 ax1; // length 1 joint axis in global coordinates, from 1st body
  638. dVector3 p,q; // plane space vectors for ax1
  639. dMULTIPLY0_331 (ax1,joint->node[0].body->R,joint->axis1);
  640. dPlaneSpace (ax1,p,q);
  641. int s3=3*info->rowskip;
  642. int s4=4*info->rowskip;
  643. info->J1a[s3+0] = p[0];
  644. info->J1a[s3+1] = p[1];
  645. info->J1a[s3+2] = p[2];
  646. info->J1a[s4+0] = q[0];
  647. info->J1a[s4+1] = q[1];
  648. info->J1a[s4+2] = q[2];
  649. if (joint->node[1].body) {
  650. info->J2a[s3+0] = -p[0];
  651. info->J2a[s3+1] = -p[1];
  652. info->J2a[s3+2] = -p[2];
  653. info->J2a[s4+0] = -q[0];
  654. info->J2a[s4+1] = -q[1];
  655. info->J2a[s4+2] = -q[2];
  656. }
  657. // compute the right hand side of the constraint equation. set relative
  658. // body velocities along p and q to bring the hinge back into alignment.
  659. // if ax1,ax2 are the unit length hinge axes as computed from body1 and
  660. // body2, we need to rotate both bodies along the axis u = (ax1 x ax2).
  661. // if `theta' is the angle between ax1 and ax2, we need an angular velocity
  662. // along u to cover angle erp*theta in one step :
  663. // |angular_velocity| = angle/time = erp*theta / stepsize
  664. // = (erp*fps) * theta
  665. // angular_velocity = |angular_velocity| * (ax1 x ax2) / |ax1 x ax2|
  666. // = (erp*fps) * theta * (ax1 x ax2) / sin(theta)
  667. // ...as ax1 and ax2 are unit length. if theta is smallish,
  668. // theta ~= sin(theta), so
  669. // angular_velocity = (erp*fps) * (ax1 x ax2)
  670. // ax1 x ax2 is in the plane space of ax1, so we project the angular
  671. // velocity to p and q to find the right hand side.
  672. dVector3 ax2,b;
  673. if (joint->node[1].body) {
  674. dMULTIPLY0_331 (ax2,joint->node[1].body->R,joint->axis2);
  675. }
  676. else {
  677. ax2[0] = joint->axis2[0];
  678. ax2[1] = joint->axis2[1];
  679. ax2[2] = joint->axis2[2];
  680. }
  681. dCROSS (b,=,ax1,ax2);
  682. dReal k = info->fps * info->erp;
  683. info->c[3] = k * dDOT(b,p);
  684. info->c[4] = k * dDOT(b,q);
  685. // if the hinge is powered, or has joint limits, add in the stuff
  686. joint->limot.addLimot (joint,info,5,ax1,1);
  687. }
  688. // compute initial relative rotation body1 -> body2, or env -> body1
  689. static void hingeComputeInitialRelativeRotation (dxJointHinge *joint)
  690. {
  691. if (joint->node[0].body) {
  692. if (joint->node[1].body) {
  693. dQMultiply1 (joint->qrel,joint->node[0].body->q,joint->node[1].body->q);
  694. }
  695. else {
  696. // set joint->qrel to the transpose of the first body q
  697. joint->qrel[0] = joint->node[0].body->q[0];
  698. for (int i=1; i<4; i++) joint->qrel[i] = -joint->node[0].body->q[i];
  699. }
  700. }
  701. }
  702. extern "C" void dJointSetHingeAnchor (dxJointHinge *joint,
  703. dReal x, dReal y, dReal z)
  704. {
  705. dUASSERT(joint,"bad joint argument");
  706. dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge");
  707. setAnchors (joint,x,y,z,joint->anchor1,joint->anchor2);
  708. hingeComputeInitialRelativeRotation (joint);
  709. }
  710. extern "C" void dJointSetHingeAxis (dxJointHinge *joint,
  711. dReal x, dReal y, dReal z)
  712. {
  713. dUASSERT(joint,"bad joint argument");
  714. dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge");
  715. setAxes (joint,x,y,z,joint->axis1,joint->axis2);
  716. hingeComputeInitialRelativeRotation (joint);
  717. }
  718. extern "C" void dJointGetHingeAnchor (dxJointHinge *joint, dVector3 result)
  719. {
  720. dUASSERT(joint,"bad joint argument");
  721. dUASSERT(result,"bad result argument");
  722. dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge");
  723. if (joint->flags & dJOINT_REVERSE)
  724. getAnchor2 (joint,result,joint->anchor2);
  725. else
  726. getAnchor (joint,result,joint->anchor1);
  727. }
  728. extern "C" void dJointGetHingeAnchor2 (dxJointHinge *joint, dVector3 result)
  729. {
  730. dUASSERT(joint,"bad joint argument");
  731. dUASSERT(result,"bad result argument");
  732. dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge");
  733. if (joint->flags & dJOINT_REVERSE)
  734. getAnchor (joint,result,joint->anchor1);
  735. else
  736. getAnchor2 (joint,result,joint->anchor2);
  737. }
  738. extern "C" void dJointGetHingeAxis (dxJointHinge *joint, dVector3 result)
  739. {
  740. dUASSERT(joint,"bad joint argument");
  741. dUASSERT(result,"bad result argument");
  742. dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge");
  743. getAxis (joint,result,joint->axis1);
  744. }
  745. extern "C" void dJointSetHingeParam (dxJointHinge *joint,
  746. int parameter, dReal value)
  747. {
  748. dUASSERT(joint,"bad joint argument");
  749. dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge");
  750. joint->limot.set (parameter,value);
  751. }
  752. extern "C" dReal dJointGetHingeParam (dxJointHinge *joint, int parameter)
  753. {
  754. dUASSERT(joint,"bad joint argument");
  755. dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge");
  756. return joint->limot.get (parameter);
  757. }
  758. extern "C" dReal dJointGetHingeAngle (dxJointHinge *joint)
  759. {
  760. dAASSERT(joint);
  761. dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge");
  762. if (joint->node[0].body) {
  763. dReal ang = getHingeAngle (joint->node[0].body,joint->node[1].body,joint->axis1,
  764. joint->qrel);
  765. if (joint->flags & dJOINT_REVERSE)
  766. return -ang;
  767. else
  768. return ang;
  769. }
  770. else return 0;
  771. }
  772. extern "C" dReal dJointGetHingeAngleRate (dxJointHinge *joint)
  773. {
  774. dAASSERT(joint);
  775. dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a Hinge");
  776. if (joint->node[0].body) {
  777. dVector3 axis;
  778. dMULTIPLY0_331 (axis,joint->node[0].body->R,joint->axis1);
  779. dReal rate = dDOT(axis,joint->node[0].body->avel);
  780. if (joint->node[1].body) rate -= dDOT(axis,joint->node[1].body->avel);
  781. if (joint->flags & dJOINT_REVERSE) rate = - rate;
  782. return rate;
  783. }
  784. else return 0;
  785. }
  786. extern "C" void dJointAddHingeTorque (dxJointHinge *joint, dReal torque)
  787. {
  788. dVector3 axis;
  789. dAASSERT(joint);
  790. dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a Hinge");
  791. if (joint->flags & dJOINT_REVERSE)
  792. torque = -torque;
  793. getAxis (joint,axis,joint->axis1);
  794. axis[0] *= torque;
  795. axis[1] *= torque;
  796. axis[2] *= torque;
  797. if (joint->node[0].body != 0)
  798. dBodyAddTorque (joint->node[0].body, axis[0], axis[1], axis[2]);
  799. if (joint->node[1].body != 0)
  800. dBodyAddTorque(joint->node[1].body, -axis[0], -axis[1], -axis[2]);
  801. }
  802. dxJoint::Vtable __dhinge_vtable = {
  803. sizeof(dxJointHinge),
  804. (dxJoint::init_fn*) hingeInit,
  805. (dxJoint::getInfo1_fn*) hingeGetInfo1,
  806. (dxJoint::getInfo2_fn*) hingeGetInfo2,
  807. dJointTypeHinge};
  808. //****************************************************************************
  809. // slider
  810. static void sliderInit (dxJointSlider *j)
  811. {
  812. dSetZero (j->axis1,4);
  813. j->axis1[0] = 1;
  814. dSetZero (j->qrel,4);
  815. dSetZero (j->offset,4);
  816. j->limot.init (j->world);
  817. }
  818. extern "C" dReal dJointGetSliderPosition (dxJointSlider *joint)
  819. {
  820. dUASSERT(joint,"bad joint argument");
  821. dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider");
  822. // get axis1 in global coordinates
  823. dVector3 ax1,q;
  824. dMULTIPLY0_331 (ax1,joint->node[0].body->R,joint->axis1);
  825. if (joint->node[1].body) {
  826. // get body2 + offset point in global coordinates
  827. dMULTIPLY0_331 (q,joint->node[1].body->R,joint->offset);
  828. for (int i=0; i<3; i++) q[i] = joint->node[0].body->pos[i] - q[i] -
  829. joint->node[1].body->pos[i];
  830. }
  831. else {
  832. for (int i=0; i<3; i++) q[i] = joint->node[0].body->pos[i] -
  833. joint->offset[i];
  834. }
  835. return dDOT(ax1,q);
  836. }
  837. extern "C" dReal dJointGetSliderPositionRate (dxJointSlider *joint)
  838. {
  839. dUASSERT(joint,"bad joint argument");
  840. dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider");
  841. // get axis1 in global coordinates
  842. dVector3 ax1;
  843. dMULTIPLY0_331 (ax1,joint->node[0].body->R,joint->axis1);
  844. if (joint->node[1].body) {
  845. return dDOT(ax1,joint->node[0].body->lvel) -
  846. dDOT(ax1,joint->node[1].body->lvel);
  847. }
  848. else {
  849. return dDOT(ax1,joint->node[0].body->lvel);
  850. }
  851. }
  852. static void sliderGetInfo1 (dxJointSlider *j, dxJoint::Info1 *info)
  853. {
  854. info->nub = 5;
  855. // see if joint is powered
  856. if (j->limot.fmax > 0)
  857. info->m = 6; // powered slider needs an extra constraint row
  858. else info->m = 5;
  859. // see if we're at a joint limit.
  860. j->limot.limit = 0;
  861. if ((j->limot.lostop > -dInfinity || j->limot.histop < dInfinity) &&
  862. j->limot.lostop <= j->limot.histop) {
  863. // measure joint position
  864. dReal pos = dJointGetSliderPosition (j);
  865. if (pos <= j->limot.lostop) {
  866. j->limot.limit = 1;
  867. j->limot.limit_err = pos - j->limot.lostop;
  868. info->m = 6;
  869. }
  870. else if (pos >= j->limot.histop) {
  871. j->limot.limit = 2;
  872. j->limot.limit_err = pos - j->limot.histop;
  873. info->m = 6;
  874. }
  875. }
  876. }
  877. static void sliderGetInfo2 (dxJointSlider *joint, dxJoint::Info2 *info)
  878. {
  879. int i,s = info->rowskip;
  880. int s2=2*s,s3=3*s,s4=4*s;
  881. // pull out pos and R for both bodies. also get the `connection'
  882. // vector pos2-pos1.
  883. dReal *pos1,*pos2,*R1,*R2;
  884. dVector3 c;
  885. pos1 = joint->node[0].body->pos;
  886. R1 = joint->node[0].body->R;
  887. if (joint->node[1].body) {
  888. pos2 = joint->node[1].body->pos;
  889. R2 = joint->node[1].body->R;
  890. for (i=0; i<3; i++) c[i] = pos2[i] - pos1[i];
  891. }
  892. else {
  893. pos2 = 0;
  894. R2 = 0;
  895. }
  896. // 3 rows to make body rotations equal
  897. setFixedOrientation(joint, info, joint->qrel, 0);
  898. // remaining two rows. we want: vel2 = vel1 + w1 x c ... but this would
  899. // result in three equations, so we project along the planespace vectors
  900. // so that sliding along the slider axis is disregarded. for symmetry we
  901. // also substitute (w1+w2)/2 for w1, as w1 is supposed to equal w2.
  902. dVector3 ax1; // joint axis in global coordinates (unit length)
  903. dVector3 p,q; // plane space of ax1
  904. dMULTIPLY0_331 (ax1,R1,joint->axis1);
  905. dPlaneSpace (ax1,p,q);
  906. if (joint->node[1].body) {
  907. dVector3 tmp;
  908. dCROSS (tmp, = REAL(0.5) * ,c,p);
  909. for (i=0; i<3; i++) info->J2a[s3+i] = tmp[i];
  910. for (i=0; i<3; i++) info->J2a[s3+i] = tmp[i];
  911. dCROSS (tmp, = REAL(0.5) * ,c,q);
  912. for (i=0; i<3; i++) info->J2a[s4+i] = tmp[i];
  913. for (i=0; i<3; i++) info->J2a[s4+i] = tmp[i];
  914. for (i=0; i<3; i++) info->J2l[s3+i] = -p[i];
  915. for (i=0; i<3; i++) info->J2l[s4+i] = -q[i];
  916. }
  917. for (i=0; i<3; i++) info->J1l[s3+i] = p[i];
  918. for (i=0; i<3; i++) info->J1l[s4+i] = q[i];
  919. // compute last two elements of right hand side. we want to align the offset
  920. // point (in body 2's frame) with the center of body 1.
  921. dReal k = info->fps * info->erp;
  922. if (joint->node[1].body) {
  923. dVector3 ofs; // offset point in global coordinates
  924. dMULTIPLY0_331 (ofs,R2,joint->offset);
  925. for (i=0; i<3; i++) c[i] += ofs[i];
  926. info->c[3] = k * dDOT(p,c);
  927. info->c[4] = k * dDOT(q,c);
  928. }
  929. else {
  930. dVector3 ofs; // offset point in global coordinates
  931. for (i=0; i<3; i++) ofs[i] = joint->offset[i] - pos1[i];
  932. info->c[3] = k * dDOT(p,ofs);
  933. info->c[4] = k * dDOT(q,ofs);
  934. }
  935. // if the slider is powered, or has joint limits, add in the extra row
  936. joint->limot.addLimot (joint,info,5,ax1,0);
  937. }
  938. extern "C" void dJointSetSliderAxis (dxJointSlider *joint,
  939. dReal x, dReal y, dReal z)
  940. {
  941. int i;
  942. dUASSERT(joint,"bad joint argument");
  943. dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider");
  944. setAxes (joint,x,y,z,joint->axis1,0);
  945. // compute initial relative rotation body1 -> body2, or env -> body1
  946. // also compute center of body1 w.r.t body 2
  947. if (joint->node[1].body) {
  948. dQMultiply1 (joint->qrel,joint->node[0].body->q,joint->node[1].body->q);
  949. dVector3 c;
  950. for (i=0; i<3; i++)
  951. c[i] = joint->node[0].body->pos[i] - joint->node[1].body->pos[i];
  952. dMULTIPLY1_331 (joint->offset,joint->node[1].body->R,c);
  953. }
  954. else {
  955. // set joint->qrel to the transpose of the first body's q
  956. joint->qrel[0] = joint->node[0].body->q[0];
  957. for (i=1; i<4; i++) joint->qrel[i] = -joint->node[0].body->q[i];
  958. for (i=0; i<3; i++) joint->offset[i] = joint->node[0].body->pos[i];
  959. }
  960. }
  961. extern "C" void dJointGetSliderAxis (dxJointSlider *joint, dVector3 result)
  962. {
  963. dUASSERT(joint,"bad joint argument");
  964. dUASSERT(result,"bad result argument");
  965. dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider");
  966. getAxis (joint,result,joint->axis1);
  967. }
  968. extern "C" void dJointSetSliderParam (dxJointSlider *joint,
  969. int parameter, dReal value)
  970. {
  971. dUASSERT(joint,"bad joint argument");
  972. dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider");
  973. joint->limot.set (parameter,value);
  974. }
  975. extern "C" dReal dJointGetSliderParam (dxJointSlider *joint, int parameter)
  976. {
  977. dUASSERT(joint,"bad joint argument");
  978. dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider");
  979. return joint->limot.get (parameter);
  980. }
  981. extern "C" void dJointAddSliderForce (dxJointSlider *joint, dReal force)
  982. {
  983. dVector3 axis;
  984. dUASSERT(joint,"bad joint argument");
  985. dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider");
  986. if (joint->flags & dJOINT_REVERSE)
  987. force -= force;
  988. getAxis (joint,axis,joint->axis1);
  989. axis[0] *= force;
  990. axis[1] *= force;
  991. axis[2] *= force;
  992. if (joint->node[0].body != 0)
  993. dBodyAddForce (joint->node[0].body,axis[0],axis[1],axis[2]);
  994. if (joint->node[1].body != 0)
  995. dBodyAddForce(joint->node[1].body, -axis[0], -axis[1], -axis[2]);
  996. }
  997. dxJoint::Vtable __dslider_vtable = {
  998. sizeof(dxJointSlider),
  999. (dxJoint::init_fn*) sliderInit,
  1000. (dxJoint::getInfo1_fn*) sliderGetInfo1,
  1001. (dxJoint::getInfo2_fn*) sliderGetInfo2,
  1002. dJointTypeSlider};
  1003. //****************************************************************************
  1004. // contact
  1005. static void contactInit (dxJointContact *j)
  1006. {
  1007. // default frictionless contact. hmmm, this info gets overwritten straight
  1008. // away anyway, so why bother?
  1009. #if 0 /* so don't bother ;) */
  1010. j->contact.surface.mode = 0;
  1011. j->contact.surface.mu = 0;
  1012. dSetZero (j->contact.geom.pos,4);
  1013. dSetZero (j->contact.geom.normal,4);
  1014. j->contact.geom.depth = 0;
  1015. #endif
  1016. }
  1017. static void contactGetInfo1 (dxJointContact *j, dxJoint::Info1 *info)
  1018. {
  1019. // make sure mu's >= 0, then calculate number of constraint rows and number
  1020. // of unbounded rows.
  1021. int m = 1, nub=0;
  1022. if (j->contact.surface.mu < 0) j->contact.surface.mu = 0;
  1023. if (j->contact.surface.mode & dContactMu2) {
  1024. if (j->contact.surface.mu > 0) m++;
  1025. if (j->contact.surface.mu2 < 0) j->contact.surface.mu2 = 0;
  1026. if (j->contact.surface.mu2 > 0) m++;
  1027. if (j->contact.surface.mu == dInfinity) nub ++;
  1028. if (j->contact.surface.mu2 == dInfinity) nub ++;
  1029. }
  1030. else {
  1031. if (j->contact.surface.mu > 0) m += 2;
  1032. if (j->contact.surface.mu == dInfinity) nub += 2;
  1033. }
  1034. j->the_m = m;
  1035. info->m = m;
  1036. info->nub = nub;
  1037. }
  1038. static void contactGetInfo2 (dxJointContact *j, dxJoint::Info2 *info)
  1039. {
  1040. int i,s = info->rowskip;
  1041. int s2 = 2*s;
  1042. // get normal, with sign adjusted for body1/body2 polarity
  1043. dVector3 normal;
  1044. if (j->flags & dJOINT_REVERSE) {
  1045. normal[0] = - j->contact.geom.normal[0];
  1046. normal[1] = - j->contact.geom.normal[1];
  1047. normal[2] = - j->contact.geom.normal[2];
  1048. }
  1049. else {
  1050. normal[0] = j->contact.geom.normal[0];
  1051. normal[1] = j->contact.geom.normal[1];
  1052. normal[2] = j->contact.geom.normal[2];
  1053. }
  1054. normal[3] = 0; // @@@ hmmm
  1055. // c1,c2 = contact points with respect to body PORs
  1056. dVector3 c1,c2;
  1057. for (i=0; i<3; i++) c1[i] = j->contact.geom.pos[i] - j->node[0].body->pos[i];
  1058. // set jacobian for normal
  1059. info->J1l[0] = normal[0];
  1060. info->J1l[1] = normal[1];
  1061. info->J1l[2] = normal[2];
  1062. dCROSS (info->J1a,=,c1,normal);
  1063. if (j->node[1].body) {
  1064. for (i=0; i<3; i++) c2[i] = j->contact.geom.pos[i] -
  1065. j->node[1].body->pos[i];
  1066. info->J2l[0] = -normal[0];
  1067. info->J2l[1] = -normal[1];
  1068. info->J2l[2] = -normal[2];
  1069. dCROSS (info->J2a,= -,c2,normal);
  1070. }
  1071. // set right hand side and cfm value for normal
  1072. dReal erp = info->erp;
  1073. if (j->contact.surface.mode & dContactSoftERP)
  1074. erp = j->contact.surface.soft_erp;
  1075. dReal k = info->fps * erp;
  1076. info->c[0] = k*j->contact.geom.depth;
  1077. if (j->contact.surface.mode & dContactSoftCFM)
  1078. info->cfm[0] = j->contact.surface.soft_cfm;
  1079. // deal with bounce
  1080. if (j->contact.surface.mode & dContactBounce) {
  1081. // calculate outgoing velocity (-ve for incoming contact)
  1082. dReal outgoing = dDOT(info->J1l,j->node[0].body->lvel) +
  1083. dDOT(info->J1a,j->node[0].body->avel);
  1084. if (j->node[1].body) {
  1085. outgoing += dDOT(info->J2l,j->node[1].body->lvel) +
  1086. dDOT(info->J2a,j->node[1].body->avel);
  1087. }
  1088. // only apply bounce if the outgoing velocity is greater than the
  1089. // threshold, and if the resulting c[0] exceeds what we already have.
  1090. if (j->contact.surface.bounce_vel >= 0 &&
  1091. (-outgoing) > j->contact.surface.bounce_vel) {
  1092. dReal newc = - j->contact.surface.bounce * outgoing;
  1093. if (newc > info->c[0]) info->c[0] = newc;
  1094. }
  1095. }
  1096. // set LCP limits for normal
  1097. info->lo[0] = 0;
  1098. info->hi[0] = dInfinity;
  1099. // now do jacobian for tangential forces
  1100. dVector3 t1,t2; // two vectors tangential to normal
  1101. // first friction direction
  1102. if (j->the_m >= 2) {
  1103. if (j->contact.surface.mode & dContactFDir1) { // use fdir1 ?
  1104. t1[0] = j->contact.fdir1[0];
  1105. t1[1] = j->contact.fdir1[1];
  1106. t1[2] = j->contact.fdir1[2];
  1107. dCROSS (t2,=,normal,t1);
  1108. }
  1109. else {
  1110. dPlaneSpace (normal,t1,t2);
  1111. }
  1112. info->J1l[s+0] = t1[0];
  1113. info->J1l[s+1] = t1[1];
  1114. info->J1l[s+2] = t1[2];
  1115. dCROSS (info->J1a+s,=,c1,t1);
  1116. if (j->node[1].body) {
  1117. info->J2l[s+0] = -t1[0];
  1118. info->J2l[s+1] = -t1[1];
  1119. info->J2l[s+2] = -t1[2];
  1120. dCROSS (info->J2a+s,= -,c2,t1);
  1121. }
  1122. // set right hand side
  1123. if (j->contact.surface.mode & dContactMotion1) {
  1124. info->c[1] = j->contact.surface.motion1;
  1125. }
  1126. // set LCP bounds and friction index. this depends on the approximation
  1127. // mode
  1128. info->lo[1] = -j->contact.surface.mu;
  1129. info->hi[1] = j->contact.surface.mu;
  1130. if (j->contact.surface.mode & dContactApprox1_1) info->findex[1] = 0;
  1131. // set slip (constraint force mixing)
  1132. if (j->contact.surface.mode & dContactSlip1)
  1133. info->cfm[1] = j->contact.surface.slip1;
  1134. }
  1135. // second friction direction
  1136. if (j->the_m >= 3) {
  1137. info->J1l[s2+0] = t2[0];
  1138. info->J1l[s2+1] = t2[1];
  1139. info->J1l[s2+2] = t2[2];
  1140. dCROSS (info->J1a+s2,=,c1,t2);
  1141. if (j->node[1].body) {
  1142. info->J2l[s2+0] = -t2[0];
  1143. info->J2l[s2+1] = -t2[1];
  1144. info->J2l[s2+2] = -t2[2];
  1145. dCROSS (info->J2a+s2,= -,c2,t2);
  1146. }
  1147. // set right hand side
  1148. if (j->contact.surface.mode & dContactMotion2) {
  1149. info->c[2] = j->contact.surface.motion2;
  1150. }
  1151. // set LCP bounds and friction index. this depends on the approximation
  1152. // mode
  1153. if (j->contact.surface.mode & dContactMu2) {
  1154. info->lo[2] = -j->contact.surface.mu2;
  1155. info->hi[2] = j->contact.surface.mu2;
  1156. }
  1157. else {
  1158. info->lo[2] = -j->contact.surface.mu;
  1159. info->hi[2] = j->contact.surface.mu;
  1160. }
  1161. if (j->contact.surface.mode & dContactApprox1_2) info->findex[2] = 0;
  1162. // set slip (constraint force mixing)
  1163. if (j->contact.surface.mode & dContactSlip2)
  1164. info->cfm[2] = j->contact.surface.slip2;
  1165. }
  1166. }
  1167. dxJoint::Vtable __dcontact_vtable = {
  1168. sizeof(dxJointContact),
  1169. (dxJoint::init_fn*) contactInit,
  1170. (dxJoint::getInfo1_fn*) contactGetInfo1,
  1171. (dxJoint::getInfo2_fn*) contactGetInfo2,
  1172. dJointTypeContact};
  1173. //****************************************************************************
  1174. // hinge 2. note that this joint must be attached to two bodies for it to work
  1175. static dReal measureHinge2Angle (dxJointHinge2 *joint)
  1176. {
  1177. dVector3 a1,a2;
  1178. dMULTIPLY0_331 (a1,joint->node[1].body->R,joint->axis2);
  1179. dMULTIPLY1_331 (a2,joint->node[0].body->R,a1);
  1180. dReal x = dDOT(joint->v1,a2);
  1181. dReal y = dDOT(joint->v2,a2);
  1182. return -dAtan2 (y,x);
  1183. }
  1184. static void hinge2Init (dxJointHinge2 *j)
  1185. {
  1186. dSetZero (j->anchor1,4);
  1187. dSetZero (j->anchor2,4);
  1188. dSetZero (j->axis1,4);
  1189. j->axis1[0] = 1;
  1190. dSetZero (j->axis2,4);
  1191. j->axis2[1] = 1;
  1192. j->c0 = 0;
  1193. j->s0 = 0;
  1194. dSetZero (j->v1,4);
  1195. j->v1[0] = 1;
  1196. dSetZero (j->v2,4);
  1197. j->v2[1] = 1;
  1198. j->limot1.init (j->world);
  1199. j->limot2.init (j->world);
  1200. j->susp_erp = j->world->global_erp;
  1201. j->susp_cfm = j->world->global_cfm;
  1202. j->flags |= dJOINT_TWOBODIES;
  1203. }
  1204. static void hinge2GetInfo1 (dxJointHinge2 *j, dxJoint::Info1 *info)
  1205. {
  1206. info->m = 4;
  1207. info->nub = 4;
  1208. // see if we're powered or at a joint limit for axis 1
  1209. int atlimit=0;
  1210. if ((j->limot1.lostop >= -M_PI || j->limot1.histop <= M_PI) &&
  1211. j->limot1.lostop <= j->limot1.histop) {
  1212. dReal angle = measureHinge2Angle (j);
  1213. if (j->limot1.testRotationalLimit (angle)) atlimit = 1;
  1214. }
  1215. if (atlimit || j->limot1.fmax > 0) info->m++;
  1216. // see if we're powering axis 2 (we currently never limit this axis)
  1217. j->limot2.limit = 0;
  1218. if (j->limot2.fmax > 0) info->m++;
  1219. }
  1220. // macro that computes ax1,ax2 = axis 1 and 2 in global coordinates (they are
  1221. // relative to body 1 and 2 initially) and then computes the constrained
  1222. // rotational axis as the cross product of ax1 and ax2.
  1223. // the sin and cos of the angle between axis 1 and 2 is computed, this comes
  1224. // from dot and cross product rules.
  1225. #define HINGE2_GET_AXIS_INFO(axis,sin_angle,cos_angle) \
  1226. dVector3 ax1,ax2; \
  1227. dMULTIPLY0_331 (ax1,joint->node[0].body->R,joint->axis1); \
  1228. dMULTIPLY0_331 (ax2,joint->node[1].body->R,joint->axis2); \
  1229. dCROSS (axis,=,ax1,ax2); \
  1230. sin_angle = dSqrt (axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2]); \
  1231. cos_angle = dDOT (ax1,ax2);
  1232. static void hinge2GetInfo2 (dxJointHinge2 *joint, dxJoint::Info2 *info)
  1233. {
  1234. // get information we need to set the hinge row
  1235. dReal s,c;
  1236. dVector3 q;
  1237. HINGE2_GET_AXIS_INFO (q,s,c);
  1238. dNormalize3 (q); // @@@ quicker: divide q by s ?
  1239. // set the three ball-and-socket rows (aligned to the suspension axis ax1)
  1240. setBall2 (joint,info,joint->anchor1,joint->anchor2,ax1,joint->susp_erp);
  1241. // set the hinge row
  1242. int s3=3*info->rowskip;
  1243. info->J1a[s3+0] = q[0];
  1244. info->J1a[s3+1] = q[1];
  1245. info->J1a[s3+2] = q[2];
  1246. if (joint->node[1].body) {
  1247. info->J2a[s3+0] = -q[0];
  1248. info->J2a[s3+1] = -q[1];
  1249. info->J2a[s3+2] = -q[2];
  1250. }
  1251. // compute the right hand side for the constrained rotational DOF.
  1252. // axis 1 and axis 2 are separated by an angle `theta'. the desired
  1253. // separation angle is theta0. sin(theta0) and cos(theta0) are recorded
  1254. // in the joint structure. the correcting angular velocity is:
  1255. // |angular_velocity| = angle/time = erp*(theta0-theta) / stepsize
  1256. // = (erp*fps) * (theta0-theta)
  1257. // (theta0-theta) can be computed using the following small-angle-difference
  1258. // approximation:
  1259. // theta0-theta ~= tan(theta0-theta)
  1260. // = sin(theta0-theta)/cos(theta0-theta)
  1261. // = (c*s0 - s*c0) / (c*c0 + s*s0)
  1262. // = c*s0 - s*c0 assuming c*c0 + s*s0 ~= 1
  1263. // where c = cos(theta), s = sin(theta)
  1264. // c0 = cos(theta0), s0 = sin(theta0)
  1265. dReal k = info->fps * info->erp;
  1266. info->c[3] = k * (joint->c0 * s - joint->s0 * c);
  1267. // if the axis1 hinge is powered, or has joint limits, add in more stuff
  1268. int row = 4 + joint->limot1.addLimot (joint,info,4,ax1,1);
  1269. // if the axis2 hinge is powered, add in more stuff
  1270. joint->limot2.addLimot (joint,info,row,ax2,1);
  1271. // set parameter for the suspension
  1272. info->cfm[0] = joint->susp_cfm;
  1273. }
  1274. // compute vectors v1 and v2 (embedded in body1), used to measure angle
  1275. // between body 1 and body 2
  1276. static void makeHinge2V1andV2 (dxJointHinge2 *joint)
  1277. {
  1278. if (joint->node[0].body) {
  1279. // get axis 1 and 2 in global coords
  1280. dVector3 ax1,ax2,v;
  1281. dMULTIPLY0_331 (ax1,joint->node[0].body->R,joint->axis1);
  1282. dMULTIPLY0_331 (ax2,joint->node[1].body->R,joint->axis2);
  1283. // don't do anything if the axis1 or axis2 vectors are zero or the same
  1284. if ((ax1[0]==0 && ax1[1]==0 && ax1[2]==0) ||
  1285. (ax2[0]==0 && ax2[1]==0 && ax2[2]==0) ||
  1286. (ax1[0]==ax2[0] && ax1[1]==ax2[1] && ax1[2]==ax2[2])) return;
  1287. // modify axis 2 so it's perpendicular to axis 1
  1288. dReal k = dDOT(ax1,ax2);
  1289. for (int i=0; i<3; i++) ax2[i] -= k*ax1[i];
  1290. dNormalize3 (ax2);
  1291. // make v1 = modified axis2, v2 = axis1 x (modified axis2)
  1292. dCROSS (v,=,ax1,ax2);
  1293. dMULTIPLY1_331 (joint->v1,joint->node[0].body->R,ax2);
  1294. dMULTIPLY1_331 (joint->v2,joint->node[0].body->R,v);
  1295. }
  1296. }
  1297. extern "C" void dJointSetHinge2Anchor (dxJointHinge2 *joint,
  1298. dReal x, dReal y, dReal z)
  1299. {
  1300. dUASSERT(joint,"bad joint argument");
  1301. dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2");
  1302. setAnchors (joint,x,y,z,joint->anchor1,joint->anchor2);
  1303. makeHinge2V1andV2 (joint);
  1304. }
  1305. extern "C" void dJointSetHinge2Axis1 (dxJointHinge2 *joint,
  1306. dReal x, dReal y, dReal z)
  1307. {
  1308. dUASSERT(joint,"bad joint argument");
  1309. dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2");
  1310. if (joint->node[0].body) {
  1311. dReal q[4];
  1312. q[0] = x;
  1313. q[1] = y;
  1314. q[2] = z;
  1315. q[3] = 0;
  1316. dNormalize3 (q);
  1317. dMULTIPLY1_331 (joint->axis1,joint->node[0].body->R,q);
  1318. joint->axis1[3] = 0;
  1319. // compute the sin and cos of the angle between axis 1 and axis 2
  1320. dVector3 ax;
  1321. HINGE2_GET_AXIS_INFO(ax,joint->s0,joint->c0);
  1322. }
  1323. makeHinge2V1andV2 (joint);
  1324. }
  1325. extern "C" void dJointSetHinge2Axis2 (dxJointHinge2 *joint,
  1326. dReal x, dReal y, dReal z)
  1327. {
  1328. dUASSERT(joint,"bad joint argument");
  1329. dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2");
  1330. if (joint->node[1].body) {
  1331. dReal q[4];
  1332. q[0] = x;
  1333. q[1] = y;
  1334. q[2] = z;
  1335. q[3] = 0;
  1336. dNormalize3 (q);
  1337. dMULTIPLY1_331 (joint->axis2,joint->node[1].body->R,q);
  1338. joint->axis1[3] = 0;
  1339. // compute the sin and cos of the angle between axis 1 and axis 2
  1340. dVector3 ax;
  1341. HINGE2_GET_AXIS_INFO(ax,joint->s0,joint->c0);
  1342. }
  1343. makeHinge2V1andV2 (joint);
  1344. }
  1345. extern "C" void dJointSetHinge2Param (dxJointHinge2 *joint,
  1346. int parameter, dReal value)
  1347. {
  1348. dUASSERT(joint,"bad joint argument");
  1349. dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2");
  1350. if ((parameter & 0xff00) == 0x100) {
  1351. joint->limot2.set (parameter & 0xff,value);
  1352. }
  1353. else {
  1354. if (parameter == dParamSuspensionERP) joint->susp_erp = value;
  1355. else if (parameter == dParamSuspensionCFM) joint->susp_cfm = value;
  1356. else joint->limot1.set (parameter,value);
  1357. }
  1358. }
  1359. extern "C" void dJointGetHinge2Anchor (dxJointHinge2 *joint, dVector3 result)
  1360. {
  1361. dUASSERT(joint,"bad joint argument");
  1362. dUASSERT(result,"bad result argument");
  1363. dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2");
  1364. if (joint->flags & dJOINT_REVERSE)
  1365. getAnchor2 (joint,result,joint->anchor2);
  1366. else
  1367. getAnchor (joint,result,joint->anchor1);
  1368. }
  1369. extern "C" void dJointGetHinge2Anchor2 (dxJointHinge2 *joint, dVector3 result)
  1370. {
  1371. dUASSERT(joint,"bad joint argument");
  1372. dUASSERT(result,"bad result argument");
  1373. dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2");
  1374. if (joint->flags & dJOINT_REVERSE)
  1375. getAnchor (joint,result,joint->anchor1);
  1376. else
  1377. getAnchor2 (joint,result,joint->anchor2);
  1378. }
  1379. extern "C" void dJointGetHinge2Axis1 (dxJointHinge2 *joint, dVector3 result)
  1380. {
  1381. dUASSERT(joint,"bad joint argument");
  1382. dUASSERT(result,"bad result argument");
  1383. dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2");
  1384. if (joint->node[0].body) {
  1385. dMULTIPLY0_331 (result,joint->node[0].body->R,joint->axis1);
  1386. }
  1387. }
  1388. extern "C" void dJointGetHinge2Axis2 (dxJointHinge2 *joint, dVector3 result)
  1389. {
  1390. dUASSERT(joint,"bad joint argument");
  1391. dUASSERT(result,"bad result argument");
  1392. dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2");
  1393. if (joint->node[1].body) {
  1394. dMULTIPLY0_331 (result,joint->node[1].body->R,joint->axis2);
  1395. }
  1396. }
  1397. extern "C" dReal dJointGetHinge2Param (dxJointHinge2 *joint, int parameter)
  1398. {
  1399. dUASSERT(joint,"bad joint argument");
  1400. dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2");
  1401. if ((parameter & 0xff00) == 0x100) {
  1402. return joint->limot2.get (parameter & 0xff);
  1403. }
  1404. else {
  1405. if (parameter == dParamSuspensionERP) return joint->susp_erp;
  1406. else if (parameter == dParamSuspensionCFM) return joint->susp_cfm;
  1407. else return joint->limot1.get (parameter);
  1408. }
  1409. }
  1410. extern "C" dReal dJointGetHinge2Angle1 (dxJointHinge2 *joint)
  1411. {
  1412. dUASSERT(joint,"bad joint argument");
  1413. dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2");
  1414. if (joint->node[0].body) return measureHinge2Angle (joint);
  1415. else return 0;
  1416. }
  1417. extern "C" dReal dJointGetHinge2Angle1Rate (dxJointHinge2 *joint)
  1418. {
  1419. dUASSERT(joint,"bad joint argument");
  1420. dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2");
  1421. if (joint->node[0].body) {
  1422. dVector3 axis;
  1423. dMULTIPLY0_331 (axis,joint->node[0].body->R,joint->axis1);
  1424. dReal rate = dDOT(axis,joint->node[0].body->avel);
  1425. if (joint->node[1].body) rate -= dDOT(axis,joint->node[1].body->avel);
  1426. return rate;
  1427. }
  1428. else return 0;
  1429. }
  1430. extern "C" dReal dJointGetHinge2Angle2Rate (dxJointHinge2 *joint)
  1431. {
  1432. dUASSERT(joint,"bad joint argument");
  1433. dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2");
  1434. if (joint->node[0].body && joint->node[1].body) {
  1435. dVector3 axis;
  1436. dMULTIPLY0_331 (axis,joint->node[1].body->R,joint->axis2);
  1437. dReal rate = dDOT(axis,joint->node[0].body->avel);
  1438. if (joint->node[1].body) rate -= dDOT(axis,joint->node[1].body->avel);
  1439. return rate;
  1440. }
  1441. else return 0;
  1442. }
  1443. extern "C" void dJointAddHinge2Torques (dxJointHinge2 *joint, dReal torque1, dReal torque2)
  1444. {
  1445. dVector3 axis1, axis2;
  1446. dUASSERT(joint,"bad joint argument");
  1447. dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2");
  1448. if (joint->node[0].body && joint->node[1].body) {
  1449. dMULTIPLY0_331 (axis1,joint->node[0].body->R,joint->axis1);
  1450. dMULTIPLY0_331 (axis2,joint->node[1].body->R,joint->axis2);
  1451. axis1[0] = axis1[0] * torque1 + axis2[0] * torque2;
  1452. axis1[1] = axis1[1] * torque1 + axis2[1] * torque2;
  1453. axis1[2] = axis1[2] * torque1 + axis2[2] * torque2;
  1454. dBodyAddTorque (joint->node[0].body,axis1[0],axis1[1],axis1[2]);
  1455. dBodyAddTorque(joint->node[1].body, -axis1[0], -axis1[1], -axis1[2]);
  1456. }
  1457. }
  1458. dxJoint::Vtable __dhinge2_vtable = {
  1459. sizeof(dxJointHinge2),
  1460. (dxJoint::init_fn*) hinge2Init,
  1461. (dxJoint::getInfo1_fn*) hinge2GetInfo1,
  1462. (dxJoint::getInfo2_fn*) hinge2GetInfo2,
  1463. dJointTypeHinge2};
  1464. //****************************************************************************
  1465. // universal
  1466. // I just realized that the universal joint is equivalent to a hinge 2 joint with
  1467. // perfectly stiff suspension. By comparing the hinge 2 implementation to
  1468. // the universal implementation, you may be able to improve this
  1469. // implementation (or, less likely, the hinge2 implementation).
  1470. static void universalInit (dxJointUniversal *j)
  1471. {
  1472. dSetZero (j->anchor1,4);
  1473. dSetZero (j->anchor2,4);
  1474. dSetZero (j->axis1,4);
  1475. j->axis1[0] = 1;
  1476. dSetZero (j->axis2,4);
  1477. j->axis2[1] = 1;
  1478. dSetZero(j->qrel1,4);
  1479. dSetZero(j->qrel2,4);
  1480. j->limot1.init (j->world);
  1481. j->limot2.init (j->world);
  1482. }
  1483. static void getUniversalAxes(dxJointUniversal *joint, dVector3 ax1, dVector3 ax2)
  1484. {
  1485. // This says "ax1 = joint->node[0].body->R * joint->axis1"
  1486. dMULTIPLY0_331 (ax1,joint->node[0].body->R,joint->axis1);
  1487. if (joint->node[1].body) {
  1488. dMULTIPLY0_331 (ax2,joint->node[1].body->R,joint->axis2);
  1489. }
  1490. else {
  1491. ax2[0] = joint->axis2[0];
  1492. ax2[1] = joint->axis2[1];
  1493. ax2[2] = joint->axis2[2];
  1494. }
  1495. }
  1496. static dReal getUniversalAngle1(dxJointUniversal *joint)
  1497. {
  1498. if (joint->node[0].body) {
  1499. // length 1 joint axis in global coordinates, from each body
  1500. dVector3 ax1, ax2;
  1501. dMatrix3 R;
  1502. dQuaternion qcross, qq, qrel;
  1503. getUniversalAxes (joint,ax1,ax2);
  1504. // It should be possible to get both angles without explicitly
  1505. // constructing the rotation matrix of the cross. Basically,
  1506. // orientation of the cross about axis1 comes from body 2,
  1507. // about axis 2 comes from body 1, and the perpendicular
  1508. // axis can come from the two bodies somehow. (We don't really
  1509. // want to assume it's 90 degrees, because in general the
  1510. // constraints won't be perfectly satisfied, or even very well
  1511. // satisfied.)
  1512. //
  1513. // However, we'd need a version of getHingeAngleFromRElativeQuat()
  1514. // that CAN handle when its relative quat is rotated along a direction
  1515. // other than the given axis. What I have here works,
  1516. // although it's probably much slower than need be.
  1517. dRFrom2Axes(R, ax1[0], ax1[1], ax1[2], ax2[0], ax2[1], ax2[2]);
  1518. dRtoQ (R,qcross);
  1519. // This code is essential the same as getHingeAngle(), see the comments
  1520. // there for details.
  1521. // get qrel = relative rotation between node[0] and the cross
  1522. dQMultiply1 (qq,joint->node[0].body->q,qcross);
  1523. dQMultiply2 (qrel,qq,joint->qrel1);
  1524. return getHingeAngleFromRelativeQuat(qrel, joint->axis1);
  1525. }
  1526. return 0;
  1527. }
  1528. static dReal getUniversalAngle2(dxJointUniversal *joint)
  1529. {
  1530. if (joint->node[0].body) {
  1531. // length 1 joint axis in global coordinates, from each body
  1532. dVector3 ax1, ax2;
  1533. dMatrix3 R;
  1534. dQuaternion qcross, qq, qrel;
  1535. getUniversalAxes (joint,ax1,ax2);
  1536. // It should be possible to get both angles without explicitly
  1537. // constructing the rotation matrix of the cross. Basically,
  1538. // orientation of the cross about axis1 comes from body 2,
  1539. // about axis 2 comes from body 1, and the perpendicular
  1540. // axis can come from the two bodies somehow. (We don't really
  1541. // want to assume it's 90 degrees, because in general the
  1542. // constraints won't be perfectly satisfied, or even very well
  1543. // satisfied.)
  1544. //
  1545. // However, we'd need a version of getHingeAngleFromRElativeQuat()
  1546. // that CAN handle when its relative quat is rotated along a direction
  1547. // other than the given axis. What I have here works,
  1548. // although it's probably much slower than need be.
  1549. dRFrom2Axes(R, ax2[0], ax2[1], ax2[2], ax1[0], ax1[1], ax1[2]);
  1550. dRtoQ(R, qcross);
  1551. if (joint->node[1].body) {
  1552. dQMultiply1 (qq, joint->node[1].body->q, qcross);
  1553. dQMultiply2 (qrel,qq,joint->qrel2);
  1554. }
  1555. else {
  1556. // pretend joint->node[1].body->q is the identity
  1557. dQMultiply2 (qrel,qcross, joint->qrel2);
  1558. }
  1559. return - getHingeAngleFromRelativeQuat(qrel, joint->axis2);
  1560. }
  1561. return 0;
  1562. }
  1563. static void universalGetInfo1 (dxJointUniversal *j, dxJoint::Info1 *info)
  1564. {
  1565. info->nub = 4;
  1566. info->m = 4;
  1567. // see if we're powered or at a joint limit.
  1568. bool constraint1 = j->limot1.fmax > 0;
  1569. bool constraint2 = j->limot2.fmax > 0;
  1570. bool limiting1 = (j->limot1.lostop >= -M_PI || j->limot1.histop <= M_PI) &&
  1571. j->limot1.lostop <= j->limot1.histop;
  1572. bool limiting2 = (j->limot2.lostop >= -M_PI || j->limot2.histop <= M_PI) &&
  1573. j->limot2.lostop <= j->limot2.histop;
  1574. // We need to call testRotationLimit() even if we're motored, since it
  1575. // records the result.
  1576. if (limiting1 || limiting2) {
  1577. dReal angle1, angle2;
  1578. angle1 = getUniversalAngle1(j);
  1579. angle2 = getUniversalAngle2(j);
  1580. if (limiting1 && j->limot1.testRotationalLimit (angle1)) constraint1 = true;
  1581. if (limiting2 && j->limot2.testRotationalLimit (angle2)) constraint2 = true;
  1582. }
  1583. if (constraint1)
  1584. info->m++;
  1585. if (constraint2)
  1586. info->m++;
  1587. }
  1588. static void universalGetInfo2 (dxJointUniversal *joint, dxJoint::Info2 *info)
  1589. {
  1590. // set the three ball-and-socket rows
  1591. setBall (joint,info,joint->anchor1,joint->anchor2);
  1592. // set the universal joint row. the angular velocity about an axis
  1593. // perpendicular to both joint axes should be equal. thus the constraint
  1594. // equation is
  1595. // p*w1 - p*w2 = 0
  1596. // where p is a vector normal to both joint axes, and w1 and w2
  1597. // are the angular velocity vectors of the two bodies.
  1598. // length 1 joint axis in global coordinates, from each body
  1599. dVector3 ax1, ax2;
  1600. dVector3 ax2_temp;
  1601. // length 1 vector perpendicular to ax1 and ax2. Neither body can rotate
  1602. // about this.
  1603. dVector3 p;
  1604. dReal k;
  1605. getUniversalAxes(joint, ax1, ax2);
  1606. k = dDOT(ax1, ax2);
  1607. ax2_temp[0] = ax2[0] - k*ax1[0];
  1608. ax2_temp[1] = ax2[1] - k*ax1[1];
  1609. ax2_temp[2] = ax2[2] - k*ax1[2];
  1610. dCROSS(p, =, ax1, ax2_temp);
  1611. dNormalize3(p);
  1612. int s3=3*info->rowskip;
  1613. info->J1a[s3+0] = p[0];
  1614. info->J1a[s3+1] = p[1];
  1615. info->J1a[s3+2] = p[2];
  1616. if (joint->node[1].body) {
  1617. info->J2a[s3+0] = -p[0];
  1618. info->J2a[s3+1] = -p[1];
  1619. info->J2a[s3+2] = -p[2];
  1620. }
  1621. // compute the right hand side of the constraint equation. set relative
  1622. // body velocities along p to bring the axes back to perpendicular.
  1623. // If ax1, ax2 are unit length joint axes as computed from body1 and
  1624. // body2, we need to rotate both bodies along the axis p. If theta
  1625. // is the angle between ax1 and ax2, we need an angular velocity
  1626. // along p to cover the angle erp * (theta - Pi/2) in one step:
  1627. //
  1628. // |angular_velocity| = angle/time = erp*(theta - Pi/2) / stepsize
  1629. // = (erp*fps) * (theta - Pi/2)
  1630. //
  1631. // if theta is close to Pi/2,
  1632. // theta - Pi/2 ~= cos(theta), so
  1633. // |angular_velocity| ~= (erp*fps) * (ax1 dot ax2)
  1634. info->c[3] = info->fps * info->erp * - dDOT(ax1, ax2);
  1635. // if the first angle is powered, or has joint limits, add in the stuff
  1636. int row = 4 + joint->limot1.addLimot (joint,info,4,ax1,1);
  1637. // if the second angle is powered, or has joint limits, add in more stuff
  1638. joint->limot2.addLimot (joint,info,row,ax2,1);
  1639. }
  1640. static void universalComputeInitialRelativeRotations (dxJointUniversal *joint)
  1641. {
  1642. if (joint->node[0].body) {
  1643. dVector3 ax1, ax2;
  1644. dMatrix3 R;
  1645. dQuaternion qcross;
  1646. getUniversalAxes(joint, ax1, ax2);
  1647. // Axis 1.
  1648. dRFrom2Axes(R, ax1[0], ax1[1], ax1[2], ax2[0], ax2[1], ax2[2]);
  1649. dRtoQ(R, qcross);
  1650. dQMultiply1 (joint->qrel1, joint->node[0].body->q, qcross);
  1651. // Axis 2.
  1652. dRFrom2Axes(R, ax2[0], ax2[1], ax2[2], ax1[0], ax1[1], ax1[2]);
  1653. dRtoQ(R, qcross);
  1654. if (joint->node[1].body) {
  1655. dQMultiply1 (joint->qrel2, joint->node[1].body->q, qcross);
  1656. }
  1657. else {
  1658. // set joint->qrel to qcross
  1659. for (int i=0; i<4; i++) joint->qrel2[i] = qcross[i];
  1660. }
  1661. }
  1662. }
  1663. extern "C" void dJointSetUniversalAnchor (dxJointUniversal *joint,
  1664. dReal x, dReal y, dReal z)
  1665. {
  1666. dUASSERT(joint,"bad joint argument");
  1667. dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal");
  1668. setAnchors (joint,x,y,z,joint->anchor1,joint->anchor2);
  1669. universalComputeInitialRelativeRotations(joint);
  1670. }
  1671. extern "C" void dJointSetUniversalAxis1 (dxJointUniversal *joint,
  1672. dReal x, dReal y, dReal z)
  1673. {
  1674. dUASSERT(joint,"bad joint argument");
  1675. dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal");
  1676. if (joint->flags & dJOINT_REVERSE)
  1677. setAxes (joint,x,y,z,NULL,joint->axis2);
  1678. else
  1679. setAxes (joint,x,y,z,joint->axis1,NULL);
  1680. universalComputeInitialRelativeRotations(joint);
  1681. }
  1682. extern "C" void dJointSetUniversalAxis2 (dxJointUniversal *joint,
  1683. dReal x, dReal y, dReal z)
  1684. {
  1685. dUASSERT(joint,"bad joint argument");
  1686. dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal");
  1687. if (joint->flags & dJOINT_REVERSE)
  1688. setAxes (joint,x,y,z,joint->axis1,NULL);
  1689. else
  1690. setAxes (joint,x,y,z,NULL,joint->axis2);
  1691. universalComputeInitialRelativeRotations(joint);
  1692. }
  1693. extern "C" void dJointGetUniversalAnchor (dxJointUniversal *joint,
  1694. dVector3 result)
  1695. {
  1696. dUASSERT(joint,"bad joint argument");
  1697. dUASSERT(result,"bad result argument");
  1698. dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal");
  1699. if (joint->flags & dJOINT_REVERSE)
  1700. getAnchor2 (joint,result,joint->anchor2);
  1701. else
  1702. getAnchor (joint,result,joint->anchor1);
  1703. }
  1704. extern "C" void dJointGetUniversalAnchor2 (dxJointUniversal *joint,
  1705. dVector3 result)
  1706. {
  1707. dUASSERT(joint,"bad joint argument");
  1708. dUASSERT(result,"bad result argument");
  1709. dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal");
  1710. if (joint->flags & dJOINT_REVERSE)
  1711. getAnchor (joint,result,joint->anchor1);
  1712. else
  1713. getAnchor2 (joint,result,joint->anchor2);
  1714. }
  1715. extern "C" void dJointGetUniversalAxis1 (dxJointUniversal *joint,
  1716. dVector3 result)
  1717. {
  1718. dUASSERT(joint,"bad joint argument");
  1719. dUASSERT(result,"bad result argument");
  1720. dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal");
  1721. if (joint->flags & dJOINT_REVERSE)
  1722. getAxis2 (joint,result,joint->axis2);
  1723. else
  1724. getAxis (joint,result,joint->axis1);
  1725. }
  1726. extern "C" void dJointGetUniversalAxis2 (dxJointUniversal *joint,
  1727. dVector3 result)
  1728. {
  1729. dUASSERT(joint,"bad joint argument");
  1730. dUASSERT(result,"bad result argument");
  1731. dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal");
  1732. if (joint->flags & dJOINT_REVERSE)
  1733. getAxis (joint,result,joint->axis1);
  1734. else
  1735. getAxis2 (joint,result,joint->axis2);
  1736. }
  1737. extern "C" void dJointSetUniversalParam (dxJointUniversal *joint,
  1738. int parameter, dReal value)
  1739. {
  1740. dUASSERT(joint,"bad joint argument");
  1741. dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal");
  1742. if ((parameter & 0xff00) == 0x100) {
  1743. joint->limot2.set (parameter & 0xff,value);
  1744. }
  1745. else {
  1746. joint->limot1.set (parameter,value);
  1747. }
  1748. }
  1749. extern "C" dReal dJointGetUniversalParam (dxJointUniversal *joint, int parameter)
  1750. {
  1751. dUASSERT(joint,"bad joint argument");
  1752. dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal");
  1753. if ((parameter & 0xff00) == 0x100) {
  1754. return joint->limot2.get (parameter & 0xff);
  1755. }
  1756. else {
  1757. return joint->limot1.get (parameter);
  1758. }
  1759. }
  1760. extern "C" dReal dJointGetUniversalAngle1 (dxJointUniversal *joint)
  1761. {
  1762. dUASSERT(joint,"bad joint argument");
  1763. dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal");
  1764. if (joint->flags & dJOINT_REVERSE)
  1765. return getUniversalAngle2 (joint);
  1766. else
  1767. return getUniversalAngle1 (joint);
  1768. }
  1769. extern "C" dReal dJointGetUniversalAngle2 (dxJointUniversal *joint)
  1770. {
  1771. dUASSERT(joint,"bad joint argument");
  1772. dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal");
  1773. if (joint->flags & dJOINT_REVERSE)
  1774. return getUniversalAngle1 (joint);
  1775. else
  1776. return getUniversalAngle2 (joint);
  1777. }
  1778. extern "C" dReal dJointGetUniversalAngle1Rate (dxJointUniversal *joint)
  1779. {
  1780. dUASSERT(joint,"bad joint argument");
  1781. dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal");
  1782. if (joint->node[0].body) {
  1783. dVector3 axis;
  1784. if (joint->flags & dJOINT_REVERSE)
  1785. getAxis2 (joint,axis,joint->axis2);
  1786. else
  1787. getAxis (joint,axis,joint->axis1);
  1788. dReal rate = dDOT(axis, joint->node[0].body->avel);
  1789. if (joint->node[1].body) rate -= dDOT(axis, joint->node[1].body->avel);
  1790. return rate;
  1791. }
  1792. return 0;
  1793. }
  1794. extern "C" dReal dJointGetUniversalAngle2Rate (dxJointUniversal *joint)
  1795. {
  1796. dUASSERT(joint,"bad joint argument");
  1797. dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal");
  1798. if (joint->node[0].body) {
  1799. dVector3 axis;
  1800. if (joint->flags & dJOINT_REVERSE)
  1801. getAxis (joint,axis,joint->axis1);
  1802. else
  1803. getAxis2 (joint,axis,joint->axis2);
  1804. dReal rate = dDOT(axis, joint->node[0].body->avel);
  1805. if (joint->node[1].body) rate -= dDOT(axis, joint->node[1].body->avel);
  1806. return rate;
  1807. }
  1808. return 0;
  1809. }
  1810. extern "C" void dJointAddUniversalTorques (dxJointUniversal *joint, dReal torque1, dReal torque2)
  1811. {
  1812. dVector3 axis1, axis2;
  1813. dAASSERT(joint);
  1814. dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal");
  1815. if (joint->flags & dJOINT_REVERSE) {
  1816. dReal temp = torque1;
  1817. torque1 = - torque2;
  1818. torque2 = - temp;
  1819. }
  1820. getAxis (joint,axis1,joint->axis1);
  1821. getAxis2 (joint,axis2,joint->axis2);
  1822. axis1[0] = axis1[0] * torque1 + axis2[0] * torque2;
  1823. axis1[1] = axis1[1] * torque1 + axis2[1] * torque2;
  1824. axis1[2] = axis1[2] * torque1 + axis2[2] * torque2;
  1825. if (joint->node[0].body != 0)
  1826. dBodyAddTorque (joint->node[0].body,axis1[0],axis1[1],axis1[2]);
  1827. if (joint->node[1].body != 0)
  1828. dBodyAddTorque(joint->node[1].body, -axis1[0], -axis1[1], -axis1[2]);
  1829. }
  1830. dxJoint::Vtable __duniversal_vtable = {
  1831. sizeof(dxJointUniversal),
  1832. (dxJoint::init_fn*) universalInit,
  1833. (dxJoint::getInfo1_fn*) universalGetInfo1,
  1834. (dxJoint::getInfo2_fn*) universalGetInfo2,
  1835. dJointTypeUniversal};
  1836. //****************************************************************************
  1837. // angular motor
  1838. static void amotorInit (dxJointAMotor *j)
  1839. {
  1840. int i;
  1841. j->num = 0;
  1842. j->mode = dAMotorUser;
  1843. for (i=0; i<3; i++) {
  1844. j->rel[i] = 0;
  1845. dSetZero (j->axis[i],4);
  1846. j->limot[i].init (j->world);
  1847. j->angle[i] = 0;
  1848. }
  1849. dSetZero (j->reference1,4);
  1850. dSetZero (j->reference2,4);
  1851. j->flags |= dJOINT_TWOBODIES;
  1852. }
  1853. // compute the 3 axes in global coordinates
  1854. static void amotorComputeGlobalAxes (dxJointAMotor *joint, dVector3 ax[3])
  1855. {
  1856. if (joint->mode == dAMotorEuler) {
  1857. // special handling for euler mode
  1858. dMULTIPLY0_331 (ax[0],joint->node[0].body->R,joint->axis[0]);
  1859. dMULTIPLY0_331 (ax[2],joint->node[1].body->R,joint->axis[2]);
  1860. dCROSS (ax[1],=,ax[2],ax[0]);
  1861. dNormalize3 (ax[1]);
  1862. }
  1863. else {
  1864. for (int i=0; i < joint->num; i++) {
  1865. if (joint->rel[i] == 1) {
  1866. // relative to b1
  1867. dMULTIPLY0_331 (ax[i],joint->node[0].body->R,joint->axis[i]);
  1868. }
  1869. if (joint->rel[i] == 2) {
  1870. // relative to b2
  1871. dMULTIPLY0_331 (ax[i],joint->node[1].body->R,joint->axis[i]);
  1872. }
  1873. else {
  1874. // global - just copy it
  1875. ax[i][0] = joint->axis[i][0];
  1876. ax[i][1] = joint->axis[i][1];
  1877. ax[i][2] = joint->axis[i][2];
  1878. }
  1879. }
  1880. }
  1881. }
  1882. static void amotorComputeEulerAngles (dxJointAMotor *joint, dVector3 ax[3])
  1883. {
  1884. // assumptions:
  1885. // global axes already calculated --> ax
  1886. // axis[0] is relative to body 1 --> global ax[0]
  1887. // axis[2] is relative to body 2 --> global ax[2]
  1888. // ax[1] = ax[2] x ax[0]
  1889. // original ax[0] and ax[2] are perpendicular
  1890. // reference1 is perpendicular to ax[0] (in body 1 frame)
  1891. // reference2 is perpendicular to ax[2] (in body 2 frame)
  1892. // all ax[] and reference vectors are unit length
  1893. // calculate references in global frame
  1894. dVector3 ref1,ref2;
  1895. dMULTIPLY0_331 (ref1,joint->node[0].body->R,joint->reference1);
  1896. dMULTIPLY0_331 (ref2,joint->node[1].body->R,joint->reference2);
  1897. // get q perpendicular to both ax[0] and ref1, get first euler angle
  1898. dVector3 q;
  1899. dCROSS (q,=,ax[0],ref1);
  1900. joint->angle[0] = -dAtan2 (dDOT(ax[2],q),dDOT(ax[2],ref1));
  1901. // get q perpendicular to both ax[0] and ax[1], get second euler angle
  1902. dCROSS (q,=,ax[0],ax[1]);
  1903. joint->angle[1] = -dAtan2 (dDOT(ax[2],ax[0]),dDOT(ax[2],q));
  1904. // get q perpendicular to both ax[1] and ax[2], get third euler angle
  1905. dCROSS (q,=,ax[1],ax[2]);
  1906. joint->angle[2] = -dAtan2 (dDOT(ref2,ax[1]), dDOT(ref2,q));
  1907. }
  1908. // set the reference vectors as follows:
  1909. // * reference1 = current axis[2] relative to body 1
  1910. // * reference2 = current axis[0] relative to body 2
  1911. // this assumes that:
  1912. // * axis[0] is relative to body 1
  1913. // * axis[2] is relative to body 2
  1914. static void amotorSetEulerReferenceVectors (dxJointAMotor *j)
  1915. {
  1916. if (j->node[0].body && j->node[1].body) {
  1917. dVector3 r; // axis[2] and axis[0] in global coordinates
  1918. dMULTIPLY0_331 (r,j->node[1].body->R,j->axis[2]);
  1919. dMULTIPLY1_331 (j->reference1,j->node[0].body->R,r);
  1920. dMULTIPLY0_331 (r,j->node[0].body->R,j->axis[0]);
  1921. dMULTIPLY1_331 (j->reference2,j->node[1].body->R,r);
  1922. }
  1923. }
  1924. static void amotorGetInfo1 (dxJointAMotor *j, dxJoint::Info1 *info)
  1925. {
  1926. info->m = 0;
  1927. info->nub = 0;
  1928. // compute the axes and angles, if in euler mode
  1929. if (j->mode == dAMotorEuler) {
  1930. dVector3 ax[3];
  1931. amotorComputeGlobalAxes (j,ax);
  1932. amotorComputeEulerAngles (j,ax);
  1933. }
  1934. // see if we're powered or at a joint limit for each axis
  1935. for (int i=0; i < j->num; i++) {
  1936. if (j->limot[i].testRotationalLimit (j->angle[i]) ||
  1937. j->limot[i].fmax > 0) {
  1938. info->m++;
  1939. }
  1940. }
  1941. }
  1942. static void amotorGetInfo2 (dxJointAMotor *joint, dxJoint::Info2 *info)
  1943. {
  1944. int i;
  1945. // compute the axes (if not global)
  1946. dVector3 ax[3];
  1947. amotorComputeGlobalAxes (joint,ax);
  1948. // in euler angle mode we do not actually constrain the angular velocity
  1949. // along the axes axis[0] and axis[2] (although we do use axis[1]) :
  1950. //
  1951. // to get constrain w2-w1 along ...not
  1952. // ------ --------------------- ------
  1953. // d(angle[0])/dt = 0 ax[1] x ax[2] ax[0]
  1954. // d(angle[1])/dt = 0 ax[1]
  1955. // d(angle[2])/dt = 0 ax[0] x ax[1] ax[2]
  1956. //
  1957. // constraining w2-w1 along an axis 'a' means that a'*(w2-w1)=0.
  1958. // to prove the result for angle[0], write the expression for angle[0] from
  1959. // GetInfo1 then take the derivative. to prove this for angle[2] it is
  1960. // easier to take the euler rate expression for d(angle[2])/dt with respect
  1961. // to the components of w and set that to 0.
  1962. dVector3 *axptr[3];
  1963. axptr[0] = &ax[0];
  1964. axptr[1] = &ax[1];
  1965. axptr[2] = &ax[2];
  1966. dVector3 ax0_cross_ax1;
  1967. dVector3 ax1_cross_ax2;
  1968. if (joint->mode == dAMotorEuler) {
  1969. dCROSS (ax0_cross_ax1,=,ax[0],ax[1]);
  1970. axptr[2] = &ax0_cross_ax1;
  1971. dCROSS (ax1_cross_ax2,=,ax[1],ax[2]);
  1972. axptr[0] = &ax1_cross_ax2;
  1973. }
  1974. int row=0;
  1975. for (i=0; i < joint->num; i++) {
  1976. row += joint->limot[i].addLimot (joint,info,row,*(axptr[i]),1);
  1977. }
  1978. }
  1979. extern "C" void dJointSetAMotorNumAxes (dxJointAMotor *joint, int num)
  1980. {
  1981. dAASSERT(joint && num >= 0 && num <= 3);
  1982. dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor");
  1983. if (joint->mode == dAMotorEuler) {
  1984. joint->num = 3;
  1985. }
  1986. else {
  1987. if (num < 0) num = 0;
  1988. if (num > 3) num = 3;
  1989. joint->num = num;
  1990. }
  1991. }
  1992. extern "C" void dJointSetAMotorAxis (dxJointAMotor *joint, int anum, int rel,
  1993. dReal x, dReal y, dReal z)
  1994. {
  1995. dAASSERT(joint && anum >= 0 && anum <= 2 && rel >= 0 && rel <= 2);
  1996. dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor");
  1997. if (anum < 0) anum = 0;
  1998. if (anum > 2) anum = 2;
  1999. joint->rel[anum] = rel;
  2000. // x,y,z is always in global coordinates regardless of rel, so we may have
  2001. // to convert it to be relative to a body
  2002. dVector3 r;
  2003. r[0] = x;
  2004. r[1] = y;
  2005. r[2] = z;
  2006. r[3] = 0;
  2007. if (rel > 0) {
  2008. if (rel==1) {
  2009. dMULTIPLY1_331 (joint->axis[anum],joint->node[0].body->R,r);
  2010. }
  2011. else {
  2012. dMULTIPLY1_331 (joint->axis[anum],joint->node[1].body->R,r);
  2013. }
  2014. }
  2015. else {
  2016. joint->axis[anum][0] = r[0];
  2017. joint->axis[anum][1] = r[1];
  2018. joint->axis[anum][2] = r[2];
  2019. }
  2020. dNormalize3 (joint->axis[anum]);
  2021. if (joint->mode == dAMotorEuler) amotorSetEulerReferenceVectors (joint);
  2022. }
  2023. extern "C" void dJointSetAMotorAngle (dxJointAMotor *joint, int anum,
  2024. dReal angle)
  2025. {
  2026. dAASSERT(joint && anum >= 0 && anum < 3);
  2027. dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor");
  2028. if (joint->mode == dAMotorUser) {
  2029. if (anum < 0) anum = 0;
  2030. if (anum > 3) anum = 3;
  2031. joint->angle[anum] = angle;
  2032. }
  2033. }
  2034. extern "C" void dJointSetAMotorParam (dxJointAMotor *joint, int parameter,
  2035. dReal value)
  2036. {
  2037. dAASSERT(joint);
  2038. dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor");
  2039. int anum = parameter >> 8;
  2040. if (anum < 0) anum = 0;
  2041. if (anum > 2) anum = 2;
  2042. parameter &= 0xff;
  2043. joint->limot[anum].set (parameter, value);
  2044. }
  2045. extern "C" void dJointSetAMotorMode (dxJointAMotor *joint, int mode)
  2046. {
  2047. dAASSERT(joint);
  2048. dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor");
  2049. joint->mode = mode;
  2050. if (joint->mode == dAMotorEuler) {
  2051. joint->num = 3;
  2052. amotorSetEulerReferenceVectors (joint);
  2053. }
  2054. }
  2055. extern "C" int dJointGetAMotorNumAxes (dxJointAMotor *joint)
  2056. {
  2057. dAASSERT(joint);
  2058. dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor");
  2059. return joint->num;
  2060. }
  2061. extern "C" void dJointGetAMotorAxis (dxJointAMotor *joint, int anum,
  2062. dVector3 result)
  2063. {
  2064. dAASSERT(joint && anum >= 0 && anum < 3);
  2065. dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor");
  2066. if (anum < 0) anum = 0;
  2067. if (anum > 2) anum = 2;
  2068. if (joint->rel[anum] > 0) {
  2069. if (joint->rel[anum]==1) {
  2070. dMULTIPLY0_331 (result,joint->node[0].body->R,joint->axis[anum]);
  2071. }
  2072. else {
  2073. dMULTIPLY0_331 (result,joint->node[1].body->R,joint->axis[anum]);
  2074. }
  2075. }
  2076. else {
  2077. result[0] = joint->axis[anum][0];
  2078. result[1] = joint->axis[anum][1];
  2079. result[2] = joint->axis[anum][2];
  2080. }
  2081. }
  2082. extern "C" int dJointGetAMotorAxisRel (dxJointAMotor *joint, int anum)
  2083. {
  2084. dAASSERT(joint && anum >= 0 && anum < 3);
  2085. dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor");
  2086. if (anum < 0) anum = 0;
  2087. if (anum > 2) anum = 2;
  2088. return joint->rel[anum];
  2089. }
  2090. extern "C" dReal dJointGetAMotorAngle (dxJointAMotor *joint, int anum)
  2091. {
  2092. dAASSERT(joint && anum >= 0 && anum < 3);
  2093. dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor");
  2094. if (anum < 0) anum = 0;
  2095. if (anum > 3) anum = 3;
  2096. return joint->angle[anum];
  2097. }
  2098. extern "C" dReal dJointGetAMotorAngleRate (dxJointAMotor *joint, int anum)
  2099. {
  2100. // @@@
  2101. dDebug (0,"not yet implemented");
  2102. return 0;
  2103. }
  2104. extern "C" dReal dJointGetAMotorParam (dxJointAMotor *joint, int parameter)
  2105. {
  2106. dAASSERT(joint);
  2107. dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor");
  2108. int anum = parameter >> 8;
  2109. if (anum < 0) anum = 0;
  2110. if (anum > 2) anum = 2;
  2111. parameter &= 0xff;
  2112. return joint->limot[anum].get (parameter);
  2113. }
  2114. extern "C" int dJointGetAMotorMode (dxJointAMotor *joint)
  2115. {
  2116. dAASSERT(joint);
  2117. dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor");
  2118. return joint->mode;
  2119. }
  2120. extern "C" void dJointAddAMotorTorques (dxJointAMotor *joint, dReal torque1, dReal torque2, dReal torque3)
  2121. {
  2122. dVector3 axes[3];
  2123. dAASSERT(joint);
  2124. dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor");
  2125. if (joint->num == 0)
  2126. return;
  2127. dUASSERT((joint->flags & dJOINT_REVERSE) == 0, "dJointAddAMotorTorques not yet implemented for reverse AMotor joints");
  2128. amotorComputeGlobalAxes (joint,axes);
  2129. axes[0][0] *= torque1;
  2130. axes[0][1] *= torque1;
  2131. axes[0][2] *= torque1;
  2132. if (joint->num >= 2) {
  2133. axes[0][0] += axes[1][0] * torque2;
  2134. axes[0][1] += axes[1][0] * torque2;
  2135. axes[0][2] += axes[1][0] * torque2;
  2136. if (joint->num >= 3) {
  2137. axes[0][0] += axes[2][0] * torque3;
  2138. axes[0][1] += axes[2][0] * torque3;
  2139. axes[0][2] += axes[2][0] * torque3;
  2140. }
  2141. }
  2142. if (joint->node[0].body != 0)
  2143. dBodyAddTorque (joint->node[0].body,axes[0][0],axes[0][1],axes[0][2]);
  2144. if (joint->node[1].body != 0)
  2145. dBodyAddTorque(joint->node[1].body, -axes[0][0], -axes[0][1], -axes[0][2]);
  2146. }
  2147. dxJoint::Vtable __damotor_vtable = {
  2148. sizeof(dxJointAMotor),
  2149. (dxJoint::init_fn*) amotorInit,
  2150. (dxJoint::getInfo1_fn*) amotorGetInfo1,
  2151. (dxJoint::getInfo2_fn*) amotorGetInfo2,
  2152. dJointTypeAMotor};
  2153. //****************************************************************************
  2154. // fixed joint
  2155. static void fixedInit (dxJointFixed *j)
  2156. {
  2157. dSetZero (j->offset,4);
  2158. dSetZero (j->qrel,4);
  2159. }
  2160. static void fixedGetInfo1 (dxJointFixed *j, dxJoint::Info1 *info)
  2161. {
  2162. info->m = 6;
  2163. info->nub = 6;
  2164. }
  2165. static void fixedGetInfo2 (dxJointFixed *joint, dxJoint::Info2 *info)
  2166. {
  2167. int s = info->rowskip;
  2168. // Three rows for orientation
  2169. setFixedOrientation(joint, info, joint->qrel, 3);
  2170. // Three rows for position.
  2171. // set jacobian
  2172. info->J1l[0] = 1;
  2173. info->J1l[s+1] = 1;
  2174. info->J1l[2*s+2] = 1;
  2175. dVector3 ofs;
  2176. dMULTIPLY0_331 (ofs,joint->node[0].body->R,joint->offset);
  2177. if (joint->node[1].body) {
  2178. dCROSSMAT (info->J1a,ofs,s,+,-);
  2179. info->J2l[0] = -1;
  2180. info->J2l[s+1] = -1;
  2181. info->J2l[2*s+2] = -1;
  2182. }
  2183. // set right hand side for the first three rows (linear)
  2184. dReal k = info->fps * info->erp;
  2185. if (joint->node[1].body) {
  2186. for (int j=0; j<3; j++)
  2187. info->c[j] = k * (joint->node[1].body->pos[j] -
  2188. joint->node[0].body->pos[j] + ofs[j]);
  2189. }
  2190. else {
  2191. for (int j=0; j<3; j++)
  2192. info->c[j] = k * (joint->offset[j] - joint->node[0].body->pos[j]);
  2193. }
  2194. }
  2195. extern "C" void dJointSetFixed (dxJointFixed *joint)
  2196. {
  2197. dUASSERT(joint,"bad joint argument");
  2198. dUASSERT(joint->vtable == &__dfixed_vtable,"joint is not fixed");
  2199. int i;
  2200. // This code is taken from sJointSetSliderAxis(), we should really put the
  2201. // common code in its own function.
  2202. // compute the offset between the bodies
  2203. if (joint->node[0].body) {
  2204. if (joint->node[1].body) {
  2205. dQMultiply1 (joint->qrel,joint->node[0].body->q,joint->node[1].body->q);
  2206. dReal ofs[4];
  2207. for (i=0; i<4; i++) ofs[i] = joint->node[0].body->pos[i];
  2208. for (i=0; i<4; i++) ofs[i] -= joint->node[1].body->pos[i];
  2209. dMULTIPLY1_331 (joint->offset,joint->node[0].body->R,ofs);
  2210. }
  2211. else {
  2212. // set joint->qrel to the transpose of the first body's q
  2213. joint->qrel[0] = joint->node[0].body->q[0];
  2214. for (i=1; i<4; i++) joint->qrel[i] = -joint->node[0].body->q[i];
  2215. for (i=0; i<4; i++) joint->offset[i] = joint->node[0].body->pos[i];
  2216. }
  2217. }
  2218. }
  2219. dxJoint::Vtable __dfixed_vtable = {
  2220. sizeof(dxJointFixed),
  2221. (dxJoint::init_fn*) fixedInit,
  2222. (dxJoint::getInfo1_fn*) fixedGetInfo1,
  2223. (dxJoint::getInfo2_fn*) fixedGetInfo2,
  2224. dJointTypeFixed};
  2225. //****************************************************************************
  2226. // null joint
  2227. static void nullGetInfo1 (dxJointNull *j, dxJoint::Info1 *info)
  2228. {
  2229. info->m = 0;
  2230. info->nub = 0;
  2231. }
  2232. static void nullGetInfo2 (dxJointNull *joint, dxJoint::Info2 *info)
  2233. {
  2234. dDebug (0,"this should never get called");
  2235. }
  2236. dxJoint::Vtable __dnull_vtable = {
  2237. sizeof(dxJointNull),
  2238. (dxJoint::init_fn*) 0,
  2239. (dxJoint::getInfo1_fn*) nullGetInfo1,
  2240. (dxJoint::getInfo2_fn*) nullGetInfo2,
  2241. dJointTypeNull};
  2242. /******************** breakable joint contribution ***********************/
  2243. extern "C" void dJointSetBreakable (dxJoint *joint, int b) {
  2244. dAASSERT(joint);
  2245. if (b) {
  2246. // we want this joint to be breakable but we must first check if it
  2247. // was already breakable
  2248. if (!joint->breakInfo) {
  2249. // allocate a dxJointBreakInfo struct
  2250. joint->breakInfo = new dxJointBreakInfo;
  2251. joint->breakInfo->flags = 0;
  2252. for (int i = 0; i < 3; i++) {
  2253. joint->breakInfo->b1MaxF[0] = 0;
  2254. joint->breakInfo->b1MaxT[0] = 0;
  2255. joint->breakInfo->b2MaxF[0] = 0;
  2256. joint->breakInfo->b2MaxT[0] = 0;
  2257. }
  2258. joint->breakInfo->callback = 0;
  2259. }
  2260. else {
  2261. // the joint was already breakable
  2262. return;
  2263. }
  2264. }
  2265. else {
  2266. // we want this joint to be unbreakable mut we must first check if
  2267. // it is alreay unbreakable
  2268. if (joint->breakInfo) {
  2269. // deallocate the dxJointBreakInfo struct
  2270. delete joint->breakInfo;
  2271. joint->breakInfo = 0;
  2272. }
  2273. else {
  2274. // the joint was already unbreakable
  2275. return;
  2276. }
  2277. }
  2278. }
  2279. extern "C" void dJointSetBreakCallback (dxJoint *joint, dJointBreakCallback *callbackFunc) {
  2280. dAASSERT(joint);
  2281. # ifndef dNODEBUG
  2282. // only works for a breakable joint
  2283. if (!joint->breakInfo) {
  2284. dDebug (0, "dJointSetBreakCallback called on unbreakable joint");
  2285. }
  2286. # endif
  2287. joint->breakInfo->callback = callbackFunc;
  2288. }
  2289. extern "C" void dJointSetBreakMode (dxJoint *joint, int mode) {
  2290. dAASSERT(joint);
  2291. # ifndef dNODEBUG
  2292. // only works for a breakable joint
  2293. if (!joint->breakInfo) {
  2294. dDebug (0, "dJointSetBreakMode called on unbreakable joint");
  2295. }
  2296. # endif
  2297. joint->breakInfo->flags = mode;
  2298. }
  2299. extern "C" int dJointGetBreakMode (dxJoint *joint) {
  2300. dAASSERT(joint);
  2301. # ifndef dNODEBUG
  2302. // only works for a breakable joint
  2303. if (!joint->breakInfo) {
  2304. dDebug (0, "dJointGetBreakMode called on unbreakable joint");
  2305. }
  2306. # endif
  2307. return joint->breakInfo->flags;
  2308. }
  2309. extern "C" void dJointSetBreakForce (dxJoint *joint, int body, dReal x, dReal y, dReal z) {
  2310. dAASSERT(joint);
  2311. # ifndef dNODEBUG
  2312. // only works for a breakable joint
  2313. if (!joint->breakInfo) {
  2314. dDebug (0, "dJointSetBreakForce called on unbreakable joint");
  2315. }
  2316. # endif
  2317. if (body) {
  2318. joint->breakInfo->b2MaxF[0] = x;
  2319. joint->breakInfo->b2MaxF[1] = y;
  2320. joint->breakInfo->b2MaxF[2] = z;
  2321. }
  2322. else {
  2323. joint->breakInfo->b1MaxF[0] = x;
  2324. joint->breakInfo->b1MaxF[1] = y;
  2325. joint->breakInfo->b1MaxF[2] = z;
  2326. }
  2327. }
  2328. extern "C" void dJointSetBreakTorque (dxJoint *joint, int body, dReal x, dReal y, dReal z) {
  2329. dAASSERT(joint);
  2330. # ifndef dNODEBUG
  2331. // only works for a breakable joint
  2332. if (!joint->breakInfo) {
  2333. dDebug (0, "dJointSetBreakTorque called on unbreakable joint");
  2334. }
  2335. # endif
  2336. if (body) {
  2337. joint->breakInfo->b2MaxT[0] = x;
  2338. joint->breakInfo->b2MaxT[1] = y;
  2339. joint->breakInfo->b2MaxT[2] = z;
  2340. }
  2341. else {
  2342. joint->breakInfo->b1MaxT[0] = x;
  2343. joint->breakInfo->b1MaxT[1] = y;
  2344. joint->breakInfo->b1MaxT[2] = z;
  2345. }
  2346. }
  2347. extern "C" int dJointIsBreakable (dxJoint *joint) {
  2348. dAASSERT(joint);
  2349. return joint->breakInfo != 0;
  2350. }
  2351. extern "C" void dJointGetBreakForce (dxJoint *joint, int body, dReal *force) {
  2352. dAASSERT(joint);
  2353. # ifndef dNODEBUG
  2354. // only works for a breakable joint
  2355. if (!joint->breakInfo) {
  2356. dDebug (0, "dJointGetBreakForce called on unbreakable joint");
  2357. }
  2358. # endif
  2359. if (body)
  2360. for (int i=0; i<3; i++) force[i]=joint->breakInfo->b2MaxF[i];
  2361. else
  2362. for (int i=0; i<3; i++) force[i]=joint->breakInfo->b1MaxF[i];
  2363. }
  2364. extern "C" void dJointGetBreakTorque (dxJoint *joint, int body, dReal *torque) {
  2365. dAASSERT(joint);
  2366. # ifndef dNODEBUG
  2367. // only works for a breakable joint
  2368. if (!joint->breakInfo) {
  2369. dDebug (0, "dJointGetBreakTorque called on unbreakable joint");
  2370. }
  2371. # endif
  2372. if (body)
  2373. for (int i=0; i<3; i++) torque[i]=joint->breakInfo->b2MaxT[i];
  2374. else
  2375. for (int i=0; i<3; i++) torque[i]=joint->breakInfo->b1MaxT[i];
  2376. }
  2377. /*************************************************************************/