universal.cpp 65 KB

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