demo_collision.cpp 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445
  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. collision tests. if this program is run without any arguments it will
  24. perform all the tests multiple times, with different random data for each
  25. test. if this program is given a test number it will run that test
  26. graphically/interactively, in which case the space bar can be used to
  27. change the random test conditions.
  28. */
  29. #include <ode/ode.h>
  30. #include <drawstuff/drawstuff.h>
  31. #include "texturepath.h"
  32. #ifdef _MSC_VER
  33. #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
  34. #endif
  35. // select correct drawing functions
  36. #ifdef dDOUBLE
  37. #define dsDrawSphere dsDrawSphereD
  38. #define dsDrawBox dsDrawBoxD
  39. #define dsDrawLine dsDrawLineD
  40. #define dsDrawCapsule dsDrawCapsuleD
  41. #define dsDrawCylinder dsDrawCylinderD
  42. #endif
  43. //****************************************************************************
  44. // test infrastructure, including constants and macros
  45. #define TEST_REPS1 1000 // run each test this many times (first batch)
  46. #define TEST_REPS2 10000 // run each test this many times (second batch)
  47. const dReal tol = 1e-8; // tolerance used for numerical checks
  48. #define MAX_TESTS 1000 // maximum number of test slots
  49. #define Z_OFFSET 2 // z offset for drawing (to get above ground)
  50. //using namespace ode;
  51. // test function. returns 1 if the test passed or 0 if it failed
  52. typedef int test_function_t();
  53. struct TestSlot {
  54. int number; // number of test
  55. const char *name; // name of test
  56. int failcount;
  57. test_function_t *test_fn;
  58. int last_failed_line;
  59. };
  60. TestSlot testslot[MAX_TESTS];
  61. // globals used by the test functions
  62. int graphical_test=0; // show graphical results of this test, 0=none
  63. int current_test; // currently execiting test
  64. int draw_all_objects_called;
  65. #define MAKE_TEST(number,function) \
  66. if (testslot[number].name) dDebug (0,"test number already used"); \
  67. if (number <= 0 || number >= MAX_TESTS) dDebug (0,"bad test number"); \
  68. testslot[number].name = # function; \
  69. testslot[number].test_fn = function;
  70. #define FAILED() { if (graphical_test==0) { \
  71. testslot[current_test].last_failed_line=__LINE__; return 0; } }
  72. #define PASSED() { return 1; }
  73. //****************************************************************************
  74. // globals
  75. /* int dBoxBox (const dVector3 p1, const dMatrix3 R1,
  76. const dVector3 side1, const dVector3 p2,
  77. const dMatrix3 R2, const dVector3 side2,
  78. dVector3 normal, dReal *depth, int *code,
  79. int maxc, dContactGeom *contact, int skip); */
  80. void dLineClosestApproach (const dVector3 pa, const dVector3 ua,
  81. const dVector3 pb, const dVector3 ub,
  82. dReal *alpha, dReal *beta);
  83. //****************************************************************************
  84. // draw all objects in a space, and draw all the collision contact points
  85. void nearCallback (void *data, dGeomID o1, dGeomID o2)
  86. {
  87. int i,j,n;
  88. const int N = 100;
  89. dContactGeom contact[N];
  90. if (dGeomGetClass (o2) == dRayClass) {
  91. n = dCollide (o2,o1,N,&contact[0],sizeof(dContactGeom));
  92. }
  93. else {
  94. n = dCollide (o1,o2,N,&contact[0],sizeof(dContactGeom));
  95. }
  96. if (n > 0) {
  97. dMatrix3 RI;
  98. dRSetIdentity (RI);
  99. const dReal ss[3] = {0.01,0.01,0.01};
  100. for (i=0; i<n; i++) {
  101. contact[i].pos[2] += Z_OFFSET;
  102. dsDrawBox (contact[i].pos,RI,ss);
  103. dVector3 n;
  104. for (j=0; j<3; j++) n[j] = contact[i].pos[j] + 0.1*contact[i].normal[j];
  105. dsDrawLine (contact[i].pos,n);
  106. }
  107. }
  108. }
  109. void draw_all_objects (dSpaceID space)
  110. {
  111. int i, j;
  112. draw_all_objects_called = 1;
  113. if (!graphical_test) return;
  114. int n = dSpaceGetNumGeoms (space);
  115. // draw all contact points
  116. dsSetColor (0,1,1);
  117. dSpaceCollide (space,0,&nearCallback);
  118. // draw all rays
  119. for (i=0; i<n; i++) {
  120. dGeomID g = dSpaceGetGeom (space,i);
  121. if (dGeomGetClass (g) == dRayClass) {
  122. dsSetColor (1,1,1);
  123. dVector3 origin,dir;
  124. dGeomRayGet (g,origin,dir);
  125. origin[2] += Z_OFFSET;
  126. dReal length = dGeomRayGetLength (g);
  127. for (j=0; j<3; j++) dir[j] = dir[j]*length + origin[j];
  128. dsDrawLine (origin,dir);
  129. dsSetColor (0,0,1);
  130. dsDrawSphere (origin,dGeomGetRotation(g),0.01);
  131. }
  132. }
  133. // draw all other objects
  134. for (i=0; i<n; i++) {
  135. dGeomID g = dSpaceGetGeom (space,i);
  136. dVector3 pos;
  137. if (dGeomGetClass (g) != dPlaneClass) {
  138. memcpy (pos,dGeomGetPosition(g),sizeof(pos));
  139. pos[2] += Z_OFFSET;
  140. }
  141. switch (dGeomGetClass (g)) {
  142. case dSphereClass: {
  143. dsSetColorAlpha (1,0,0,0.8);
  144. dReal radius = dGeomSphereGetRadius (g);
  145. dsDrawSphere (pos,dGeomGetRotation(g),radius);
  146. break;
  147. }
  148. case dBoxClass: {
  149. dsSetColorAlpha (1,1,0,0.8);
  150. dVector3 sides;
  151. dGeomBoxGetLengths (g,sides);
  152. dsDrawBox (pos,dGeomGetRotation(g),sides);
  153. break;
  154. }
  155. case dCapsuleClass: {
  156. dsSetColorAlpha (0,1,0,0.8);
  157. dReal radius,length;
  158. dGeomCapsuleGetParams (g,&radius,&length);
  159. dsDrawCapsule (pos,dGeomGetRotation(g),length,radius);
  160. break;
  161. }
  162. case dCylinderClass: {
  163. dsSetColorAlpha (0,1,0,0.8);
  164. dReal radius,length;
  165. dGeomCylinderGetParams (g,&radius,&length);
  166. dsDrawCylinder (pos,dGeomGetRotation(g),length,radius);
  167. break;
  168. }
  169. case dPlaneClass: {
  170. dVector4 n;
  171. dMatrix3 R,sides;
  172. dVector3 pos2;
  173. dGeomPlaneGetParams (g,n);
  174. dRFromZAxis (R,n[0],n[1],n[2]);
  175. for (j=0; j<3; j++) pos[j] = n[j]*n[3];
  176. pos[2] += Z_OFFSET;
  177. sides[0] = 2;
  178. sides[1] = 2;
  179. sides[2] = 0.001;
  180. dsSetColor (1,0,1);
  181. for (j=0; j<3; j++) pos2[j] = pos[j] + 0.1*n[j];
  182. dsDrawLine (pos,pos2);
  183. dsSetColorAlpha (1,0,1,0.8);
  184. dsDrawBox (pos,R,sides);
  185. break;
  186. }
  187. }
  188. }
  189. }
  190. //****************************************************************************
  191. // point depth tests
  192. int test_sphere_point_depth()
  193. {
  194. int j;
  195. dVector3 p,q;
  196. dMatrix3 R;
  197. dReal r,d;
  198. dSimpleSpace space(0);
  199. dGeomID sphere = dCreateSphere (0,1);
  200. dSpaceAdd (space,sphere);
  201. // ********** make a random sphere of radius r at position p
  202. r = dRandReal()+0.1;
  203. dGeomSphereSetRadius (sphere,r);
  204. dMakeRandomVector (p,3,1.0);
  205. dGeomSetPosition (sphere,p[0],p[1],p[2]);
  206. dRFromAxisAndAngle (R,dRandReal()*2-1,dRandReal()*2-1,
  207. dRandReal()*2-1,dRandReal()*10-5);
  208. dGeomSetRotation (sphere,R);
  209. // ********** test center point has depth r
  210. if (dFabs(dGeomSpherePointDepth (sphere,p[0],p[1],p[2]) - r) > tol) FAILED();
  211. // ********** test point on surface has depth 0
  212. for (j=0; j<3; j++) q[j] = dRandReal()-0.5;
  213. dNormalize3 (q);
  214. for (j=0; j<3; j++) q[j] = q[j]*r + p[j];
  215. if (dFabs(dGeomSpherePointDepth (sphere,q[0],q[1],q[2])) > tol) FAILED();
  216. // ********** test point at random depth
  217. d = (dRandReal()*2-1) * r;
  218. for (j=0; j<3; j++) q[j] = dRandReal()-0.5;
  219. dNormalize3 (q);
  220. for (j=0; j<3; j++) q[j] = q[j]*(r-d) + p[j];
  221. if (dFabs(dGeomSpherePointDepth (sphere,q[0],q[1],q[2])-d) > tol) FAILED();
  222. PASSED();
  223. }
  224. int test_box_point_depth()
  225. {
  226. int i,j;
  227. dVector3 s,p,q,q2; // s = box sides
  228. dMatrix3 R;
  229. dReal ss,d; // ss = smallest side
  230. dSimpleSpace space(0);
  231. dGeomID box = dCreateBox (0,1,1,1);
  232. dSpaceAdd (space,box);
  233. // ********** make a random box
  234. for (j=0; j<3; j++) s[j] = dRandReal() + 0.1;
  235. dGeomBoxSetLengths (box,s[0],s[1],s[2]);
  236. dMakeRandomVector (p,3,1.0);
  237. dGeomSetPosition (box,p[0],p[1],p[2]);
  238. dRFromAxisAndAngle (R,dRandReal()*2-1,dRandReal()*2-1,
  239. dRandReal()*2-1,dRandReal()*10-5);
  240. dGeomSetRotation (box,R);
  241. // ********** test center point has depth of smallest side
  242. ss = 1e9;
  243. for (j=0; j<3; j++) if (s[j] < ss) ss = s[j];
  244. if (dFabs(dGeomBoxPointDepth (box,p[0],p[1],p[2]) - 0.5*ss) > tol)
  245. FAILED();
  246. // ********** test point on surface has depth 0
  247. for (j=0; j<3; j++) q[j] = (dRandReal()-0.5)*s[j];
  248. i = dRandInt (3);
  249. if (dRandReal() > 0.5) q[i] = 0.5*s[i]; else q[i] = -0.5*s[i];
  250. dMultiply0 (q2,dGeomGetRotation(box),q,3,3,1);
  251. for (j=0; j<3; j++) q2[j] += p[j];
  252. if (dFabs(dGeomBoxPointDepth (box,q2[0],q2[1],q2[2])) > tol) FAILED();
  253. // ********** test points outside box have -ve depth
  254. for (j=0; j<3; j++) {
  255. q[j] = 0.5*s[j] + dRandReal() + 0.01;
  256. if (dRandReal() > 0.5) q[j] = -q[j];
  257. }
  258. dMultiply0 (q2,dGeomGetRotation(box),q,3,3,1);
  259. for (j=0; j<3; j++) q2[j] += p[j];
  260. if (dGeomBoxPointDepth (box,q2[0],q2[1],q2[2]) >= 0) FAILED();
  261. // ********** test points inside box have +ve depth
  262. for (j=0; j<3; j++) q[j] = s[j] * 0.99 * (dRandReal()-0.5);
  263. dMultiply0 (q2,dGeomGetRotation(box),q,3,3,1);
  264. for (j=0; j<3; j++) q2[j] += p[j];
  265. if (dGeomBoxPointDepth (box,q2[0],q2[1],q2[2]) <= 0) FAILED();
  266. // ********** test random depth of point aligned along axis (up to ss deep)
  267. i = dRandInt (3);
  268. for (j=0; j<3; j++) q[j] = 0;
  269. d = (dRandReal()*(ss*0.5+1)-1);
  270. q[i] = s[i]*0.5 - d;
  271. if (dRandReal() > 0.5) q[i] = -q[i];
  272. dMultiply0 (q2,dGeomGetRotation(box),q,3,3,1);
  273. for (j=0; j<3; j++) q2[j] += p[j];
  274. if (dFabs(dGeomBoxPointDepth (box,q2[0],q2[1],q2[2]) - d) >= tol) FAILED();
  275. PASSED();
  276. }
  277. int test_ccylinder_point_depth()
  278. {
  279. int j;
  280. dVector3 p,a;
  281. dMatrix3 R;
  282. dReal r,l,beta,x,y,d;
  283. dSimpleSpace space(0);
  284. dGeomID ccyl = dCreateCapsule (0,1,1);
  285. dSpaceAdd (space,ccyl);
  286. // ********** make a random ccyl
  287. r = dRandReal()*0.5 + 0.01;
  288. l = dRandReal()*1 + 0.01;
  289. dGeomCapsuleSetParams (ccyl,r,l);
  290. dMakeRandomVector (p,3,1.0);
  291. dGeomSetPosition (ccyl,p[0],p[1],p[2]);
  292. dRFromAxisAndAngle (R,dRandReal()*2-1,dRandReal()*2-1,
  293. dRandReal()*2-1,dRandReal()*10-5);
  294. dGeomSetRotation (ccyl,R);
  295. // ********** test point on axis has depth of 'radius'
  296. beta = dRandReal()-0.5;
  297. for (j=0; j<3; j++) a[j] = p[j] + l*beta*R[j*4+2];
  298. if (dFabs(dGeomCapsulePointDepth (ccyl,a[0],a[1],a[2]) - r) >= tol)
  299. FAILED();
  300. // ********** test point on surface (excluding caps) has depth 0
  301. beta = dRandReal()*2*M_PI;
  302. x = r*sin(beta);
  303. y = r*cos(beta);
  304. beta = dRandReal()-0.5;
  305. for (j=0; j<3; j++) a[j] = p[j] + x*R[j*4+0] + y*R[j*4+1] + l*beta*R[j*4+2];
  306. if (dFabs(dGeomCapsulePointDepth (ccyl,a[0],a[1],a[2])) >= tol) FAILED();
  307. // ********** test point on surface of caps has depth 0
  308. for (j=0; j<3; j++) a[j] = dRandReal()-0.5;
  309. dNormalize3 (a);
  310. if (dCalcVectorDot3_14(a,R+2) > 0) {
  311. for (j=0; j<3; j++) a[j] = p[j] + a[j]*r + l*0.5*R[j*4+2];
  312. }
  313. else {
  314. for (j=0; j<3; j++) a[j] = p[j] + a[j]*r - l*0.5*R[j*4+2];
  315. }
  316. if (dFabs(dGeomCapsulePointDepth (ccyl,a[0],a[1],a[2])) >= tol) FAILED();
  317. // ********** test point inside ccyl has positive depth
  318. for (j=0; j<3; j++) a[j] = dRandReal()-0.5;
  319. dNormalize3 (a);
  320. beta = dRandReal()-0.5;
  321. for (j=0; j<3; j++) a[j] = p[j] + a[j]*r*0.99 + l*beta*R[j*4+2];
  322. if (dGeomCapsulePointDepth (ccyl,a[0],a[1],a[2]) < 0) FAILED();
  323. // ********** test point depth (1)
  324. d = (dRandReal()*2-1) * r;
  325. beta = dRandReal()*2*M_PI;
  326. x = (r-d)*sin(beta);
  327. y = (r-d)*cos(beta);
  328. beta = dRandReal()-0.5;
  329. for (j=0; j<3; j++) a[j] = p[j] + x*R[j*4+0] + y*R[j*4+1] + l*beta*R[j*4+2];
  330. if (dFabs(dGeomCapsulePointDepth (ccyl,a[0],a[1],a[2]) - d) >= tol)
  331. FAILED();
  332. // ********** test point depth (2)
  333. d = (dRandReal()*2-1) * r;
  334. for (j=0; j<3; j++) a[j] = dRandReal()-0.5;
  335. dNormalize3 (a);
  336. if (dCalcVectorDot3_14(a,R+2) > 0) {
  337. for (j=0; j<3; j++) a[j] = p[j] + a[j]*(r-d) + l*0.5*R[j*4+2];
  338. }
  339. else {
  340. for (j=0; j<3; j++) a[j] = p[j] + a[j]*(r-d) - l*0.5*R[j*4+2];
  341. }
  342. if (dFabs(dGeomCapsulePointDepth (ccyl,a[0],a[1],a[2]) - d) >= tol)
  343. FAILED();
  344. PASSED();
  345. }
  346. int test_plane_point_depth()
  347. {
  348. int j;
  349. dVector3 n,p,q,a,b; // n = plane normal
  350. dReal d;
  351. dSimpleSpace space(0);
  352. dGeomID plane = dCreatePlane (0,0,0,1,0);
  353. dSpaceAdd (space,plane);
  354. // ********** make a random plane
  355. for (j=0; j<3; j++) n[j] = dRandReal() - 0.5;
  356. dNormalize3 (n);
  357. d = dRandReal() - 0.5;
  358. dGeomPlaneSetParams (plane,n[0],n[1],n[2],d);
  359. dPlaneSpace (n,p,q);
  360. // ********** test point on plane has depth 0
  361. a[0] = dRandReal() - 0.5;
  362. a[1] = dRandReal() - 0.5;
  363. a[2] = 0;
  364. for (j=0; j<3; j++) b[j] = a[0]*p[j] + a[1]*q[j] + (a[2]+d)*n[j];
  365. if (dFabs(dGeomPlanePointDepth (plane,b[0],b[1],b[2])) >= tol) FAILED();
  366. // ********** test arbitrary depth point
  367. a[0] = dRandReal() - 0.5;
  368. a[1] = dRandReal() - 0.5;
  369. a[2] = dRandReal() - 0.5;
  370. for (j=0; j<3; j++) b[j] = a[0]*p[j] + a[1]*q[j] + (a[2]+d)*n[j];
  371. if (dFabs(dGeomPlanePointDepth (plane,b[0],b[1],b[2]) + a[2]) >= tol)
  372. FAILED();
  373. // ********** test depth-1 point
  374. a[0] = dRandReal() - 0.5;
  375. a[1] = dRandReal() - 0.5;
  376. a[2] = -1;
  377. for (j=0; j<3; j++) b[j] = a[0]*p[j] + a[1]*q[j] + (a[2]+d)*n[j];
  378. if (dFabs(dGeomPlanePointDepth (plane,b[0],b[1],b[2]) - 1) >= tol) FAILED();
  379. PASSED();
  380. }
  381. //****************************************************************************
  382. // ray tests
  383. int test_ray_and_sphere()
  384. {
  385. int j;
  386. dContactGeom contact;
  387. dVector3 p,q,q2,n,v1;
  388. dMatrix3 R;
  389. dReal r,k;
  390. dSimpleSpace space(0);
  391. dGeomID ray = dCreateRay (0,0);
  392. dGeomID sphere = dCreateSphere (0,1);
  393. dSpaceAdd (space,ray);
  394. dSpaceAdd (space,sphere);
  395. // ********** make a random sphere of radius r at position p
  396. r = dRandReal()+0.1;
  397. dGeomSphereSetRadius (sphere,r);
  398. dMakeRandomVector (p,3,1.0);
  399. dGeomSetPosition (sphere,p[0],p[1],p[2]);
  400. dRFromAxisAndAngle (R,dRandReal()*2-1,dRandReal()*2-1,
  401. dRandReal()*2-1,dRandReal()*10-5);
  402. dGeomSetRotation (sphere,R);
  403. // ********** test zero length ray just inside sphere
  404. dGeomRaySetLength (ray,0);
  405. dMakeRandomVector (q,3,1.0);
  406. dNormalize3 (q);
  407. for (j=0; j<3; j++) q[j] = 0.99*r * q[j] + p[j];
  408. dGeomSetPosition (ray,q[0],q[1],q[2]);
  409. dRFromAxisAndAngle (R,dRandReal()*2-1,dRandReal()*2-1,
  410. dRandReal()*2-1,dRandReal()*10-5);
  411. dGeomSetRotation (ray,R);
  412. if (dCollide (ray,sphere,1,&contact,sizeof(dContactGeom)) != 0) FAILED();
  413. // ********** test zero length ray just outside that sphere
  414. dGeomRaySetLength (ray,0);
  415. dMakeRandomVector (q,3,1.0);
  416. dNormalize3 (q);
  417. for (j=0; j<3; j++) q[j] = 1.01*r * q[j] + p[j];
  418. dGeomSetPosition (ray,q[0],q[1],q[2]);
  419. dRFromAxisAndAngle (R,dRandReal()*2-1,dRandReal()*2-1,
  420. dRandReal()*2-1,dRandReal()*10-5);
  421. dGeomSetRotation (ray,R);
  422. if (dCollide (ray,sphere,1,&contact,sizeof(dContactGeom)) != 0) FAILED();
  423. // ********** test finite length ray totally contained inside the sphere
  424. dMakeRandomVector (q,3,1.0);
  425. dNormalize3 (q);
  426. k = dRandReal();
  427. for (j=0; j<3; j++) q[j] = k*r*0.99 * q[j] + p[j];
  428. dMakeRandomVector (q2,3,1.0);
  429. dNormalize3 (q2);
  430. k = dRandReal();
  431. for (j=0; j<3; j++) q2[j] = k*r*0.99 * q2[j] + p[j];
  432. for (j=0; j<3; j++) n[j] = q2[j] - q[j];
  433. dNormalize3 (n);
  434. dGeomRaySet (ray,q[0],q[1],q[2],n[0],n[1],n[2]);
  435. dGeomRaySetLength (ray,dCalcPointsDistance3(q,q2));
  436. if (dCollide (ray,sphere,1,&contact,sizeof(dContactGeom)) != 0) FAILED();
  437. // ********** test finite length ray totally outside the sphere
  438. dMakeRandomVector (q,3,1.0);
  439. dNormalize3 (q);
  440. do {
  441. dMakeRandomVector (n,3,1.0);
  442. dNormalize3 (n);
  443. }
  444. while (dCalcVectorDot3(n,q) < 0); // make sure normal goes away from sphere
  445. for (j=0; j<3; j++) q[j] = 1.01*r * q[j] + p[j];
  446. dGeomRaySet (ray,q[0],q[1],q[2],n[0],n[1],n[2]);
  447. dGeomRaySetLength (ray,100);
  448. if (dCollide (ray,sphere,1,&contact,sizeof(dContactGeom)) != 0) FAILED();
  449. // ********** test ray from outside to just above surface
  450. dMakeRandomVector (q,3,1.0);
  451. dNormalize3 (q);
  452. for (j=0; j<3; j++) n[j] = -q[j];
  453. for (j=0; j<3; j++) q2[j] = 2*r * q[j] + p[j];
  454. dGeomRaySet (ray,q2[0],q2[1],q2[2],n[0],n[1],n[2]);
  455. dGeomRaySetLength (ray,0.99*r);
  456. if (dCollide (ray,sphere,1,&contact,sizeof(dContactGeom)) != 0) FAILED();
  457. // ********** test ray from outside to just below surface
  458. dGeomRaySetLength (ray,1.01*r);
  459. if (dCollide (ray,sphere,1,&contact,sizeof(dContactGeom)) != 1) FAILED();
  460. for (j=0; j<3; j++) q2[j] = r * q[j] + p[j];
  461. if (dCalcPointsDistance3 (contact.pos,q2) > tol) FAILED();
  462. // ********** test contact point distance for random rays
  463. dMakeRandomVector (q,3,1.0);
  464. dNormalize3 (q);
  465. k = dRandReal()+0.5;
  466. for (j=0; j<3; j++) q[j] = k*r * q[j] + p[j];
  467. dMakeRandomVector (n,3,1.0);
  468. dNormalize3 (n);
  469. dGeomRaySet (ray,q[0],q[1],q[2],n[0],n[1],n[2]);
  470. dGeomRaySetLength (ray,100);
  471. if (dCollide (ray,sphere,1,&contact,sizeof(dContactGeom))) {
  472. k = dCalcPointsDistance3 (contact.pos,dGeomGetPosition(sphere));
  473. if (dFabs(k - r) > tol) FAILED();
  474. // also check normal signs
  475. if (dCalcVectorDot3 (n,contact.normal) > 0) FAILED();
  476. // also check depth of contact point
  477. if (dFabs (dGeomSpherePointDepth
  478. (sphere,contact.pos[0],contact.pos[1],contact.pos[2])) > tol)
  479. FAILED();
  480. draw_all_objects (space);
  481. }
  482. // ********** test tangential grazing - miss
  483. dMakeRandomVector (q,3,1.0);
  484. dNormalize3 (q);
  485. dPlaneSpace (q,n,v1);
  486. for (j=0; j<3; j++) q[j] = 1.01*r * q[j] + p[j];
  487. for (j=0; j<3; j++) q[j] -= n[j];
  488. dGeomRaySet (ray,q[0],q[1],q[2],n[0],n[1],n[2]);
  489. dGeomRaySetLength (ray,2);
  490. if (dCollide (ray,sphere,1,&contact,sizeof(dContactGeom)) != 0) FAILED();
  491. // ********** test tangential grazing - hit
  492. dMakeRandomVector (q,3,1.0);
  493. dNormalize3 (q);
  494. dPlaneSpace (q,n,v1);
  495. for (j=0; j<3; j++) q[j] = 0.99*r * q[j] + p[j];
  496. for (j=0; j<3; j++) q[j] -= n[j];
  497. dGeomRaySet (ray,q[0],q[1],q[2],n[0],n[1],n[2]);
  498. dGeomRaySetLength (ray,2);
  499. if (dCollide (ray,sphere,1,&contact,sizeof(dContactGeom)) != 1) FAILED();
  500. PASSED();
  501. }
  502. int test_ray_and_box()
  503. {
  504. int i,j;
  505. dContactGeom contact;
  506. dVector3 s,p,q,n,q2,q3,q4; // s = box sides
  507. dMatrix3 R;
  508. dReal k;
  509. dSimpleSpace space(0);
  510. dGeomID ray = dCreateRay (0,0);
  511. dGeomID box = dCreateBox (0,1,1,1);
  512. dSpaceAdd (space,ray);
  513. dSpaceAdd (space,box);
  514. // ********** make a random box
  515. for (j=0; j<3; j++) s[j] = dRandReal() + 0.1;
  516. dGeomBoxSetLengths (box,s[0],s[1],s[2]);
  517. dMakeRandomVector (p,3,1.0);
  518. dGeomSetPosition (box,p[0],p[1],p[2]);
  519. dRFromAxisAndAngle (R,dRandReal()*2-1,dRandReal()*2-1,
  520. dRandReal()*2-1,dRandReal()*10-5);
  521. dGeomSetRotation (box,R);
  522. // ********** test zero length ray just inside box
  523. dGeomRaySetLength (ray,0);
  524. for (j=0; j<3; j++) q[j] = (dRandReal()-0.5)*s[j];
  525. i = dRandInt (3);
  526. if (dRandReal() > 0.5) q[i] = 0.99*0.5*s[i]; else q[i] = -0.99*0.5*s[i];
  527. dMultiply0 (q2,dGeomGetRotation(box),q,3,3,1);
  528. for (j=0; j<3; j++) q2[j] += p[j];
  529. dGeomSetPosition (ray,q2[0],q2[1],q2[2]);
  530. dRFromAxisAndAngle (R,dRandReal()*2-1,dRandReal()*2-1,
  531. dRandReal()*2-1,dRandReal()*10-5);
  532. dGeomSetRotation (ray,R);
  533. if (dCollide (ray,box,1,&contact,sizeof(dContactGeom)) != 0) FAILED();
  534. // ********** test zero length ray just outside box
  535. dGeomRaySetLength (ray,0);
  536. for (j=0; j<3; j++) q[j] = (dRandReal()-0.5)*s[j];
  537. i = dRandInt (3);
  538. if (dRandReal() > 0.5) q[i] = 1.01*0.5*s[i]; else q[i] = -1.01*0.5*s[i];
  539. dMultiply0 (q2,dGeomGetRotation(box),q,3,3,1);
  540. for (j=0; j<3; j++) q2[j] += p[j];
  541. dGeomSetPosition (ray,q2[0],q2[1],q2[2]);
  542. dRFromAxisAndAngle (R,dRandReal()*2-1,dRandReal()*2-1,
  543. dRandReal()*2-1,dRandReal()*10-5);
  544. dGeomSetRotation (ray,R);
  545. if (dCollide (ray,box,1,&contact,sizeof(dContactGeom)) != 0) FAILED();
  546. // ********** test finite length ray totally contained inside the box
  547. for (j=0; j<3; j++) q[j] = (dRandReal()-0.5)*0.99*s[j];
  548. dMultiply0 (q2,dGeomGetRotation(box),q,3,3,1);
  549. for (j=0; j<3; j++) q2[j] += p[j];
  550. for (j=0; j<3; j++) q3[j] = (dRandReal()-0.5)*0.99*s[j];
  551. dMultiply0 (q4,dGeomGetRotation(box),q3,3,3,1);
  552. for (j=0; j<3; j++) q4[j] += p[j];
  553. for (j=0; j<3; j++) n[j] = q4[j] - q2[j];
  554. dNormalize3 (n);
  555. dGeomRaySet (ray,q2[0],q2[1],q2[2],n[0],n[1],n[2]);
  556. dGeomRaySetLength (ray,dCalcPointsDistance3(q2,q4));
  557. if (dCollide (ray,box,1,&contact,sizeof(dContactGeom)) != 0) FAILED();
  558. // ********** test finite length ray totally outside the box
  559. for (j=0; j<3; j++) q[j] = (dRandReal()-0.5)*s[j];
  560. i = dRandInt (3);
  561. if (dRandReal() > 0.5) q[i] = 1.01*0.5*s[i]; else q[i] = -1.01*0.5*s[i];
  562. dMultiply0 (q2,dGeomGetRotation(box),q,3,3,1);
  563. for (j=0; j<3; j++) q3[j] = q2[j] + p[j];
  564. dNormalize3 (q2);
  565. dGeomRaySet (ray,q3[0],q3[1],q3[2],q2[0],q2[1],q2[2]);
  566. dGeomRaySetLength (ray,10);
  567. if (dCollide (ray,box,1,&contact,sizeof(dContactGeom)) != 0) FAILED();
  568. // ********** test ray from outside to just above surface
  569. for (j=0; j<3; j++) q[j] = (dRandReal()-0.5)*s[j];
  570. i = dRandInt (3);
  571. if (dRandReal() > 0.5) q[i] = 1.01*0.5*s[i]; else q[i] = -1.01*0.5*s[i];
  572. dMultiply0 (q2,dGeomGetRotation(box),q,3,3,1);
  573. for (j=0; j<3; j++) q3[j] = 2*q2[j] + p[j];
  574. k = dSqrt(q2[0]*q2[0] + q2[1]*q2[1] + q2[2]*q2[2]);
  575. for (j=0; j<3; j++) q2[j] = -q2[j];
  576. dGeomRaySet (ray,q3[0],q3[1],q3[2],q2[0],q2[1],q2[2]);
  577. dGeomRaySetLength (ray,k*0.99);
  578. if (dCollide (ray,box,1,&contact,sizeof(dContactGeom)) != 0) FAILED();
  579. // ********** test ray from outside to just below surface
  580. dGeomRaySetLength (ray,k*1.01);
  581. if (dCollide (ray,box,1,&contact,sizeof(dContactGeom)) != 1) FAILED();
  582. // ********** test contact point position for random rays
  583. for (j=0; j<3; j++) q[j] = dRandReal()*s[j];
  584. dMultiply0 (q2,dGeomGetRotation(box),q,3,3,1);
  585. for (j=0; j<3; j++) q2[j] += p[j];
  586. for (j=0; j<3; j++) q3[j] = dRandReal()-0.5;
  587. dNormalize3 (q3);
  588. dGeomRaySet (ray,q2[0],q2[1],q2[2],q3[0],q3[1],q3[2]);
  589. dGeomRaySetLength (ray,10);
  590. if (dCollide (ray,box,1,&contact,sizeof(dContactGeom))) {
  591. // check depth of contact point
  592. if (dFabs (dGeomBoxPointDepth
  593. (box,contact.pos[0],contact.pos[1],contact.pos[2])) > tol)
  594. FAILED();
  595. // check position of contact point
  596. for (j=0; j<3; j++) contact.pos[j] -= p[j];
  597. dMultiply1 (q,dGeomGetRotation(box),contact.pos,3,3,1);
  598. if ( dFabs(dFabs (q[0]) - 0.5*s[0]) > tol &&
  599. dFabs(dFabs (q[1]) - 0.5*s[1]) > tol &&
  600. dFabs(dFabs (q[2]) - 0.5*s[2]) > tol) {
  601. FAILED();
  602. }
  603. // also check normal signs
  604. if (dCalcVectorDot3 (q3,contact.normal) > 0) FAILED();
  605. draw_all_objects (space);
  606. }
  607. PASSED();
  608. }
  609. int test_ray_and_ccylinder()
  610. {
  611. int j;
  612. dContactGeom contact;
  613. dVector3 p,a,b,n;
  614. dMatrix3 R;
  615. dReal r,l,k,x,y;
  616. dSimpleSpace space(0);
  617. dGeomID ray = dCreateRay (0,0);
  618. dGeomID ccyl = dCreateCapsule (0,1,1);
  619. dSpaceAdd (space,ray);
  620. dSpaceAdd (space,ccyl);
  621. // ********** make a random capped cylinder
  622. r = dRandReal()*0.5 + 0.01;
  623. l = dRandReal()*1 + 0.01;
  624. dGeomCapsuleSetParams (ccyl,r,l);
  625. dMakeRandomVector (p,3,1.0);
  626. dGeomSetPosition (ccyl,p[0],p[1],p[2]);
  627. dRFromAxisAndAngle (R,dRandReal()*2-1,dRandReal()*2-1,
  628. dRandReal()*2-1,dRandReal()*10-5);
  629. dGeomSetRotation (ccyl,R);
  630. // ********** test ray completely within ccyl
  631. for (j=0; j<3; j++) a[j] = dRandReal()-0.5;
  632. dNormalize3 (a);
  633. k = (dRandReal()-0.5)*l;
  634. for (j=0; j<3; j++) a[j] = p[j] + r*0.99*a[j] + k*0.99*R[j*4+2];
  635. for (j=0; j<3; j++) b[j] = dRandReal()-0.5;
  636. dNormalize3 (b);
  637. k = (dRandReal()-0.5)*l;
  638. for (j=0; j<3; j++) b[j] = p[j] + r*0.99*b[j] + k*0.99*R[j*4+2];
  639. dGeomRaySetLength (ray,dCalcPointsDistance3(a,b));
  640. for (j=0; j<3; j++) b[j] -= a[j];
  641. dNormalize3 (b);
  642. dGeomRaySet (ray,a[0],a[1],a[2],b[0],b[1],b[2]);
  643. if (dCollide (ray,ccyl,1,&contact,sizeof(dContactGeom)) != 0) FAILED();
  644. // ********** test ray outside ccyl that just misses (between caps)
  645. k = dRandReal()*2*M_PI;
  646. x = sin(k);
  647. y = cos(k);
  648. for (j=0; j<3; j++) a[j] = x*R[j*4+0] + y*R[j*4+1];
  649. k = (dRandReal()-0.5)*l;
  650. for (j=0; j<3; j++) b[j] = -a[j]*r*2 + k*R[j*4+2] + p[j];
  651. dGeomRaySet (ray,b[0],b[1],b[2],a[0],a[1],a[2]);
  652. dGeomRaySetLength (ray,r*0.99);
  653. if (dCollide (ray,ccyl,1,&contact,sizeof(dContactGeom)) != 0) FAILED();
  654. // ********** test ray outside ccyl that just hits (between caps)
  655. dGeomRaySetLength (ray,r*1.01);
  656. if (dCollide (ray,ccyl,1,&contact,sizeof(dContactGeom)) != 1) FAILED();
  657. // check depth of contact point
  658. if (dFabs (dGeomCapsulePointDepth
  659. (ccyl,contact.pos[0],contact.pos[1],contact.pos[2])) > tol)
  660. FAILED();
  661. // ********** test ray outside ccyl that just misses (caps)
  662. for (j=0; j<3; j++) a[j] = dRandReal()-0.5;
  663. dNormalize3 (a);
  664. if (dCalcVectorDot3_14(a,R+2) < 0) {
  665. for (j=0; j<3; j++) b[j] = p[j] - a[j]*2*r + l*0.5*R[j*4+2];
  666. }
  667. else {
  668. for (j=0; j<3; j++) b[j] = p[j] - a[j]*2*r - l*0.5*R[j*4+2];
  669. }
  670. dGeomRaySet (ray,b[0],b[1],b[2],a[0],a[1],a[2]);
  671. dGeomRaySetLength (ray,r*0.99);
  672. if (dCollide (ray,ccyl,1,&contact,sizeof(dContactGeom)) != 0) FAILED();
  673. // ********** test ray outside ccyl that just hits (caps)
  674. dGeomRaySetLength (ray,r*1.01);
  675. if (dCollide (ray,ccyl,1,&contact,sizeof(dContactGeom)) != 1) FAILED();
  676. // check depth of contact point
  677. if (dFabs (dGeomCapsulePointDepth
  678. (ccyl,contact.pos[0],contact.pos[1],contact.pos[2])) > tol)
  679. FAILED();
  680. // ********** test random rays
  681. for (j=0; j<3; j++) a[j] = dRandReal()-0.5;
  682. for (j=0; j<3; j++) n[j] = dRandReal()-0.5;
  683. dNormalize3 (n);
  684. dGeomRaySet (ray,a[0],a[1],a[2],n[0],n[1],n[2]);
  685. dGeomRaySetLength (ray,10);
  686. if (dCollide (ray,ccyl,1,&contact,sizeof(dContactGeom))) {
  687. // check depth of contact point
  688. if (dFabs (dGeomCapsulePointDepth
  689. (ccyl,contact.pos[0],contact.pos[1],contact.pos[2])) > tol)
  690. FAILED();
  691. // check normal signs
  692. if (dCalcVectorDot3 (n,contact.normal) > 0) FAILED();
  693. draw_all_objects (space);
  694. }
  695. PASSED();
  696. }
  697. /*
  698. Test rays within the cylinder
  699. -completely inside
  700. -exiting through side
  701. -exiting through cap
  702. -exiting through corner
  703. Test rays outside the cylinder
  704. */
  705. int test_ray_and_cylinder()
  706. {
  707. int j;
  708. dContactGeom contact;
  709. dVector3 p,a,b,n;
  710. dMatrix3 R;
  711. dReal r,l,k,x,y;
  712. const int positions = 5;
  713. const int slices = 13;
  714. const int pitch = 11;
  715. dSimpleSpace space(0);
  716. dGeomID ray = dCreateRay(space,4);
  717. dGeomID cyl = dCreateCylinder(space,0.5,1);
  718. // The first thing that happens is the ray is
  719. // rotated into cylinder coordinates. We'll trust that's
  720. // done right. The major axis is in the z-dir.
  721. // Random tests
  722. /*b[0]=4*dRandReal()-2;
  723. b[1]=4*dRandReal()-2;
  724. b[2]=4*dRandReal()-2;
  725. a[0]=2*dRandReal()-1;
  726. a[1]=2*dRandReal()-1;
  727. a[2]=2*dRandReal()-1;*/
  728. // Inside out
  729. b[0]=dRandReal()-0.5;
  730. b[1]=dRandReal()-0.5;
  731. b[2]=dRandReal()-0.5;
  732. a[0]=2*dRandReal()-1;
  733. a[1]=2*dRandReal()-1;
  734. a[2]=2*dRandReal()-1;
  735. // Outside in
  736. /*b[0]=4*dRandReal()-2;
  737. b[1]=4*dRandReal()-2;
  738. b[2]=4*dRandReal()-2;
  739. a[0]=-b[0];
  740. a[1]=-b[1];
  741. a[2]=-b[2];*/
  742. dGeomRaySet (ray,b[0],b[1],b[2],a[0],a[1],a[2]);
  743. // This is just for visual inspection right now.
  744. //if (dCollide (ray,cyl,1,&contact,sizeof(dContactGeom)) != 1) FAILED();
  745. draw_all_objects (space);
  746. PASSED();
  747. }
  748. int test_ray_and_plane()
  749. {
  750. int j;
  751. dContactGeom contact;
  752. dVector3 n,p,q,a,b,g,h; // n,d = plane parameters
  753. dMatrix3 R;
  754. dReal d;
  755. dSimpleSpace space(0);
  756. dGeomID ray = dCreateRay (0,0);
  757. dGeomID plane = dCreatePlane (0,0,0,1,0);
  758. dSpaceAdd (space,ray);
  759. dSpaceAdd (space,plane);
  760. // ********** make a random plane
  761. for (j=0; j<3; j++) n[j] = dRandReal() - 0.5;
  762. dNormalize3 (n);
  763. d = dRandReal() - 0.5;
  764. dGeomPlaneSetParams (plane,n[0],n[1],n[2],d);
  765. dPlaneSpace (n,p,q);
  766. // ********** test finite length ray below plane
  767. dGeomRaySetLength (ray,0.09);
  768. a[0] = dRandReal()-0.5;
  769. a[1] = dRandReal()-0.5;
  770. a[2] = -dRandReal()*0.5 - 0.1;
  771. for (j=0; j<3; j++) b[j] = a[0]*p[j] + a[1]*q[j] + (a[2]+d)*n[j];
  772. dGeomSetPosition (ray,b[0],b[1],b[2]);
  773. dRFromAxisAndAngle (R,dRandReal()*2-1,dRandReal()*2-1,
  774. dRandReal()*2-1,dRandReal()*10-5);
  775. dGeomSetRotation (ray,R);
  776. if (dCollide (ray,plane,1,&contact,sizeof(dContactGeom)) != 0) FAILED();
  777. // ********** test finite length ray above plane
  778. a[0] = dRandReal()-0.5;
  779. a[1] = dRandReal()-0.5;
  780. a[2] = dRandReal()*0.5 + 0.01;
  781. for (j=0; j<3; j++) b[j] = a[0]*p[j] + a[1]*q[j] + (a[2]+d)*n[j];
  782. g[0] = dRandReal()-0.5;
  783. g[1] = dRandReal()-0.5;
  784. g[2] = dRandReal() + 0.01;
  785. for (j=0; j<3; j++) h[j] = g[0]*p[j] + g[1]*q[j] + g[2]*n[j];
  786. dNormalize3 (h);
  787. dGeomRaySet (ray,b[0],b[1],b[2],h[0],h[1],h[2]);
  788. dGeomRaySetLength (ray,10);
  789. if (dCollide (ray,plane,1,&contact,sizeof(dContactGeom)) != 0) FAILED();
  790. // ********** test finite length ray that intersects plane
  791. a[0] = dRandReal()-0.5;
  792. a[1] = dRandReal()-0.5;
  793. a[2] = dRandReal()-0.5;
  794. for (j=0; j<3; j++) b[j] = a[0]*p[j] + a[1]*q[j] + (a[2]+d)*n[j];
  795. g[0] = dRandReal()-0.5;
  796. g[1] = dRandReal()-0.5;
  797. g[2] = dRandReal()-0.5;
  798. for (j=0; j<3; j++) h[j] = g[0]*p[j] + g[1]*q[j] + g[2]*n[j];
  799. dNormalize3 (h);
  800. dGeomRaySet (ray,b[0],b[1],b[2],h[0],h[1],h[2]);
  801. dGeomRaySetLength (ray,10);
  802. if (dCollide (ray,plane,1,&contact,sizeof(dContactGeom))) {
  803. // test that contact is on plane surface
  804. if (dFabs (dCalcVectorDot3(contact.pos,n) - d) > tol) FAILED();
  805. // also check normal signs
  806. if (dCalcVectorDot3 (h,contact.normal) > 0) FAILED();
  807. // also check contact point depth
  808. if (dFabs (dGeomPlanePointDepth
  809. (plane,contact.pos[0],contact.pos[1],contact.pos[2])) > tol)
  810. FAILED();
  811. draw_all_objects (space);
  812. }
  813. // ********** test ray that just misses
  814. for (j=0; j<3; j++) b[j] = (1+d)*n[j];
  815. for (j=0; j<3; j++) h[j] = -n[j];
  816. dGeomRaySet (ray,b[0],b[1],b[2],h[0],h[1],h[2]);
  817. dGeomRaySetLength (ray,0.99);
  818. if (dCollide (ray,plane,1,&contact,sizeof(dContactGeom)) != 0) FAILED();
  819. // ********** test ray that just hits
  820. dGeomRaySetLength (ray,1.01);
  821. if (dCollide (ray,plane,1,&contact,sizeof(dContactGeom)) != 1) FAILED();
  822. // ********** test polarity with typical ground plane
  823. dGeomPlaneSetParams (plane,0,0,1,0);
  824. for (j=0; j<3; j++) a[j] = 0.1;
  825. for (j=0; j<3; j++) b[j] = 0;
  826. a[2] = 1;
  827. b[2] = -1;
  828. dGeomRaySet (ray,a[0],a[1],a[2],b[0],b[1],b[2]);
  829. dGeomRaySetLength (ray,2);
  830. if (dCollide (ray,plane,1,&contact,sizeof(dContactGeom)) != 1) FAILED();
  831. if (dFabs (contact.depth - 1) > tol) FAILED();
  832. a[2] = -1;
  833. b[2] = 1;
  834. dGeomRaySet (ray,a[0],a[1],a[2],b[0],b[1],b[2]);
  835. if (dCollide (ray,plane,1,&contact,sizeof(dContactGeom)) != 1) FAILED();
  836. if (dFabs (contact.depth - 1) > tol) FAILED();
  837. PASSED();
  838. }
  839. //****************************************************************************
  840. // a really inefficient, but hopefully correct implementation of
  841. // dBoxTouchesBox(), that does 144 edge-face tests.
  842. // return 1 if edge v1 -> v2 hits the rectangle described by p1,p2,p3
  843. static int edgeIntersectsRect (dVector3 v1, dVector3 v2,
  844. dVector3 p1, dVector3 p2, dVector3 p3)
  845. {
  846. int k;
  847. dVector3 u1,u2,n,tmp;
  848. for (k=0; k<3; k++) u1[k] = p3[k]-p1[k];
  849. for (k=0; k<3; k++) u2[k] = p2[k]-p1[k];
  850. dReal d1 = dSqrt(dCalcVectorDot3(u1,u1));
  851. dReal d2 = dSqrt(dCalcVectorDot3(u2,u2));
  852. dNormalize3 (u1);
  853. dNormalize3 (u2);
  854. if (dFabs(dCalcVectorDot3(u1,u2)) > 1e-6) dDebug (0,"bad u1/u2");
  855. dCalcVectorCross3(n,u1,u2);
  856. for (k=0; k<3; k++) tmp[k] = v2[k]-v1[k];
  857. dReal d = -dCalcVectorDot3(n,p1);
  858. if (dFabs(dCalcVectorDot3(n,p1)+d) > 1e-8) dDebug (0,"bad n wrt p1");
  859. if (dFabs(dCalcVectorDot3(n,p2)+d) > 1e-8) dDebug (0,"bad n wrt p2");
  860. if (dFabs(dCalcVectorDot3(n,p3)+d) > 1e-8) dDebug (0,"bad n wrt p3");
  861. dReal alpha = -(d+dCalcVectorDot3(n,v1))/dCalcVectorDot3(n,tmp);
  862. for (k=0; k<3; k++) tmp[k] = v1[k]+alpha*(v2[k]-v1[k]);
  863. if (dFabs(dCalcVectorDot3(n,tmp)+d) > 1e-6) dDebug (0,"bad tmp");
  864. if (alpha < 0) return 0;
  865. if (alpha > 1) return 0;
  866. for (k=0; k<3; k++) tmp[k] -= p1[k];
  867. dReal a1 = dCalcVectorDot3(u1,tmp);
  868. dReal a2 = dCalcVectorDot3(u2,tmp);
  869. if (a1<0 || a2<0 || a1>d1 || a2>d2) return 0;
  870. return 1;
  871. }
  872. // return 1 if box 1 is completely inside box 2
  873. static int box1inside2 (const dVector3 p1, const dMatrix3 R1,
  874. const dVector3 side1, const dVector3 p2,
  875. const dMatrix3 R2, const dVector3 side2)
  876. {
  877. for (int i=-1; i<=1; i+=2) {
  878. for (int j=-1; j<=1; j+=2) {
  879. for (int k=-1; k<=1; k+=2) {
  880. dVector3 v,vv;
  881. v[0] = i*0.5*side1[0];
  882. v[1] = j*0.5*side1[1];
  883. v[2] = k*0.5*side1[2];
  884. dMultiply0_331 (vv,R1,v);
  885. vv[0] += p1[0] - p2[0];
  886. vv[1] += p1[1] - p2[1];
  887. vv[2] += p1[2] - p2[2];
  888. for (int axis=0; axis < 3; axis++) {
  889. dReal z = dCalcVectorDot3_14(vv,R2+axis);
  890. if (z < (-side2[axis]*0.5) || z > (side2[axis]*0.5)) return 0;
  891. }
  892. }
  893. }
  894. }
  895. return 1;
  896. }
  897. // test if any edge from box 1 hits a face from box 2
  898. static int testBoxesTouch2 (const dVector3 p1, const dMatrix3 R1,
  899. const dVector3 side1, const dVector3 p2,
  900. const dMatrix3 R2, const dVector3 side2)
  901. {
  902. int j,k,j1,j2;
  903. // for 6 faces from box 2
  904. for (int fd=0; fd<3; fd++) { // direction for face
  905. for (int fo=0; fo<2; fo++) { // offset of face
  906. // get four points on the face. first get 2 indexes that are not fd
  907. int k1=0,k2=0;
  908. if (fd==0) { k1 = 1; k2 = 2; }
  909. if (fd==1) { k1 = 0; k2 = 2; }
  910. if (fd==2) { k1 = 0; k2 = 1; }
  911. dVector3 fp[4],tmp;
  912. k=0;
  913. for (j1=-1; j1<=1; j1+=2) {
  914. for (j2=-1; j2<=1; j2+=2) {
  915. fp[k][k1] = j1;
  916. fp[k][k2] = j2;
  917. fp[k][fd] = fo*2-1;
  918. k++;
  919. }
  920. }
  921. for (j=0; j<4; j++) {
  922. for (k=0; k<3; k++) fp[j][k] *= 0.5*side2[k];
  923. dMultiply0_331 (tmp,R2,fp[j]);
  924. for (k=0; k<3; k++) fp[j][k] = tmp[k] + p2[k];
  925. }
  926. // for 8 vertices
  927. dReal v1[3];
  928. for (v1[0]=-1; v1[0] <= 1; v1[0] += 2) {
  929. for (v1[1]=-1; v1[1] <= 1; v1[1] += 2) {
  930. for (v1[2]=-1; v1[2] <= 1; v1[2] += 2) {
  931. // for all possible +ve leading edges from those vertices
  932. for (int ei=0; ei < 3; ei ++) {
  933. if (v1[ei] < 0) {
  934. // get vertex1 -> vertex2 = an edge from box 1
  935. dVector3 vv1,vv2;
  936. for (k=0; k<3; k++) vv1[k] = v1[k] * 0.5*side1[k];
  937. for (k=0; k<3; k++) vv2[k] = (v1[k] + (k==ei)*2)*0.5*side1[k];
  938. dVector3 vertex1,vertex2;
  939. dMultiply0_331 (vertex1,R1,vv1);
  940. dMultiply0_331 (vertex2,R1,vv2);
  941. for (k=0; k<3; k++) vertex1[k] += p1[k];
  942. for (k=0; k<3; k++) vertex2[k] += p1[k];
  943. // see if vertex1 -> vertex2 interesects face
  944. if (edgeIntersectsRect (vertex1,vertex2,fp[0],fp[1],fp[2]))
  945. return 1;
  946. }
  947. }
  948. }
  949. }
  950. }
  951. }
  952. }
  953. if (box1inside2 (p1,R1,side1,p2,R2,side2)) return 1;
  954. if (box1inside2 (p2,R2,side2,p1,R1,side1)) return 1;
  955. return 0;
  956. }
  957. //****************************************************************************
  958. // dBoxTouchesBox() test
  959. int test_dBoxTouchesBox()
  960. {
  961. int k,bt1,bt2;
  962. dVector3 p1,p2,side1,side2;
  963. dMatrix3 R1,R2;
  964. dSimpleSpace space(0);
  965. dGeomID box1 = dCreateBox (0,1,1,1);
  966. dSpaceAdd (space,box1);
  967. dGeomID box2 = dCreateBox (0,1,1,1);
  968. dSpaceAdd (space,box2);
  969. dMakeRandomVector (p1,3,0.5);
  970. dMakeRandomVector (p2,3,0.5);
  971. for (k=0; k<3; k++) side1[k] = dRandReal() + 0.01;
  972. for (k=0; k<3; k++) side2[k] = dRandReal() + 0.01;
  973. dRFromAxisAndAngle (R1,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0,
  974. dRandReal()*2.0-1.0,dRandReal()*10.0-5.0);
  975. dRFromAxisAndAngle (R2,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0,
  976. dRandReal()*2.0-1.0,dRandReal()*10.0-5.0);
  977. dGeomBoxSetLengths (box1,side1[0],side1[1],side1[2]);
  978. dGeomBoxSetLengths (box2,side2[0],side2[1],side2[2]);
  979. dGeomSetPosition (box1,p1[0],p1[1],p1[2]);
  980. dGeomSetRotation (box1,R1);
  981. dGeomSetPosition (box2,p2[0],p2[1],p2[2]);
  982. dGeomSetRotation (box2,R2);
  983. draw_all_objects (space);
  984. int t1 = testBoxesTouch2 (p1,R1,side1,p2,R2,side2);
  985. int t2 = testBoxesTouch2 (p2,R2,side2,p1,R1,side1);
  986. bt1 = t1 || t2;
  987. bt2 = dBoxTouchesBox (p1,R1,side1,p2,R2,side2);
  988. if (bt1 != bt2) FAILED();
  989. /*
  990. // some more debugging info if necessary
  991. if (bt1 && bt2) printf ("agree - boxes touch\n");
  992. if (!bt1 && !bt2) printf ("agree - boxes don't touch\n");
  993. if (bt1 && !bt2) printf ("disagree - boxes touch but dBoxTouchesBox "
  994. "says no\n");
  995. if (!bt1 && bt2) printf ("disagree - boxes don't touch but dBoxTouchesBox "
  996. "says yes\n");
  997. */
  998. PASSED();
  999. }
  1000. //****************************************************************************
  1001. // test box-box collision
  1002. int test_dBoxBox()
  1003. {
  1004. int k,bt;
  1005. dVector3 p1,p2,side1,side2,normal,normal2;
  1006. dMatrix3 R1,R2;
  1007. dReal depth,depth2;
  1008. int code;
  1009. dContactGeom contact[48];
  1010. dSimpleSpace space(0);
  1011. dGeomID box1 = dCreateBox (0,1,1,1);
  1012. dSpaceAdd (space,box1);
  1013. dGeomID box2 = dCreateBox (0,1,1,1);
  1014. dSpaceAdd (space,box2);
  1015. dMakeRandomVector (p1,3,0.5);
  1016. dMakeRandomVector (p2,3,0.5);
  1017. for (k=0; k<3; k++) side1[k] = dRandReal() + 0.01;
  1018. for (k=0; k<3; k++) side2[k] = dRandReal() + 0.01;
  1019. dRFromAxisAndAngle (R1,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0,
  1020. dRandReal()*2.0-1.0,dRandReal()*10.0-5.0);
  1021. dRFromAxisAndAngle (R2,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0,
  1022. dRandReal()*2.0-1.0,dRandReal()*10.0-5.0);
  1023. // dRSetIdentity (R1); // we can also try this
  1024. // dRSetIdentity (R2);
  1025. dGeomBoxSetLengths (box1,side1[0],side1[1],side1[2]);
  1026. dGeomBoxSetLengths (box2,side2[0],side2[1],side2[2]);
  1027. dGeomSetPosition (box1,p1[0],p1[1],p1[2]);
  1028. dGeomSetRotation (box1,R1);
  1029. dGeomSetPosition (box2,p2[0],p2[1],p2[2]);
  1030. dGeomSetRotation (box2,R2);
  1031. code = 0;
  1032. depth = 0;
  1033. bt = dBoxBox (p1,R1,side1,p2,R2,side2,normal,&depth,&code,8,contact,
  1034. sizeof(dContactGeom));
  1035. if (bt==1) {
  1036. p2[0] += normal[0] * 0.96 * depth;
  1037. p2[1] += normal[1] * 0.96 * depth;
  1038. p2[2] += normal[2] * 0.96 * depth;
  1039. bt = dBoxBox (p1,R1,side1,p2,R2,side2,normal2,&depth2,&code,8,contact,
  1040. sizeof(dContactGeom));
  1041. /*
  1042. dGeomSetPosition (box2,p2[0],p2[1],p2[2]);
  1043. draw_all_objects (space);
  1044. */
  1045. if (bt != 1) {
  1046. FAILED();
  1047. dGeomSetPosition (box2,p2[0],p2[1],p2[2]);
  1048. draw_all_objects (space);
  1049. }
  1050. p2[0] += normal[0] * 0.08 * depth;
  1051. p2[1] += normal[1] * 0.08 * depth;
  1052. p2[2] += normal[2] * 0.08 * depth;
  1053. bt = dBoxBox (p1,R1,side1,p2,R2,side2,normal2,&depth2,&code,8,contact,
  1054. sizeof(dContactGeom));
  1055. if (bt != 0) FAILED();
  1056. // dGeomSetPosition (box2,p2[0],p2[1],p2[2]);
  1057. // draw_all_objects (space);
  1058. }
  1059. // printf ("code=%2d depth=%.4f ",code,depth);
  1060. PASSED();
  1061. }
  1062. //****************************************************************************
  1063. // graphics
  1064. int space_pressed = 0;
  1065. // start simulation - set viewpoint
  1066. static void start()
  1067. {
  1068. dAllocateODEDataForThread(dAllocateMaskAll);
  1069. static float xyz[3] = {2.4807,-1.8023,2.7600};
  1070. static float hpr[3] = {141.5000,-18.5000,0.0000};
  1071. dsSetViewpoint (xyz,hpr);
  1072. }
  1073. // called when a key pressed
  1074. static void command (int cmd)
  1075. {
  1076. if (cmd == ' ') space_pressed = 1;
  1077. }
  1078. // simulation loop
  1079. static void simLoop (int pause)
  1080. {
  1081. do {
  1082. draw_all_objects_called = 0;
  1083. unsigned long seed = dRandGetSeed();
  1084. testslot[graphical_test].test_fn();
  1085. if (draw_all_objects_called) {
  1086. if (space_pressed) space_pressed = 0; else dRandSetSeed (seed);
  1087. }
  1088. }
  1089. while (!draw_all_objects_called);
  1090. }
  1091. //****************************************************************************
  1092. // do all the tests
  1093. void do_tests (int argc, char **argv)
  1094. {
  1095. int i,j;
  1096. // process command line arguments
  1097. if (argc >= 2) {
  1098. graphical_test = atoi (argv[1]);
  1099. }
  1100. if (graphical_test) {
  1101. // do one test gaphically and interactively
  1102. if (graphical_test < 1 || graphical_test >= MAX_TESTS ||
  1103. !testslot[graphical_test].name) {
  1104. dError (0,"invalid test number");
  1105. }
  1106. printf ("performing test: %s\n",testslot[graphical_test].name);
  1107. // setup pointers to drawstuff callback functions
  1108. dsFunctions fn;
  1109. fn.version = DS_VERSION;
  1110. fn.start = &start;
  1111. fn.step = &simLoop;
  1112. fn.command = &command;
  1113. fn.stop = 0;
  1114. fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
  1115. dsSetSphereQuality (3);
  1116. dsSetCapsuleQuality (8);
  1117. dsSimulationLoop (argc,argv,1280,900,&fn);
  1118. }
  1119. else {
  1120. // do all tests noninteractively
  1121. for (i=0; i<MAX_TESTS; i++) testslot[i].number = i;
  1122. // first put the active tests into a separate array
  1123. int n=0;
  1124. for (i=0; i<MAX_TESTS; i++) if (testslot[i].name) n++;
  1125. TestSlot **ts = (TestSlot**) malloc (n * sizeof(TestSlot*));
  1126. j = 0;
  1127. for (i=0; i<MAX_TESTS; i++) if (testslot[i].name) ts[j++] = testslot+i;
  1128. if (j != n) dDebug (0,"internal");
  1129. // do two test batches. the first test batch has far fewer reps and will
  1130. // catch problems quickly. if all tests in the first batch passes, the
  1131. // second batch is run.
  1132. for (i=0; i<n; i++) ts[i]->failcount = 0;
  1133. int total_reps=0;
  1134. for (int batch=0; batch<2; batch++) {
  1135. int reps = (batch==0) ? TEST_REPS1 : TEST_REPS2;
  1136. total_reps += reps;
  1137. printf ("testing batch %d (%d reps)...\n",batch+1,reps);
  1138. // run tests
  1139. for (j=0; j<reps; j++) {
  1140. for (i=0; i<n; i++) {
  1141. current_test = ts[i]->number;
  1142. if (ts[i]->test_fn() != 1) ts[i]->failcount++;
  1143. }
  1144. }
  1145. // check for failures
  1146. int total_fail_count=0;
  1147. for (i=0; i<n; i++) total_fail_count += ts[i]->failcount;
  1148. if (total_fail_count) break;
  1149. }
  1150. // print results
  1151. for (i=0; i<n; i++) {
  1152. printf ("%3d: %-30s: ",ts[i]->number,ts[i]->name);
  1153. if (ts[i]->failcount) {
  1154. printf ("FAILED (%.2f%%) at line %d\n",
  1155. double(ts[i]->failcount)/double(total_reps)*100.0,
  1156. ts[i]->last_failed_line);
  1157. }
  1158. else {
  1159. printf ("ok\n");
  1160. }
  1161. }
  1162. }
  1163. }
  1164. //****************************************************************************
  1165. int main (int argc, char **argv)
  1166. {
  1167. // setup all tests
  1168. memset (testslot,0,sizeof(testslot));
  1169. dInitODE2(0);
  1170. MAKE_TEST(1,test_sphere_point_depth);
  1171. MAKE_TEST(2,test_box_point_depth);
  1172. MAKE_TEST(3,test_ccylinder_point_depth);
  1173. MAKE_TEST(4,test_plane_point_depth);
  1174. MAKE_TEST(10,test_ray_and_sphere);
  1175. MAKE_TEST(11,test_ray_and_box);
  1176. MAKE_TEST(12,test_ray_and_ccylinder);
  1177. MAKE_TEST(13,test_ray_and_plane);
  1178. MAKE_TEST(14,test_ray_and_cylinder);
  1179. MAKE_TEST(100,test_dBoxTouchesBox);
  1180. MAKE_TEST(101,test_dBoxBox);
  1181. do_tests (argc,argv);
  1182. dCloseODE();
  1183. return 0;
  1184. }