universal.cpp 65 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118
  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. // This file create unit test for some of the functions found in:
  24. // ode/src/joinst/universal.cpp
  25. //
  26. //
  27. ////////////////////////////////////////////////////////////////////////////////
  28. #include <iostream>
  29. #include <UnitTest++.h>
  30. #include <ode/ode.h>
  31. #include "../../ode/src/joints/universal.h"
  32. dReal d2r(dReal degree)
  33. {
  34. return degree * (dReal)(M_PI / 180.0);
  35. }
  36. dReal r2d(dReal degree)
  37. {
  38. return degree * (dReal)(180.0/M_PI);
  39. }
  40. SUITE (TestdxJointUniversal)
  41. {
  42. // The 2 bodies are positionned at (0, 0, 0)
  43. // The bodis have no rotation.
  44. // The joint is a Universal Joint
  45. // Axis1 is along the X axis
  46. // Axis2 is along the Y axis
  47. // Anchor at (0, 0, 0)
  48. struct Fixture_dxJointUniversal_B1_and_B2_At_Zero_Axis1_Along_X_Axis2_Along_Y
  49. {
  50. Fixture_dxJointUniversal_B1_and_B2_At_Zero_Axis1_Along_X_Axis2_Along_Y()
  51. {
  52. wId = dWorldCreate();
  53. bId1 = dBodyCreate (wId);
  54. dBodySetPosition (bId1, 0, 0, 0);
  55. bId2 = dBodyCreate (wId);
  56. dBodySetPosition (bId2, 0, 0, 0);
  57. jId = dJointCreateUniversal (wId, 0);
  58. joint = (dxJointUniversal*) jId;
  59. dJointAttach (jId, bId1, bId2);
  60. }
  61. ~Fixture_dxJointUniversal_B1_and_B2_At_Zero_Axis1_Along_X_Axis2_Along_Y()
  62. {
  63. dWorldDestroy (wId);
  64. }
  65. dWorldID wId;
  66. dBodyID bId1;
  67. dBodyID bId2;
  68. dJointID jId;
  69. dxJointUniversal* joint;
  70. };
  71. // The 2 bodies are positionned at (-1, -2, -3), and (11, 22, 33)
  72. // The bodis have rotation of 27deg around some axis.
  73. // The joint is a Universal Joint
  74. // Axis is along the X axis
  75. // Anchor at (0, 0, 0)
  76. struct Fixture_dxJointUniversal_B1_and_B2_At_Random_Axis_Along_X
  77. {
  78. Fixture_dxJointUniversal_B1_and_B2_At_Random_Axis_Along_X()
  79. {
  80. wId = dWorldCreate();
  81. bId1 = dBodyCreate (wId);
  82. dBodySetPosition (bId1, -1, -2, -3);
  83. bId2 = dBodyCreate (wId);
  84. dBodySetPosition (bId2, 11, 22, 33);
  85. dMatrix3 R;
  86. dVector3 axis;
  87. axis[0] = REAL(0.53);
  88. axis[1] = -REAL(0.71);
  89. axis[2] = REAL(0.43);
  90. dNormalize3(axis);
  91. dRFromAxisAndAngle (R, axis[0], axis[1], axis[2],
  92. REAL(0.47123)); // 27deg
  93. dBodySetRotation (bId1, R);
  94. axis[0] = REAL(1.2);
  95. axis[1] = REAL(0.87);
  96. axis[2] = -REAL(0.33);
  97. dNormalize3(axis);
  98. dRFromAxisAndAngle (R, axis[0], axis[1], axis[2],
  99. REAL(0.47123)); // 27deg
  100. dBodySetRotation (bId2, R);
  101. jId = dJointCreateUniversal (wId, 0);
  102. joint = (dxJointUniversal*) jId;
  103. dJointAttach (jId, bId1, bId2);
  104. }
  105. ~Fixture_dxJointUniversal_B1_and_B2_At_Random_Axis_Along_X()
  106. {
  107. dWorldDestroy (wId);
  108. }
  109. dWorldID wId;
  110. dBodyID bId1;
  111. dBodyID bId2;
  112. dJointID jId;
  113. dxJointUniversal* joint;
  114. };
  115. // Only one body body1 at (0,0,0)
  116. // The joint is an Universal Joint.
  117. // Axis1 is along the X axis
  118. // Axis2 is along the Y axis
  119. // Anchor at (0, 0, 0)
  120. //
  121. // ^Y
  122. // |
  123. // |
  124. // |
  125. // |
  126. // |
  127. // Z <-- X
  128. struct Fixture_dxJointUniversal_B1_At_Zero_Default_Axes
  129. {
  130. Fixture_dxJointUniversal_B1_At_Zero_Default_Axes()
  131. {
  132. wId = dWorldCreate();
  133. bId1 = dBodyCreate (wId);
  134. dBodySetPosition (bId1, 0, 0, 0);
  135. jId = dJointCreateUniversal (wId, 0);
  136. dJointAttach (jId, bId1, NULL);
  137. dJointSetUniversalAnchor (jId, 0, 0, 0);
  138. }
  139. ~Fixture_dxJointUniversal_B1_At_Zero_Default_Axes()
  140. {
  141. dWorldDestroy (wId);
  142. }
  143. dWorldID wId;
  144. dBodyID bId1;
  145. dJointID jId;
  146. };
  147. // Only one body body2 at (0,0,0)
  148. // The joint is an Universal Joint.
  149. // Axis1 is along the X axis.
  150. // Axis2 is along the Y axis.
  151. // Anchor at (0, 0, 0)
  152. //
  153. // ^Y
  154. // |
  155. // |
  156. // |
  157. // |
  158. // |
  159. // Z <-- X
  160. struct Fixture_dxJointUniversal_B2_At_Zero_Default_Axes
  161. {
  162. Fixture_dxJointUniversal_B2_At_Zero_Default_Axes()
  163. {
  164. wId = dWorldCreate();
  165. bId2 = dBodyCreate (wId);
  166. dBodySetPosition (bId2, 0, 0, 0);
  167. jId = dJointCreateUniversal (wId, 0);
  168. dJointAttach (jId, NULL, bId2);
  169. dJointSetUniversalAnchor (jId, 0, 0, 0);
  170. }
  171. ~Fixture_dxJointUniversal_B2_At_Zero_Default_Axes()
  172. {
  173. dWorldDestroy (wId);
  174. }
  175. dWorldID wId;
  176. dBodyID bId2;
  177. dJointID jId;
  178. };
  179. // Test is dJointGetUniversalAngles versus
  180. // dJointGetUniversalAngle1 and dJointGetUniversalAngle2 dJointGetUniversalAxis
  181. TEST_FIXTURE (Fixture_dxJointUniversal_B1_and_B2_At_Zero_Axis1_Along_X_Axis2_Along_Y,
  182. test_dJointSetGetUniversalAngles_Versus_Angle1_and_Angle2)
  183. {
  184. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  185. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  186. dReal angle1, angle2;
  187. dJointGetUniversalAngles(jId, &angle1, &angle2);
  188. CHECK_CLOSE (0, angle1, 1e-4);
  189. CHECK_CLOSE (0, angle2, 1e-4);
  190. dMatrix3 R;
  191. dReal ang1, ang2;
  192. dVector3 axis1;
  193. dJointGetUniversalAxis1 (jId, axis1);
  194. dVector3 axis2;
  195. dJointGetUniversalAxis2 (jId, axis2);
  196. ang1 = d2r(REAL(23.0));
  197. dRFromAxisAndAngle (R, axis1[0], axis1[1], axis1[2], ang1);
  198. dBodySetRotation (bId1, R);
  199. ang2 = d2r(REAL(17.0));
  200. dRFromAxisAndAngle (R, axis2[0], axis2[1], axis2[2], ang2);
  201. dBodySetRotation (bId2, R);
  202. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  203. CHECK_CLOSE (-ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  204. dJointGetUniversalAngles(jId, &angle1, &angle2);
  205. CHECK_CLOSE (ang1, angle1, 1e-4);
  206. CHECK_CLOSE (-ang2, angle2, 1e-4);
  207. // ax1 and ax2 are pseudo-random axis. N.B. They are NOT the axis of the joints.
  208. dVector3 ax1;
  209. ax1[0] = REAL(0.2);
  210. ax1[1] = -REAL(0.67);
  211. ax1[2] = -REAL(0.81);
  212. dNormalize3(ax1);
  213. dVector3 ax2;
  214. ax2[0] = REAL(0.62);
  215. ax2[1] = REAL(0.31);
  216. ax2[2] = REAL(0.43);
  217. dNormalize3(ax2);
  218. ang1 = d2r(REAL(23.0));
  219. dRFromAxisAndAngle (R, ax1[0], ax1[1], ax1[2], ang1);
  220. dBodySetRotation (bId1, R);
  221. ang2 = d2r(REAL(0.0));
  222. dJointGetUniversalAngles(jId, &angle1, &angle2);
  223. CHECK_CLOSE (angle1, dJointGetUniversalAngle1 (jId), 1e-4);
  224. CHECK_CLOSE (angle2, dJointGetUniversalAngle2 (jId), 1e-4);
  225. ang1 = d2r(REAL(0.0));
  226. ang2 = d2r(REAL(23.0));
  227. dRFromAxisAndAngle (R, ax2[0], ax2[1], ax2[2], ang2);
  228. dBodySetRotation (bId1, R);
  229. dJointGetUniversalAngles(jId, &angle1, &angle2);
  230. CHECK_CLOSE (angle1, dJointGetUniversalAngle1 (jId), 1e-4);
  231. CHECK_CLOSE (angle2, dJointGetUniversalAngle2 (jId), 1e-4);
  232. ang1 = d2r(REAL(38.0));
  233. dRFromAxisAndAngle (R, ax1[0], ax1[1], ax1[2], ang2);
  234. dBodySetRotation (bId1, R);
  235. ang2 = d2r(REAL(-43.0));
  236. dRFromAxisAndAngle (R, ax2[0], ax2[1], ax2[2], ang2);
  237. dBodySetRotation (bId1, R);
  238. dJointGetUniversalAngles(jId, &angle1, &angle2);
  239. CHECK_CLOSE (angle1, dJointGetUniversalAngle1 (jId), 1e-4);
  240. CHECK_CLOSE (angle2, dJointGetUniversalAngle2 (jId), 1e-4);
  241. // Try with random axis for the axis of the joints
  242. dRSetIdentity(R);
  243. dBodySetRotation (bId1, R);
  244. dBodySetRotation (bId1, R);
  245. axis1[0] = REAL(0.32);
  246. axis1[1] = -REAL(0.57);
  247. axis1[2] = REAL(0.71);
  248. dNormalize3(axis1);
  249. axis2[0] = -REAL(0.26);
  250. axis2[1] = -REAL(0.31);
  251. axis2[2] = REAL(0.69);
  252. dNormalize3(axis2);
  253. dVector3 cross;
  254. dCalcVectorCross3(cross, axis1, axis2);
  255. dJointSetUniversalAxis1(jId, axis1[0], axis1[1], axis1[2]);
  256. dJointSetUniversalAxis2(jId, cross[0], cross[1], cross[2]);
  257. ang1 = d2r(REAL(23.0));
  258. dRFromAxisAndAngle (R, ax1[0], ax1[1], ax1[2], ang1);
  259. dBodySetRotation (bId1, R);
  260. ang2 = d2r(REAL(0.0));
  261. dJointGetUniversalAngles(jId, &angle1, &angle2);
  262. CHECK_CLOSE (angle1, dJointGetUniversalAngle1 (jId), 1e-4);
  263. CHECK_CLOSE (angle2, dJointGetUniversalAngle2 (jId), 1e-4);
  264. ang1 = d2r(REAL(0.0));
  265. ang2 = d2r(REAL(23.0));
  266. dRFromAxisAndAngle (R, ax2[0], ax2[1], ax2[2], ang2);
  267. dBodySetRotation (bId1, R);
  268. dJointGetUniversalAngles(jId, &angle1, &angle2);
  269. CHECK_CLOSE (angle1, dJointGetUniversalAngle1 (jId), 1e-4);
  270. CHECK_CLOSE (angle2, dJointGetUniversalAngle2 (jId), 1e-4);
  271. ang1 = d2r(REAL(38.0));
  272. dRFromAxisAndAngle (R, ax1[0], ax1[1], ax1[2], ang2);
  273. dBodySetRotation (bId1, R);
  274. ang2 = d2r(REAL(-43.0));
  275. dRFromAxisAndAngle (R, ax2[0], ax2[1], ax2[2], ang2);
  276. dBodySetRotation (bId1, R);
  277. dJointGetUniversalAngles(jId, &angle1, &angle2);
  278. CHECK_CLOSE (angle1, dJointGetUniversalAngle1 (jId), 1e-4);
  279. CHECK_CLOSE (angle2, dJointGetUniversalAngle2 (jId), 1e-4);
  280. }
  281. // =========================================================================
  282. // Test ONE BODY behavior
  283. // =========================================================================
  284. // Test when there is only one body at position one on the joint
  285. TEST_FIXTURE (Fixture_dxJointUniversal_B1_At_Zero_Default_Axes,
  286. test_dJointGetUniversalAngle1_1Body_B1)
  287. {
  288. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  289. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  290. dReal angle1, angle2;
  291. dJointGetUniversalAngles(jId, &angle1, &angle2);
  292. CHECK_CLOSE (0, angle1, 1e-4);
  293. CHECK_CLOSE (0, angle2, 1e-4);
  294. dVector3 axis1;
  295. dJointGetUniversalAxis1 (jId, axis1);
  296. dVector3 axis2;
  297. dJointGetUniversalAxis2 (jId, axis2);
  298. dMatrix3 R;
  299. dReal ang1 = REAL(0.23);
  300. dRFromAxisAndAngle (R, axis1[0], axis1[1], axis1[2], ang1);
  301. dBodySetRotation (bId1, R);
  302. dReal ang2 = REAL(0.0);
  303. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  304. CHECK_CLOSE (-ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  305. dJointGetUniversalAngles(jId, &angle1, &angle2);
  306. CHECK_CLOSE (ang1, angle1, 1e-4);
  307. CHECK_CLOSE (-ang2, angle2, 1e-4);
  308. dMatrix3 I;
  309. dRSetIdentity(I); // Set the rotation of the body to be the Identity (i.e. zero)
  310. dBodySetRotation (bId1, I);
  311. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  312. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  313. // Test the same rotation, when axis1 is inverted
  314. dJointSetUniversalAxis1 (jId, -axis1[0], -axis1[1], -axis1[2]);
  315. dBodySetRotation (bId1, R);
  316. CHECK_CLOSE (-ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  317. CHECK_CLOSE (-ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  318. dJointGetUniversalAngles(jId, &angle1, &angle2);
  319. CHECK_CLOSE (-ang1, angle1, 1e-4);
  320. CHECK_CLOSE (-ang2, angle2, 1e-4);
  321. // Test the same rotation, when axis1 is default and axis2 is inverted
  322. dBodySetRotation (bId1, I);
  323. dJointSetUniversalAxis1 (jId, axis1[0], axis1[1], axis1[2]);
  324. dJointSetUniversalAxis2 (jId, -axis2[0], -axis2[1], -axis2[2]);
  325. dBodySetRotation (bId1, R);
  326. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  327. CHECK_CLOSE (ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  328. dJointGetUniversalAngles(jId, &angle1, &angle2);
  329. CHECK_CLOSE (ang1, angle1, 1e-4);
  330. CHECK_CLOSE (ang2, angle2, 1e-4);
  331. }
  332. // Test when there is only one body at position two on the joint
  333. TEST_FIXTURE (Fixture_dxJointUniversal_B2_At_Zero_Default_Axes,
  334. test_dJointGetUniversalAngle1_1Body_B2)
  335. {
  336. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  337. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  338. dReal angle1, angle2;
  339. dJointGetUniversalAngles(jId, &angle1, &angle2);
  340. CHECK_CLOSE (0, angle1, 1e-4);
  341. CHECK_CLOSE (0, angle2, 1e-4);
  342. dVector3 axis1;
  343. dJointGetUniversalAxis1 (jId, axis1);
  344. dVector3 axis2;
  345. dJointGetUniversalAxis2 (jId, axis2);
  346. dMatrix3 R;
  347. dReal ang1 = REAL(0.0);
  348. dReal ang2 = REAL(0.23);
  349. dRFromAxisAndAngle (R, axis2[0], axis2[1], axis2[2], ang2);
  350. dBodySetRotation (bId2, R);
  351. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  352. CHECK_CLOSE (-ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  353. dJointGetUniversalAngles(jId, &angle1, &angle2);
  354. CHECK_CLOSE (ang1, angle1, 1e-4);
  355. CHECK_CLOSE (-ang2, angle2, 1e-4);
  356. dMatrix3 I;
  357. dRSetIdentity(I); // Set the rotation of the body to be the Identity (i.e. zero)
  358. dBodySetRotation (bId2, I);
  359. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  360. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  361. dJointSetUniversalAxis2 (jId, -axis2[0], -axis2[1], -axis2[2]);
  362. dBodySetRotation (bId2, R);
  363. CHECK_CLOSE (-ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  364. CHECK_CLOSE (ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  365. dJointGetUniversalAngles(jId, &angle1, &angle2);
  366. CHECK_CLOSE (-ang1, angle1, 1e-4);
  367. CHECK_CLOSE (ang2, angle2, 1e-4);
  368. // Test the same rotation, when axis1 is inverted and axis2 is default
  369. dBodySetRotation (bId2, I);
  370. dJointSetUniversalAxis1 (jId, -axis1[0], -axis1[1], -axis1[2]);
  371. dJointSetUniversalAxis2 (jId, axis2[0], axis2[1], axis2[2]);
  372. dBodySetRotation (bId2, R);
  373. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  374. CHECK_CLOSE (-ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  375. dJointGetUniversalAngles(jId, &angle1, &angle2);
  376. CHECK_CLOSE (ang1, angle1, 1e-4);
  377. CHECK_CLOSE (-ang2, angle2, 1e-4);
  378. }
  379. // =========================================================================
  380. //
  381. // =========================================================================
  382. // Test is dJointSetUniversalAxis and dJointGetUniversalAxis return same value
  383. TEST_FIXTURE (Fixture_dxJointUniversal_B1_and_B2_At_Random_Axis_Along_X,
  384. test_dJointSetGetUniversalAxis)
  385. {
  386. dVector3 axisOrig, axis;
  387. dJointGetUniversalAxis1 (jId, axisOrig);
  388. dJointGetUniversalAxis1 (jId, axis);
  389. dJointSetUniversalAxis1 (jId, axis[0], axis[1], axis[2]);
  390. dJointGetUniversalAxis1 (jId, axis);
  391. CHECK_CLOSE (axis[0], axisOrig[0] , 1e-4);
  392. CHECK_CLOSE (axis[1], axisOrig[1] , 1e-4);
  393. CHECK_CLOSE (axis[2], axisOrig[2] , 1e-4);
  394. dJointGetUniversalAxis2 (jId, axisOrig);
  395. dJointGetUniversalAxis2(jId, axis);
  396. dJointSetUniversalAxis2 (jId, axis[0], axis[1], axis[2]);
  397. dJointGetUniversalAxis2 (jId, axis);
  398. CHECK_CLOSE (axis[0], axisOrig[0] , 1e-4);
  399. CHECK_CLOSE (axis[1], axisOrig[1] , 1e-4);
  400. CHECK_CLOSE (axis[2], axisOrig[2] , 1e-4);
  401. dVector3 anchor1, anchor2, anchorOrig1, anchorOrig2;
  402. dJointGetUniversalAnchor (jId, anchorOrig1);
  403. dJointGetUniversalAnchor (jId, anchor1);
  404. dJointGetUniversalAnchor2 (jId, anchorOrig2);
  405. dJointGetUniversalAnchor2 (jId, anchor2);
  406. dJointSetUniversalAnchor (jId, anchor1[0], anchor1[1], anchor1[2]);
  407. dJointGetUniversalAnchor (jId, anchor1);
  408. dJointGetUniversalAnchor2 (jId, anchor2);
  409. CHECK_CLOSE (anchor1[0], anchorOrig1[0] , 1e-4);
  410. CHECK_CLOSE (anchor1[1], anchorOrig1[1] , 1e-4);
  411. CHECK_CLOSE (anchor1[2], anchorOrig1[2] , 1e-4);
  412. CHECK_CLOSE (anchor2[0], anchorOrig2[0] , 1e-4);
  413. CHECK_CLOSE (anchor2[1], anchorOrig2[1] , 1e-4);
  414. CHECK_CLOSE (anchor2[2], anchorOrig2[2] , 1e-4);
  415. }
  416. // Create 2 bodies attached by a Universal joint
  417. // Axis is along the X axis (Default value
  418. // Anchor at (0, 0, 0) (Default value)
  419. //
  420. // ^Y
  421. // |
  422. // * Body2
  423. // |
  424. // |
  425. // Body1 |
  426. // * Z-------->
  427. struct dxJointUniversal_Test_Initialization
  428. {
  429. dxJointUniversal_Test_Initialization()
  430. {
  431. wId = dWorldCreate();
  432. // Remove gravity to have the only force be the force of the joint
  433. dWorldSetGravity(wId, 0,0,0);
  434. for (int j=0; j<2; ++j)
  435. {
  436. bId[j][0] = dBodyCreate (wId);
  437. dBodySetPosition (bId[j][0], -1, -2, -3);
  438. bId[j][1] = dBodyCreate (wId);
  439. dBodySetPosition (bId[j][1], 11, 22, 33);
  440. dMatrix3 R;
  441. dVector3 axis; // Random axis
  442. axis[0] = REAL(0.53);
  443. axis[1] = -REAL(0.71);
  444. axis[2] = REAL(0.43);
  445. dNormalize3(axis);
  446. dRFromAxisAndAngle (R, axis[0], axis[1], axis[2],
  447. REAL(0.47123)); // 27deg
  448. dBodySetRotation (bId[j][0], R);
  449. axis[0] = REAL(1.2);
  450. axis[1] = REAL(0.87);
  451. axis[2] = -REAL(0.33);
  452. dNormalize3(axis);
  453. dRFromAxisAndAngle (R, axis[0], axis[1], axis[2],
  454. REAL(0.47123)); // 27deg
  455. dBodySetRotation (bId[j][1], R);
  456. jId[j] = dJointCreateUniversal (wId, 0);
  457. dJointAttach (jId[j], bId[j][0], bId[j][1]);
  458. dJointSetUniversalParam(jId[j], dParamLoStop, 1);
  459. dJointSetUniversalParam(jId[j], dParamHiStop, 2);
  460. dJointSetUniversalParam(jId[j], dParamFMax, 200);
  461. }
  462. }
  463. ~dxJointUniversal_Test_Initialization()
  464. {
  465. dWorldDestroy (wId);
  466. }
  467. dWorldID wId;
  468. dBodyID bId[2][2];
  469. dJointID jId[2];
  470. };
  471. // Test if setting a Universal with its default values
  472. // will behave the same as a default Universal joint
  473. TEST_FIXTURE (dxJointUniversal_Test_Initialization,
  474. test_Universal_Initialization)
  475. {
  476. using namespace std;
  477. dVector3 axis;
  478. dJointGetUniversalAxis1(jId[1], axis);
  479. dJointSetUniversalAxis1(jId[1], axis[0], axis[1], axis[2]);
  480. dJointGetUniversalAxis2(jId[1], axis);
  481. dJointSetUniversalAxis2(jId[1], axis[0], axis[1], axis[2]);
  482. dVector3 anchor;
  483. dJointGetUniversalAnchor(jId[1], anchor);
  484. dJointSetUniversalAnchor(jId[1], anchor[0], anchor[1], anchor[2]);
  485. for (int b=0; b<2; ++b)
  486. {
  487. // Compare body b of the first joint with its equivalent on the
  488. // second joint
  489. const dReal *qA = dBodyGetQuaternion(bId[0][b]);
  490. const dReal *qB = dBodyGetQuaternion(bId[1][b]);
  491. CHECK_CLOSE (qA[0], qB[0], 1e-4);
  492. CHECK_CLOSE (qA[1], qB[1], 1e-4);
  493. CHECK_CLOSE (qA[2], qB[2], 1e-4);
  494. CHECK_CLOSE (qA[3], qB[3], 1e-4);
  495. }
  496. dWorldStep (wId,0.5);
  497. dWorldStep (wId,0.5);
  498. dWorldStep (wId,0.5);
  499. dWorldStep (wId,0.5);
  500. for (int b=0; b<2; ++b)
  501. {
  502. // Compare body b of the first joint with its equivalent on the
  503. // second joint
  504. const dReal *qA = dBodyGetQuaternion(bId[0][b]);
  505. const dReal *qB = dBodyGetQuaternion(bId[1][b]);
  506. CHECK_CLOSE (qA[0], qB[0], 1e-4);
  507. CHECK_CLOSE (qA[1], qB[1], 1e-4);
  508. CHECK_CLOSE (qA[2], qB[2], 1e-4);
  509. CHECK_CLOSE (qA[3], qB[3], 1e-4);
  510. const dReal *posA = dBodyGetPosition(bId[0][b]);
  511. const dReal *posB = dBodyGetPosition(bId[1][b]);
  512. CHECK_CLOSE (posA[0], posB[0], 1e-4);
  513. CHECK_CLOSE (posA[1], posB[1], 1e-4);
  514. CHECK_CLOSE (posA[2], posB[2], 1e-4);
  515. CHECK_CLOSE (posA[3], posB[3], 1e-4);
  516. }
  517. }
  518. // ==========================================================================
  519. // Testing the offset
  520. // TODO:
  521. // - Test Axis1Offset(...., 0, ang2);
  522. // ==========================================================================
  523. // Rotate first body 90deg around X (Axis1) then back to original position
  524. //
  525. // ^ ^ ^ Z ^
  526. // | | => <--- | |
  527. // | | | |
  528. // B1 B2 B1 B2 .----->Y
  529. // /
  530. // /
  531. // v X (N.B. X is going out of the screen)
  532. //
  533. // Set Axis1 with an Offset of 90deg
  534. // ^ ^ ^
  535. // <--- | => | |
  536. // | | |
  537. // B1 B2 B1 B2
  538. TEST_FIXTURE (Fixture_dxJointUniversal_B1_and_B2_At_Zero_Axis1_Along_X_Axis2_Along_Y,
  539. test_dJointSetUniversalAxis1Offset_B1_90deg)
  540. {
  541. dMatrix3 R;
  542. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  543. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  544. dReal angle1, angle2;
  545. dJointGetUniversalAngles(jId, &angle1, &angle2);
  546. CHECK_CLOSE (0, angle1, 1e-4);
  547. CHECK_CLOSE (0, angle2, 1e-4);
  548. dVector3 axis;
  549. dJointGetUniversalAxis1 (jId, axis);
  550. dReal ang1 = d2r(REAL(90.0));
  551. dReal ang2 = d2r(REAL(0.0));
  552. dRFromAxisAndAngle (R, axis[0], axis[1], axis[2], ang1);
  553. dBodySetRotation (bId1, R);
  554. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  555. CHECK_CLOSE (ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  556. dJointGetUniversalAngles(jId, &angle1, &angle2);
  557. CHECK_CLOSE (ang1, angle1, 1e-4);
  558. CHECK_CLOSE (ang2, angle2, 1e-4);
  559. dJointSetUniversalAxis1Offset (jId, axis[0], axis[1], axis[2],
  560. ang1, ang2);
  561. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  562. CHECK_CLOSE (ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  563. dJointGetUniversalAngles(jId, &angle1, &angle2);
  564. CHECK_CLOSE (ang1, angle1, 1e-4);
  565. CHECK_CLOSE (ang2, angle2, 1e-4);
  566. dRSetIdentity(R); // Set the rotation of the body to be zero
  567. dBodySetRotation (bId1, R);
  568. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  569. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  570. dJointGetUniversalAngles(jId, &angle1, &angle2);
  571. CHECK_CLOSE (0, angle1, 1e-4);
  572. CHECK_CLOSE (0, angle2, 1e-4);
  573. }
  574. // Rotate 2nd body 90deg around (Axis2) then back to original position
  575. // Offset when setting axis1
  576. //
  577. // ^ ^ ^ Z ^
  578. // | | => <--- | |
  579. // | | | |
  580. // B1 B2 B1 B2 .----->Y
  581. // /
  582. // /
  583. // v X (N.B. X is going out of the screen)
  584. //
  585. // Set Axis1 with an Offset of 90deg
  586. // ^ ^ ^
  587. // <--- | => | |
  588. // | | |
  589. // B1 B2 B1 B2
  590. TEST_FIXTURE (Fixture_dxJointUniversal_B1_and_B2_At_Zero_Axis1_Along_X_Axis2_Along_Y,
  591. test_dJointSetUniversalAxis1Offset_B2_90deg)
  592. {
  593. dMatrix3 R;
  594. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  595. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  596. dReal angle1, angle2;
  597. dJointGetUniversalAngles(jId, &angle1, &angle2);
  598. CHECK_CLOSE (0, angle1, 1e-4);
  599. CHECK_CLOSE (0, angle2, 1e-4);
  600. dVector3 ax1, ax2;
  601. dJointGetUniversalAxis1 (jId, ax1);
  602. dJointGetUniversalAxis2 (jId, ax2);
  603. dReal ang1 = d2r(REAL(0.0));
  604. dReal ang2 = d2r(REAL(90.0));
  605. dRFromAxisAndAngle (R, ax2[0], ax2[1], ax2[2], ang2);
  606. dBodySetRotation (bId2, R);
  607. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  608. CHECK_CLOSE (-ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  609. dJointGetUniversalAngles(jId, &angle1, &angle2);
  610. CHECK_CLOSE (ang1, angle1, 1e-4);
  611. CHECK_CLOSE (-ang2, angle2, 1e-4);
  612. dJointSetUniversalAxis1Offset (jId, ax1[0], ax1[1], ax1[2],
  613. ang1, -ang2);
  614. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  615. CHECK_CLOSE (-ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  616. dJointGetUniversalAngles(jId, &angle1, &angle2);
  617. CHECK_CLOSE (ang1, angle1, 1e-4);
  618. CHECK_CLOSE (-ang2, angle2, 1e-4);
  619. dRSetIdentity(R); // Set the rotation of the body to be zero
  620. dBodySetRotation (bId1, R);
  621. dBodySetRotation (bId2, R);
  622. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  623. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  624. dJointGetUniversalAngles(jId, &angle1, &angle2);
  625. CHECK_CLOSE (0, angle1, 1e-4);
  626. CHECK_CLOSE (0, angle2, 1e-4);
  627. }
  628. // Rotate second body 90deg around Y (Axis2) then back to original position
  629. //
  630. // ^ ^ ^ Z ^
  631. // | | => | . |
  632. // | | | |
  633. // B1 B2 B1 B2 .----->Y
  634. // /
  635. // /
  636. // v X (N.B. X is going out of the screen)
  637. //
  638. // Set Axis2 with an Offset of 90deg
  639. // ^ ^ ^
  640. // | . => | |
  641. // | | |
  642. // B1 B2 B1 B2
  643. TEST_FIXTURE (Fixture_dxJointUniversal_B1_and_B2_At_Zero_Axis1_Along_X_Axis2_Along_Y,
  644. test_dJointSetUniversalAxisOffset_B2_90deg)
  645. {
  646. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  647. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  648. dReal angle1, angle2;
  649. dJointGetUniversalAngles(jId, &angle1, &angle2);
  650. CHECK_CLOSE (0, angle1, 1e-4);
  651. CHECK_CLOSE (0, angle2, 1e-4);
  652. dVector3 axis;
  653. dJointGetUniversalAxis2 (jId, axis);
  654. dReal ang1 = d2r(REAL(0.0));
  655. dReal ang2 = d2r(REAL(90.0));
  656. dMatrix3 R;
  657. dRFromAxisAndAngle (R, axis[0], axis[1], axis[2], ang2);
  658. dBodySetRotation (bId2, R);
  659. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  660. CHECK_CLOSE (-ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  661. dJointGetUniversalAngles(jId, &angle1, &angle2);
  662. CHECK_CLOSE (ang1, angle1, 1e-4);
  663. CHECK_CLOSE (-ang2, angle2, 1e-4);
  664. dJointSetUniversalAxis2Offset (jId, axis[0], axis[1], axis[2],
  665. ang1, -ang2);
  666. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  667. CHECK_CLOSE (-ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  668. dJointGetUniversalAngles(jId, &angle1, &angle2);
  669. CHECK_CLOSE (ang1, angle1, 1e-4);
  670. CHECK_CLOSE (-ang2, angle2, 1e-4);
  671. dRSetIdentity(R); // Set the rotation of the body to be zero
  672. dBodySetRotation (bId2, R);
  673. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  674. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  675. dJointGetUniversalAngles(jId, &angle1, &angle2);
  676. CHECK_CLOSE (0, angle1, 1e-4);
  677. CHECK_CLOSE (0, angle2, 1e-4);
  678. }
  679. // Rotate 2nd body -90deg around Y (Axis2) then back to original position
  680. //
  681. // ^ ^ ^ Z ^
  682. // | | => | x |
  683. // | | | |
  684. // B1 B2 B1 B2 X .----> Y
  685. // N.B. X is going out of the screen
  686. // Start with a Delta of 90deg
  687. // ^ ^ ^
  688. // | x => | |
  689. // | | |
  690. // B1 B2 B1 B2
  691. TEST_FIXTURE (Fixture_dxJointUniversal_B1_and_B2_At_Zero_Axis1_Along_X_Axis2_Along_Y,
  692. test_dJointSetUniversalAxisOffset_B2_Minus90deg)
  693. {
  694. CHECK_CLOSE (dJointGetUniversalAngle1 (jId), 0, 1e-4);
  695. CHECK_CLOSE (dJointGetUniversalAngle2 (jId), 0, 1e-4);
  696. dReal angle1, angle2;
  697. dJointGetUniversalAngles(jId, &angle1, &angle2);
  698. CHECK_CLOSE (0, angle1, 1e-4);
  699. CHECK_CLOSE (0, angle2, 1e-4);
  700. dVector3 axis;
  701. dJointGetUniversalAxis2 (jId, axis);
  702. dReal ang1 = d2r(REAL(0.0));
  703. dReal ang2 = d2r(REAL(90.0));
  704. dMatrix3 R;
  705. dRFromAxisAndAngle (R, axis[0], axis[1], axis[2], -ang2);
  706. dBodySetRotation (bId2, R);
  707. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  708. CHECK_CLOSE (ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  709. dJointGetUniversalAngles(jId, &angle1, &angle2);
  710. CHECK_CLOSE (ang1, angle1, 1e-4);
  711. CHECK_CLOSE (ang2, angle2, 1e-4);
  712. dJointSetUniversalAxis2Offset (jId, axis[0], axis[1], axis[2],
  713. ang1, ang2);
  714. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  715. CHECK_CLOSE (ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  716. dJointGetUniversalAngles(jId, &angle1, &angle2);
  717. CHECK_CLOSE (ang1, angle1, 1e-4);
  718. CHECK_CLOSE (ang2, angle2, 1e-4);
  719. dRFromAxisAndAngle (R, axis[0], axis[1], axis[2], 0);
  720. dBodySetRotation (bId2, R);
  721. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  722. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  723. dJointGetUniversalAngles(jId, &angle1, &angle2);
  724. CHECK_CLOSE (0, angle1, 1e-4);
  725. CHECK_CLOSE (0, angle2, 1e-4);
  726. }
  727. // Rotate 1st body 0.23rad around X (Axis1) then back to original position
  728. //
  729. // ^ ^ ^ ^ Z ^
  730. // | | => \ | |
  731. // | | \ | |
  732. // B1 B2 B1 B2 .-------> Y
  733. // /
  734. // /
  735. // v X (N.B. X is going out of the screen)
  736. //
  737. // Start with a Delta of 0.23rad
  738. // ^ ^ ^ ^
  739. // \ | => | |
  740. // \ | | |
  741. // B1 B2 B1 B2
  742. TEST_FIXTURE (Fixture_dxJointUniversal_B1_and_B2_At_Zero_Axis1_Along_X_Axis2_Along_Y,
  743. test_dJointSetUniversalAxis1Offset_B1_0_23rad)
  744. {
  745. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  746. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  747. dReal angle1, angle2;
  748. dJointGetUniversalAngles(jId, &angle1, &angle2);
  749. CHECK_CLOSE (0, angle1, 1e-4);
  750. CHECK_CLOSE (0, angle2, 1e-4);
  751. dVector3 axis;
  752. dJointGetUniversalAxis1 (jId, axis);
  753. dReal ang1 = REAL(0.23);
  754. dReal ang2 = REAL(0.0);
  755. dMatrix3 R;
  756. dRFromAxisAndAngle (R, axis[0], axis[1], axis[2], ang1);
  757. dBodySetRotation (bId1, R);
  758. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  759. CHECK_CLOSE (ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  760. dJointSetUniversalAxis1Offset (jId, axis[0], axis[1], axis[2],
  761. ang1, ang2);
  762. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  763. CHECK_CLOSE (ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  764. dJointGetUniversalAngles(jId, &angle1, &angle2);
  765. CHECK_CLOSE (ang1, angle1, 1e-4);
  766. CHECK_CLOSE (ang2, angle2, 1e-4);
  767. dRSetIdentity(R); // Set the rotation of the body to be zero
  768. dBodySetRotation (bId1, R);
  769. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  770. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  771. dJointGetUniversalAngles(jId, &angle1, &angle2);
  772. CHECK_CLOSE (0, angle1, 1e-4);
  773. CHECK_CLOSE (0, angle2, 1e-4);
  774. }
  775. // Rotate 2nd body 0.23rad around Y (Axis2) then back to original position
  776. //
  777. // ^ ^ ^ ^ Z ^ ^ Y (N.B. Y is going in the screen)
  778. // | | => | / | /
  779. // | | | / | /
  780. // B1 B2 B1 B2 .-------> X
  781. //
  782. // Start with a Delta of 0.23rad
  783. // ^ ^ ^ ^
  784. // | / => | |
  785. // | / | |
  786. // B1 B2 B1 B2
  787. TEST_FIXTURE (Fixture_dxJointUniversal_B1_and_B2_At_Zero_Axis1_Along_X_Axis2_Along_Y,
  788. test_dJointSetUniversalAxisOffset_B2_0_23rad)
  789. {
  790. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  791. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  792. dReal angle1, angle2;
  793. dJointGetUniversalAngles(jId, &angle1, &angle2);
  794. CHECK_CLOSE (0, angle1, 1e-4);
  795. CHECK_CLOSE (0, angle2, 1e-4);
  796. dVector3 axis;
  797. dJointGetUniversalAxis2 (jId, axis);
  798. dReal ang1 = REAL(0.0);
  799. dReal ang2 = REAL(0.23);
  800. dMatrix3 R;
  801. dRFromAxisAndAngle (R, axis[0], axis[1], axis[2], ang2);
  802. dBodySetRotation (bId2, R);
  803. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  804. CHECK_CLOSE (-ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  805. dJointSetUniversalAxis2Offset (jId, axis[0], axis[1], axis[2],
  806. ang1, -ang2);
  807. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  808. CHECK_CLOSE (-ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  809. dJointGetUniversalAngles(jId, &angle1, &angle2);
  810. CHECK_CLOSE (ang1, angle1, 1e-4);
  811. CHECK_CLOSE (-ang2, angle2, 1e-4);
  812. dRSetIdentity(R); // Set the rotation of the body to be zero
  813. dBodySetRotation (bId2, R);
  814. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  815. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  816. dJointGetUniversalAngles(jId, &angle1, &angle2);
  817. CHECK_CLOSE (0, angle1, 1e-4);
  818. CHECK_CLOSE (0, angle2, 1e-4);
  819. }
  820. // Rotate 1st body 0.23rad around X axis and 2nd body 0.37rad around Y (Axis2)
  821. // then back to their original position.
  822. // The Axis offset are set one at a time
  823. //
  824. // ^ ^ ^ ^ Z ^ ^ Y (N.B. Y is going in the screen)
  825. // | | => \ / | /
  826. // | | \ / | /
  827. // B1 B2 B1 B2 .-------> X
  828. //
  829. // Start with a Delta of 0.23rad
  830. // ^ ^ ^ ^
  831. // \ / => | |
  832. // \ / | |
  833. // B1 B2 B1 B2
  834. TEST_FIXTURE (Fixture_dxJointUniversal_B1_and_B2_At_Zero_Axis1_Along_X_Axis2_Along_Y,
  835. test_dJointSetUniversalAxisOffset_B1_0_23rad_B2_0_37rad_One_by_One)
  836. {
  837. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  838. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  839. dReal angle1, angle2;
  840. dJointGetUniversalAngles(jId, &angle1, &angle2);
  841. CHECK_CLOSE (0, angle1, 1e-4);
  842. CHECK_CLOSE (0, angle2, 1e-4);
  843. dVector3 axis1;
  844. dJointGetUniversalAxis1 (jId, axis1);
  845. dVector3 axis2;
  846. dJointGetUniversalAxis2 (jId, axis2);
  847. dMatrix3 R;
  848. dReal ang1 = REAL(0.23);
  849. dRFromAxisAndAngle (R, axis1[0], axis1[1], axis1[2], ang1);
  850. dBodySetRotation (bId1, R);
  851. dReal ang2 = REAL(0.37);
  852. dRFromAxisAndAngle (R, axis2[0], axis2[1], axis2[2], ang2);
  853. dBodySetRotation (bId2, R);
  854. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  855. CHECK_CLOSE (-ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  856. dJointGetUniversalAngles(jId, &angle1, &angle2);
  857. CHECK_CLOSE (ang1, angle1, 1e-4);
  858. CHECK_CLOSE (-ang2, angle2, 1e-4);
  859. dJointSetUniversalAxis1Offset (jId, axis1[0], axis1[1], axis1[2],
  860. ang1, -ang2 );
  861. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  862. CHECK_CLOSE (-ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  863. dJointGetUniversalAngles(jId, &angle1, &angle2);
  864. CHECK_CLOSE (ang1, angle1, 1e-4);
  865. CHECK_CLOSE (-ang2, angle2, 1e-4);
  866. dJointGetUniversalAxis1 (jId, axis1);
  867. dJointGetUniversalAxis2 (jId, axis2);
  868. dRFromAxisAndAngle (R, axis2[0], axis2[1], axis2[2], ang2);
  869. dBodySetRotation (bId2, R);
  870. dJointSetUniversalAxis2Offset (jId, axis2[0], axis2[1], axis2[2],
  871. ang1, -ang2);
  872. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  873. CHECK_CLOSE (-ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  874. dJointGetUniversalAngles(jId, &angle1, &angle2);
  875. CHECK_CLOSE (ang1, angle1, 1e-4);
  876. CHECK_CLOSE (-ang2, angle2, 1e-4);
  877. dRSetIdentity(R); // Set the rotation of the body to be zero
  878. dBodySetRotation (bId1, R);
  879. dBodySetRotation (bId2, R);
  880. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  881. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  882. dJointGetUniversalAngles(jId, &angle1, &angle2);
  883. CHECK_CLOSE (0, angle1, 1e-4);
  884. CHECK_CLOSE (0, angle2, 1e-4);
  885. }
  886. // The 2 bodies are positionned at (0, 0, 0), with no rotation
  887. // The joint is an Universal Joint.
  888. // Axis in the inverse direction of the X axis
  889. // Anchor at (0, 0, 0)
  890. // ^Y
  891. // |
  892. // |
  893. // |
  894. // |
  895. // |
  896. // Z <---- x (X going out of the page)
  897. struct Fixture_dxJointUniversal_B1_and_B2_At_Zero_Axis1_Inverse_of_X
  898. {
  899. Fixture_dxJointUniversal_B1_and_B2_At_Zero_Axis1_Inverse_of_X()
  900. {
  901. wId = dWorldCreate();
  902. bId1 = dBodyCreate (wId);
  903. dBodySetPosition (bId1, 0, 0, 0);
  904. bId2 = dBodyCreate (wId);
  905. dBodySetPosition (bId2, 0, 0, 0);
  906. jId = dJointCreateUniversal (wId, 0);
  907. joint = (dxJointUniversal*) jId;
  908. dJointAttach (jId, bId1, bId2);
  909. dJointSetUniversalAnchor (jId, 0, 0, 0);
  910. axis[0] = -1;
  911. axis[1] = 0;
  912. axis[2] = 0;
  913. dJointSetUniversalAxis1(jId, axis[0], axis[1], axis[2]);
  914. }
  915. ~Fixture_dxJointUniversal_B1_and_B2_At_Zero_Axis1_Inverse_of_X()
  916. {
  917. dWorldDestroy (wId);
  918. }
  919. dWorldID wId;
  920. dBodyID bId1;
  921. dBodyID bId2;
  922. dJointID jId;
  923. dxJointUniversal* joint;
  924. dVector3 axis;
  925. };
  926. // No offset when setting the Axis1 offset
  927. // x is a Symbol for lines pointing into the screen
  928. // . is a Symbol for lines pointing out of the screen
  929. //
  930. // In 2D In 3D
  931. // ^ ^ ^ ^ Z ^ ^ Y
  932. // | | => | | | /
  933. // | | | | | /
  934. // B1 B2 B1 B2 .-------> X <-- Axis1
  935. //
  936. // Start with a Delta of 90deg
  937. // ^ ^ ^ ^
  938. // | | => | |
  939. // | | | |
  940. // B1 B2 B1 B2
  941. TEST_FIXTURE (Fixture_dxJointUniversal_B1_and_B2_At_Zero_Axis1_Inverse_of_X,
  942. test_dJointSetUniversalAxis1Offset_No_Offset_Axis1_Inverse_of_X)
  943. {
  944. CHECK_CLOSE (dJointGetUniversalAngle1 (jId), 0, 1e-4);
  945. CHECK_CLOSE (dJointGetUniversalAngle2 (jId), 0, 1e-4);
  946. dReal angle1, angle2;
  947. dJointGetUniversalAngles(jId, &angle1, &angle2);
  948. CHECK_CLOSE (0, angle1, 1e-4);
  949. CHECK_CLOSE (0, angle2, 1e-4);
  950. dVector3 axis;
  951. dJointGetUniversalAxis1 (jId, axis);
  952. dReal ang1 = REAL(0.0);
  953. dReal ang2 = REAL(0.0);
  954. dMatrix3 R;
  955. dRFromAxisAndAngle (R, axis[0], axis[1], axis[2], ang1);
  956. dBodySetRotation (bId1, R);
  957. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  958. CHECK_CLOSE (ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  959. dJointSetUniversalAxis1Offset (jId, axis[0], axis[1], axis[2],
  960. ang1, ang2);
  961. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  962. CHECK_CLOSE (ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  963. dJointGetUniversalAngles(jId, &angle1, &angle2);
  964. CHECK_CLOSE (ang1, angle1, 1e-4);
  965. CHECK_CLOSE (ang2, angle2, 1e-4);
  966. dRSetIdentity(R); // Set the rotation of the body to be zero
  967. dBodySetRotation (bId1, R);
  968. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  969. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  970. dJointGetUniversalAngles(jId, &angle1, &angle2);
  971. CHECK_CLOSE (0, angle1, 1e-4);
  972. CHECK_CLOSE (0, angle2, 1e-4);
  973. }
  974. // Rotate 1st body 90deg around axis1 then back to original position
  975. // x is a Symbol for lines pointing into the screen
  976. // . is a Symbol for lines pointing out of the screen
  977. //
  978. // In 2D In 3D
  979. // ^ ^ ^ Z ^ ^ Y
  980. // | | => x | | /
  981. // | | | | /
  982. // B1 B2 B1 B2 .-------> X <-- Axis1
  983. //
  984. // Start with a Delta of 90deg
  985. // ^ ^ ^
  986. // x | => | |
  987. // | | |
  988. // B1 B2 B1 B2
  989. TEST_FIXTURE (Fixture_dxJointUniversal_B1_and_B2_At_Zero_Axis1_Inverse_of_X,
  990. test_dJointSetUniversalAxis1Offset_B1_90Deg_Axis1_Inverse_of_X)
  991. {
  992. CHECK_CLOSE (dJointGetUniversalAngle1 (jId), 0, 1e-4);
  993. CHECK_CLOSE (dJointGetUniversalAngle2 (jId), 0, 1e-4);
  994. dReal angle1, angle2;
  995. dJointGetUniversalAngles(jId, &angle1, &angle2);
  996. CHECK_CLOSE (0, angle1, 1e-4);
  997. CHECK_CLOSE (0, angle2, 1e-4);
  998. dVector3 axis;
  999. dJointGetUniversalAxis1 (jId, axis);
  1000. dReal ang1 = d2r(90);
  1001. dReal ang2 = REAL(0.0);
  1002. dMatrix3 R;
  1003. dRFromAxisAndAngle (R, axis[0], axis[1], axis[2], ang1);
  1004. dBodySetRotation (bId1, R);
  1005. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  1006. CHECK_CLOSE (ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  1007. dJointSetUniversalAxis1Offset (jId, axis[0], axis[1], axis[2],
  1008. ang1, ang2);
  1009. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  1010. CHECK_CLOSE (ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  1011. dJointGetUniversalAngles(jId, &angle1, &angle2);
  1012. CHECK_CLOSE (ang1, angle1, 1e-4);
  1013. CHECK_CLOSE (ang2, angle2, 1e-4);
  1014. dRSetIdentity(R); // Set the rotation of the body to be zero
  1015. dBodySetRotation (bId1, R);
  1016. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  1017. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  1018. dJointGetUniversalAngles(jId, &angle1, &angle2);
  1019. CHECK_CLOSE (0, angle1, 1e-4);
  1020. CHECK_CLOSE (0, angle2, 1e-4);
  1021. }
  1022. // No offset when setting the Axis 2 offset
  1023. // x is a Symbol for lines pointing into the screen
  1024. // . is a Symbol for lines pointing out of the screen
  1025. //
  1026. // In 2D In 3D
  1027. // ^ ^ ^ ^ Z ^ ^ Y ^ Axis2
  1028. // | | => | | | / /
  1029. // | | | | | / /
  1030. // B1 B2 B1 B2 . -------> <-- Axis1
  1031. //
  1032. // Start with a Delta of 90deg
  1033. // ^ ^ ^ ^
  1034. // | | => | |
  1035. // | | | |
  1036. // B1 B2 B1 B2
  1037. TEST_FIXTURE (Fixture_dxJointUniversal_B1_and_B2_At_Zero_Axis1_Inverse_of_X,
  1038. test_dJointSetUniversalAxis2Offset_No_Offset_Axis2_Inverse_of_X)
  1039. {
  1040. CHECK_CLOSE (dJointGetUniversalAngle1 (jId), 0, 1e-4);
  1041. CHECK_CLOSE (dJointGetUniversalAngle2 (jId), 0, 1e-4);
  1042. dReal angle1, angle2;
  1043. dJointGetUniversalAngles(jId, &angle1, &angle2);
  1044. CHECK_CLOSE (0, angle1, 1e-4);
  1045. CHECK_CLOSE (0, angle2, 1e-4);
  1046. dVector3 axis;
  1047. dJointGetUniversalAxis2 (jId, axis);
  1048. dReal ang1 = d2r(REAL(0.0));
  1049. dReal ang2 = d2r(REAL(0.0));
  1050. dMatrix3 R;
  1051. dRFromAxisAndAngle (R, axis[0], axis[1], axis[2], ang2);
  1052. dBodySetRotation (bId2, R);
  1053. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  1054. CHECK_CLOSE (-ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  1055. dJointSetUniversalAxis2Offset (jId, axis[0], axis[1], axis[2],
  1056. ang1, -ang2);
  1057. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  1058. CHECK_CLOSE (-ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  1059. dJointGetUniversalAngles(jId, &angle1, &angle2);
  1060. CHECK_CLOSE (ang1, angle1, 1e-4);
  1061. CHECK_CLOSE (-ang2, angle2, 1e-4);
  1062. dRSetIdentity(R); // Set the rotation of the body to be zero
  1063. dBodySetRotation (bId2, R);
  1064. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  1065. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  1066. dJointGetUniversalAngles(jId, &angle1, &angle2);
  1067. CHECK_CLOSE (0, angle1, 1e-4);
  1068. CHECK_CLOSE (0, angle2, 1e-4);
  1069. }
  1070. // Rotate 2nd body 90deg around axis2 then back to original position
  1071. //
  1072. // In 2D In 3D
  1073. // ^ ^ ^ Z ^ ^ Y ^ Axis2
  1074. // | | => | --> | / /
  1075. // | | | | / /
  1076. // B1 B2 B1 B2 . -------> <-- Axis1
  1077. //
  1078. // Start with a Delta of 90deg
  1079. // ^ ^ ^
  1080. // | <--- => | |
  1081. // | | |
  1082. // B1 B2 B1 B2
  1083. TEST_FIXTURE (Fixture_dxJointUniversal_B1_and_B2_At_Zero_Axis1_Inverse_of_X,
  1084. test_dJointSetUniversalAxisOffset_B2_90Deg)
  1085. {
  1086. CHECK_CLOSE (dJointGetUniversalAngle1 (jId), 0, 1e-4);
  1087. CHECK_CLOSE (dJointGetUniversalAngle2 (jId), 0, 1e-4);
  1088. dReal angle1, angle2;
  1089. dJointGetUniversalAngles(jId, &angle1, &angle2);
  1090. CHECK_CLOSE (0, angle1, 1e-4);
  1091. CHECK_CLOSE (0, angle2, 1e-4);
  1092. dVector3 axis;
  1093. dJointGetUniversalAxis2 (jId, axis);
  1094. dReal ang1 = d2r(REAL(0.0));
  1095. dReal ang2 = d2r(REAL(90.0));
  1096. dMatrix3 R;
  1097. dRFromAxisAndAngle (R, axis[0], axis[1], axis[2], ang2);
  1098. dBodySetRotation (bId2, R);
  1099. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  1100. CHECK_CLOSE (-ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  1101. dJointSetUniversalAxis2Offset (jId, axis[0], axis[1], axis[2],
  1102. ang1, -ang2);
  1103. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  1104. CHECK_CLOSE (-ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  1105. dJointGetUniversalAngles(jId, &angle1, &angle2);
  1106. CHECK_CLOSE (ang1, angle1, 1e-4);
  1107. CHECK_CLOSE (-ang2, angle2, 1e-4);
  1108. dRSetIdentity(R); // Set the rotation of the body to be zero
  1109. dBodySetRotation (bId2, R);
  1110. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  1111. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  1112. dJointGetUniversalAngles(jId, &angle1, &angle2);
  1113. CHECK_CLOSE (0, angle1, 1e-4);
  1114. CHECK_CLOSE (0, angle2, 1e-4);
  1115. }
  1116. // Rotate 2nd body -90deg around axis2 then back to original position
  1117. //
  1118. // ^ ^ ^
  1119. // | | => | --->
  1120. // | | |
  1121. // B1 B2 B1 B2
  1122. //
  1123. // Start with a Delta of 90deg
  1124. // ^ ^ ^
  1125. // | ---> => | |
  1126. // | | |
  1127. // B1 B2 B1 B2
  1128. TEST_FIXTURE (Fixture_dxJointUniversal_B1_and_B2_At_Zero_Axis1_Inverse_of_X,
  1129. test_dJointSetUniversalAxis1Offset_B2_Minus90Deg)
  1130. {
  1131. CHECK_CLOSE (dJointGetUniversalAngle1 (jId), 0, 1e-4);
  1132. CHECK_CLOSE (dJointGetUniversalAngle2 (jId), 0, 1e-4);
  1133. dReal angle1, angle2;
  1134. dJointGetUniversalAngles(jId, &angle1, &angle2);
  1135. CHECK_CLOSE (0, angle1, 1e-4);
  1136. CHECK_CLOSE (0, angle2, 1e-4);
  1137. dVector3 axis;
  1138. dJointGetUniversalAxis2 (jId, axis);
  1139. dReal ang1 = d2r(0.0);
  1140. dReal ang2 = d2r(REAL(-90.0));
  1141. dMatrix3 R;
  1142. dRFromAxisAndAngle (R, axis[0], axis[1], axis[2], ang2);
  1143. dBodySetRotation (bId2, R);
  1144. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  1145. CHECK_CLOSE (-ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  1146. dJointGetUniversalAngles(jId, &angle1, &angle2);
  1147. CHECK_CLOSE (ang1, angle1, 1e-4);
  1148. CHECK_CLOSE (-ang2, angle2, 1e-4);
  1149. dJointGetUniversalAxis1 (jId, axis);
  1150. dJointSetUniversalAxis1Offset (jId, axis[0], axis[1], axis[2],
  1151. ang1, -ang2);
  1152. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  1153. CHECK_CLOSE (-ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  1154. dJointGetUniversalAngles(jId, &angle1, &angle2);
  1155. CHECK_CLOSE (ang1, angle1, 1e-4);
  1156. CHECK_CLOSE (-ang2, angle2, 1e-4);
  1157. dRSetIdentity(R); // Set the rotation of the body to be zero
  1158. dBodySetRotation (bId2, R);
  1159. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  1160. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  1161. dJointGetUniversalAngles(jId, &angle1, &angle2);
  1162. CHECK_CLOSE (0, angle1, 1e-4);
  1163. CHECK_CLOSE (0, angle2, 1e-4);
  1164. }
  1165. // Rotate 1st body 0.23rad around X then back to original position
  1166. //
  1167. // ^ ^ ^ ^
  1168. // | | => \ |
  1169. // | | \ |
  1170. // B1 B2 B1 B2
  1171. //
  1172. // Start with a Delta of 0.23rad
  1173. // ^ ^ ^ ^
  1174. // \ | => | |
  1175. // \ | | |
  1176. // B1 B2 B1 B2
  1177. TEST_FIXTURE (Fixture_dxJointUniversal_B1_and_B2_At_Zero_Axis1_Inverse_of_X,
  1178. test_dJointSetUniversalAxis1Offset_B1_0_23rad)
  1179. {
  1180. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  1181. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  1182. dReal angle1, angle2;
  1183. dJointGetUniversalAngles(jId, &angle1, &angle2);
  1184. CHECK_CLOSE (0, angle1, 1e-4);
  1185. CHECK_CLOSE (0, angle2, 1e-4);
  1186. dVector3 axis;
  1187. dJointGetUniversalAxis1 (jId, axis);
  1188. dReal ang1 = REAL(0.23);
  1189. dReal ang2 = REAL(0.0);
  1190. dMatrix3 R;
  1191. dRFromAxisAndAngle (R, axis[0], axis[1], axis[2], ang1);
  1192. dBodySetRotation (bId1, R);
  1193. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  1194. CHECK_CLOSE (-ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  1195. dJointSetUniversalAxis1Offset (jId, axis[0], axis[1], axis[2], ang1, ang2);
  1196. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  1197. CHECK_CLOSE (-ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  1198. dJointGetUniversalAngles(jId, &angle1, &angle2);
  1199. CHECK_CLOSE (ang1, angle1, 1e-4);
  1200. CHECK_CLOSE (-ang2, angle2, 1e-4);
  1201. dRSetIdentity(R); // Set the rotation of the body to be zero
  1202. dBodySetRotation (bId1, R);
  1203. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  1204. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  1205. dJointGetUniversalAngles(jId, &angle1, &angle2);
  1206. CHECK_CLOSE (0, angle1, 1e-4);
  1207. CHECK_CLOSE (0, angle2, 1e-4);
  1208. }
  1209. // Rotate 2nd body -0.23rad around Z then back to original position
  1210. //
  1211. // ^ ^ ^ ^
  1212. // | | => / |
  1213. // | | / |
  1214. // B1 B2 B1 B2
  1215. //
  1216. // Start with a Delta of 0.23rad
  1217. // ^ ^ ^ ^
  1218. // / | => | |
  1219. // / | | |
  1220. // B1 B2 B1 B2
  1221. TEST_FIXTURE (Fixture_dxJointUniversal_B1_and_B2_At_Zero_Axis1_Inverse_of_X,
  1222. test_dJointSetUniversalAxisOffset_B1_Minus0_23rad)
  1223. {
  1224. CHECK_CLOSE (dJointGetUniversalAngle1 (jId), 0, 1e-4);
  1225. dMatrix3 R;
  1226. dRFromAxisAndAngle (R, 1, 0, 0, -REAL(0.23));
  1227. dBodySetRotation (bId1, R);
  1228. CHECK_CLOSE (REAL(0.23), dJointGetUniversalAngle1 (jId), 1e-4);
  1229. dVector3 axis;
  1230. dJointGetUniversalAxis1 (jId, axis);
  1231. dJointSetUniversalAxis1Offset (jId, axis[0], axis[1], axis[2], REAL(0.23), 0);
  1232. CHECK_CLOSE (REAL(0.23), dJointGetUniversalAngle1 (jId), 1e-4);
  1233. dRFromAxisAndAngle (R, 1, 0, 0, 0);
  1234. dBodySetRotation (bId1, R);
  1235. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  1236. }
  1237. // Rotate the body by 90deg around X then back to original position.
  1238. // The body is attached at the second position of the joint:
  1239. // dJointAttache(jId, 0, bId);
  1240. //
  1241. // ^
  1242. // | => <---
  1243. // |
  1244. // B1 B1
  1245. //
  1246. // Start with a Delta of 90deg
  1247. // ^
  1248. // <--- => |
  1249. // |
  1250. // B1 B1
  1251. TEST_FIXTURE (Fixture_dxJointUniversal_B1_At_Zero_Default_Axes,
  1252. test_dJointSetUniversalAxisOffset_1Body_B1_90Deg)
  1253. {
  1254. CHECK_CLOSE (dJointGetUniversalAngle1 (jId), 0, 1e-4);
  1255. dMatrix3 R;
  1256. dRFromAxisAndAngle (R, 1, 0, 0, M_PI/2.0);
  1257. dBodySetRotation (bId1, R);
  1258. CHECK_CLOSE (M_PI/2.0, dJointGetUniversalAngle1 (jId), 1e-4);
  1259. dVector3 axis;
  1260. dJointGetUniversalAxis1 (jId, axis);
  1261. dJointSetUniversalAxis1Offset (jId, axis[0], axis[1], axis[2], M_PI/2.0, 0);
  1262. CHECK_CLOSE (M_PI/2.0, dJointGetUniversalAngle1 (jId), 1e-4);
  1263. dRFromAxisAndAngle (R, 1, 0, 0, 0);
  1264. dBodySetRotation (bId1, R);
  1265. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  1266. }
  1267. // Rotate the body by -0.23rad around X then back to original position.
  1268. // The body is attached at the second position of the joint:
  1269. // dJointAttache(jId, 0, bId);
  1270. //
  1271. // ^ ^
  1272. // | => /
  1273. // | /
  1274. // B1 B1
  1275. //
  1276. // Start with a Delta of -0.23rad
  1277. // ^ ^
  1278. // / => |
  1279. // / |
  1280. // B1 B1
  1281. TEST_FIXTURE (Fixture_dxJointUniversal_B1_At_Zero_Default_Axes,
  1282. test_dJointSetUniversalAxisOffset_1Body_B1_Minus0_23rad)
  1283. {
  1284. CHECK_CLOSE (dJointGetUniversalAngle1 (jId), 0, 1e-4);
  1285. dMatrix3 R;
  1286. dRFromAxisAndAngle (R, 1, 0, 0, -REAL(0.23));
  1287. dBodySetRotation (bId1, R);
  1288. CHECK_CLOSE (-REAL(0.23), dJointGetUniversalAngle1 (jId), 1e-4);
  1289. dVector3 axis;
  1290. dJointGetUniversalAxis1 (jId, axis);
  1291. dJointSetUniversalAxis1Offset (jId, axis[0], axis[1], axis[2], -REAL(0.23), 0);
  1292. CHECK_CLOSE (-REAL(0.23), dJointGetUniversalAngle1 (jId), 1e-4);
  1293. dRFromAxisAndAngle (R, 1, 0, 0, 0);
  1294. dBodySetRotation (bId1, R);
  1295. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  1296. }
  1297. // Only one body body1 at (0,0,0)
  1298. // The joint is an Universal Joint.
  1299. // Axis the inverse of the X axis
  1300. // Anchor at (0, 0, 0)
  1301. //
  1302. // ^Y
  1303. // |
  1304. // |
  1305. // |
  1306. // |
  1307. // |
  1308. // Z <-- X
  1309. struct Fixture_dxJointUniversal_B1_At_Zero_Axis_Inverse_of_X
  1310. {
  1311. Fixture_dxJointUniversal_B1_At_Zero_Axis_Inverse_of_X()
  1312. {
  1313. wId = dWorldCreate();
  1314. bId1 = dBodyCreate (wId);
  1315. dBodySetPosition (bId1, 0, 0, 0);
  1316. jId = dJointCreateUniversal (wId, 0);
  1317. joint = (dxJointUniversal*) jId;
  1318. dJointAttach (jId, bId1, NULL);
  1319. dJointSetUniversalAnchor (jId, 0, 0, 0);
  1320. axis[0] = -1;
  1321. axis[1] = 0;
  1322. axis[2] = 0;
  1323. dJointSetUniversalAxis1(jId, axis[0], axis[1], axis[2]);
  1324. }
  1325. ~Fixture_dxJointUniversal_B1_At_Zero_Axis_Inverse_of_X()
  1326. {
  1327. dWorldDestroy (wId);
  1328. }
  1329. dWorldID wId;
  1330. dBodyID bId1;
  1331. dJointID jId;
  1332. dxJointUniversal* joint;
  1333. dVector3 axis;
  1334. };
  1335. // Rotate B1 by 90deg around X then back to original position
  1336. //
  1337. // ^
  1338. // | => <---
  1339. // |
  1340. // B1 B1
  1341. //
  1342. // Start with a Delta of 90deg
  1343. // ^
  1344. // <--- => |
  1345. // |
  1346. // B1 B1
  1347. TEST_FIXTURE (Fixture_dxJointUniversal_B1_At_Zero_Axis_Inverse_of_X,
  1348. test_dJointSetUniversalAxisOffset_1Body_B1_90Deg)
  1349. {
  1350. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  1351. dVector3 axis;
  1352. dJointGetUniversalAxis1(jId, axis);
  1353. dReal ang1 = d2r(REAL(90.0));
  1354. dMatrix3 R;
  1355. dRFromAxisAndAngle (R, axis[0], axis[1], axis[2], ang1);
  1356. dBodySetRotation (bId1, R);
  1357. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  1358. dJointSetUniversalAxis1Offset (jId, axis[0], axis[1], axis[2], ang1, 0);
  1359. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  1360. dRSetIdentity(R); // Set the rotation of the body to be zero
  1361. dBodySetRotation (bId1, R);
  1362. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  1363. }
  1364. // Rotate B1 by -0.23rad around X then back to original position
  1365. //
  1366. // ^ ^
  1367. // | => /
  1368. // | /
  1369. // B1 B1
  1370. //
  1371. // Start with a Delta of -0.23rad
  1372. // ^ ^
  1373. // / => |
  1374. // / |
  1375. // B1 B1
  1376. TEST_FIXTURE (Fixture_dxJointUniversal_B1_At_Zero_Axis_Inverse_of_X,
  1377. test_dJointSetUniversalAxisOffset_1Body_B1_Minus0_23rad)
  1378. {
  1379. CHECK_CLOSE (dJointGetUniversalAngle1 (jId), 0, 1e-4);
  1380. dMatrix3 R;
  1381. dRFromAxisAndAngle (R, 1, 0, 0, -REAL(0.23));
  1382. dBodySetRotation (bId1, R);
  1383. CHECK_CLOSE (REAL(0.23), dJointGetUniversalAngle1 (jId), 1e-4);
  1384. dVector3 axis;
  1385. dJointGetUniversalAxis1 (jId, axis);
  1386. dJointSetUniversalAxis1Offset (jId, axis[0], axis[1], axis[2], REAL(0.23), 0);
  1387. CHECK_CLOSE (REAL(0.23), dJointGetUniversalAngle1 (jId), 1e-4);
  1388. dRFromAxisAndAngle (R, 1, 0, 0, 0);
  1389. dBodySetRotation (bId1, R);
  1390. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  1391. }
  1392. // Rotate B2 by 90deg around X then back to original position
  1393. //
  1394. // ^
  1395. // | => <---
  1396. // |
  1397. // B2 B2
  1398. //
  1399. // Start with a Delta of 90deg
  1400. // ^
  1401. // <--- => |
  1402. // |
  1403. // B2 B2
  1404. TEST_FIXTURE (Fixture_dxJointUniversal_B2_At_Zero_Default_Axes,
  1405. test_dJointSetUniversalAxisOffset_1Body_B2_90Deg)
  1406. {
  1407. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  1408. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  1409. dVector3 axis;
  1410. dJointGetUniversalAxis2 (jId, axis);
  1411. dReal ang2 = d2r(REAL(90.0));
  1412. dMatrix3 R;
  1413. dRFromAxisAndAngle (R, axis[0], axis[1], axis[2], ang2);
  1414. dBodySetRotation (bId2, R);
  1415. CHECK_CLOSE (-ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  1416. dJointSetUniversalAxis2Offset (jId, axis[0], axis[1], axis[2], 0, -ang2);
  1417. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  1418. CHECK_CLOSE (-ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  1419. dRSetIdentity(R); // Set the rotation of the body to be zero
  1420. dBodySetRotation (bId2, R);
  1421. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  1422. }
  1423. // Rotate B2 by -0.23rad around Y then back to original position
  1424. //
  1425. // ^ ^
  1426. // | => /
  1427. // | /
  1428. // B2 B2
  1429. //
  1430. // Start with an offset of -0.23rad
  1431. // ^ ^
  1432. // / => |
  1433. // / |
  1434. // B2 B2
  1435. TEST_FIXTURE (Fixture_dxJointUniversal_B2_At_Zero_Default_Axes,
  1436. test_dJointSetUniversalAxis2Offset_1Body_B2_Minus0_23rad)
  1437. {
  1438. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  1439. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  1440. dReal angle1, angle2;
  1441. dJointGetUniversalAngles(jId, &angle1, &angle2);
  1442. CHECK_CLOSE (0, angle1, 1e-4);
  1443. CHECK_CLOSE (0, angle2, 1e-4);
  1444. dVector3 axis;
  1445. dJointGetUniversalAxis2 (jId, axis);
  1446. dReal ang1 = 0;
  1447. dReal ang2 = REAL(-0.23);
  1448. dMatrix3 R;
  1449. dRFromAxisAndAngle (R, axis[0], axis[1], axis[2], ang2);
  1450. dBodySetRotation (bId2, R);
  1451. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  1452. CHECK_CLOSE (-ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  1453. dJointGetUniversalAngles(jId, &angle1, &angle2);
  1454. CHECK_CLOSE (ang1, angle1, 1e-4);
  1455. CHECK_CLOSE (-ang2, angle2, 1e-4);
  1456. dJointSetUniversalAxis2Offset (jId, axis[0], axis[1], axis[2],
  1457. ang1, -ang2);
  1458. CHECK_CLOSE (ang1, dJointGetUniversalAngle1 (jId), 1e-4);
  1459. CHECK_CLOSE (-ang2, dJointGetUniversalAngle2 (jId), 1e-4);
  1460. dRSetIdentity(R); // Set the rotation of the body to be zero
  1461. dBodySetRotation (bId2, R);
  1462. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  1463. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  1464. dJointGetUniversalAngles(jId, &angle1, &angle2);
  1465. CHECK_CLOSE (0, angle1, 1e-4);
  1466. CHECK_CLOSE (0, angle2, 1e-4);
  1467. }
  1468. // The 2 bodies are positionned at (0,0,0), and (0,0,0)
  1469. // The bodis have no rotation.
  1470. // The joint is a Universal Joint
  1471. // The axis of the joint are at random (Still at 90deg w.r.t each other)
  1472. // Anchor at (0, 0, 0)
  1473. struct Fixture_dxJointUniversal_B1_and_B2_Axis_Random
  1474. {
  1475. Fixture_dxJointUniversal_B1_and_B2_Axis_Random()
  1476. {
  1477. wId = dWorldCreate();
  1478. bId1 = dBodyCreate (wId);
  1479. dBodySetPosition (bId1, -1, -2, -3);
  1480. bId2 = dBodyCreate (wId);
  1481. dBodySetPosition (bId2, 11, 22, 33);
  1482. jId = dJointCreateUniversal (wId, 0);
  1483. dJointAttach (jId, bId1, bId2);
  1484. dVector3 axis1;
  1485. axis1[0] = REAL(0.53);
  1486. axis1[1] = -REAL(0.71);
  1487. axis1[2] = REAL(0.43);
  1488. dNormalize3(axis1);
  1489. dVector3 axis;
  1490. axis[0] = REAL(1.2);
  1491. axis[1] = REAL(0.87);
  1492. axis[2] = -REAL(0.33);
  1493. dVector3 axis2;
  1494. dCalcVectorCross3(axis2, axis1, axis);
  1495. dJointSetUniversalAxis1(jId, axis1[0], axis1[1], axis1[2]);
  1496. dJointSetUniversalAxis2(jId, axis2[0], axis2[1], axis2[2]);
  1497. }
  1498. ~Fixture_dxJointUniversal_B1_and_B2_Axis_Random()
  1499. {
  1500. dWorldDestroy (wId);
  1501. }
  1502. dWorldID wId;
  1503. dBodyID bId1;
  1504. dBodyID bId2;
  1505. dJointID jId;
  1506. };
  1507. // Rotate first body 90deg around Axis1 then back to original position
  1508. //
  1509. // ^ ^ ^ Z ^
  1510. // | | => <--- | |
  1511. // | | | |
  1512. // B1 B2 B1 B2 X .----->Y
  1513. // N.B. X is going out of the screen
  1514. // Set Axis1 with an Offset of 90deg
  1515. // ^ ^ ^
  1516. // <--- | => | |
  1517. // | | |
  1518. // B1 B2 B1 B2
  1519. TEST_FIXTURE (Fixture_dxJointUniversal_B1_and_B2_Axis_Random,
  1520. test_dJointSetUniversalAxisOffset_B1_90deg_Axis_Random)
  1521. {
  1522. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  1523. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  1524. dReal angle1, angle2;
  1525. dJointGetUniversalAngles(jId, &angle1, &angle2);
  1526. CHECK_CLOSE (0, angle1, 1e-4);
  1527. CHECK_CLOSE (0, angle2, 1e-4);
  1528. dVector3 axis;
  1529. dJointGetUniversalAxis1 (jId, axis);
  1530. dReal angle = d2r(90);
  1531. dMatrix3 R;
  1532. dRFromAxisAndAngle (R, axis[0], axis[1], axis[2], angle);
  1533. dBodySetRotation (bId1, R);
  1534. CHECK_CLOSE (angle, dJointGetUniversalAngle1 (jId), 1e-4);
  1535. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  1536. dJointGetUniversalAngles(jId, &angle1, &angle2);
  1537. CHECK_CLOSE (angle, angle1, 1e-4);
  1538. CHECK_CLOSE (0, angle2, 1e-4);
  1539. dJointSetUniversalAxis1Offset (jId, axis[0], axis[1], axis[2], angle, 0);
  1540. CHECK_CLOSE (angle, dJointGetUniversalAngle1 (jId), 1e-4);
  1541. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  1542. dJointGetUniversalAngles(jId, &angle1, &angle2);
  1543. CHECK_CLOSE (angle, angle1, 1e-4);
  1544. CHECK_CLOSE (0, angle2, 1e-4);
  1545. dRFromAxisAndAngle (R, axis[0], axis[1], axis[2], 0);
  1546. dBodySetRotation (bId1, R);
  1547. CHECK_CLOSE (0, dJointGetUniversalAngle1 (jId), 1e-4);
  1548. CHECK_CLOSE (0, dJointGetUniversalAngle2 (jId), 1e-4);
  1549. dJointGetUniversalAngles(jId, &angle1, &angle2);
  1550. CHECK_CLOSE (0, angle1, 1e-4);
  1551. CHECK_CLOSE (0, angle2, 1e-4);
  1552. }
  1553. } // End of SUITE TestdxJointUniversal