box.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863
  1. /*************************************************************************
  2. * *
  3. * Open Dynamics Engine, Copyright (C) 2001-2003 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. standard ODE geometry primitives: public API and pairwise collision functions.
  24. the rule is that only the low level primitive collision functions should set
  25. dContactGeom::g1 and dContactGeom::g2.
  26. */
  27. #include <ode/common.h>
  28. #include <ode/collision.h>
  29. #include <ode/matrix.h>
  30. #include <ode/rotation.h>
  31. #include <ode/odemath.h>
  32. #include "collision_kernel.h"
  33. #include "collision_std.h"
  34. #include "collision_util.h"
  35. #ifdef _MSC_VER
  36. #pragma warning(disable:4291) // for VC++, no complaints about "no matching operator delete found"
  37. #endif
  38. //****************************************************************************
  39. // box public API
  40. dxBox::dxBox (dSpaceID space, dReal lx, dReal ly, dReal lz) : dxGeom (space,1)
  41. {
  42. dAASSERT (lx >= 0 && ly >= 0 && lz >= 0);
  43. type = dBoxClass;
  44. side[0] = lx;
  45. side[1] = ly;
  46. side[2] = lz;
  47. updateZeroSizedFlag(!lx || !ly || !lz);
  48. }
  49. void dxBox::computeAABB()
  50. {
  51. const dMatrix3& R = final_posr->R;
  52. const dVector3& pos = final_posr->pos;
  53. dReal xrange = REAL(0.5) * (dFabs (R[0] * side[0]) +
  54. dFabs (R[1] * side[1]) + dFabs (R[2] * side[2]));
  55. dReal yrange = REAL(0.5) * (dFabs (R[4] * side[0]) +
  56. dFabs (R[5] * side[1]) + dFabs (R[6] * side[2]));
  57. dReal zrange = REAL(0.5) * (dFabs (R[8] * side[0]) +
  58. dFabs (R[9] * side[1]) + dFabs (R[10] * side[2]));
  59. aabb[0] = pos[0] - xrange;
  60. aabb[1] = pos[0] + xrange;
  61. aabb[2] = pos[1] - yrange;
  62. aabb[3] = pos[1] + yrange;
  63. aabb[4] = pos[2] - zrange;
  64. aabb[5] = pos[2] + zrange;
  65. }
  66. dGeomID dCreateBox (dSpaceID space, dReal lx, dReal ly, dReal lz)
  67. {
  68. return new dxBox (space,lx,ly,lz);
  69. }
  70. void dGeomBoxSetLengths (dGeomID g, dReal lx, dReal ly, dReal lz)
  71. {
  72. dUASSERT (g && g->type == dBoxClass,"argument not a box");
  73. dAASSERT (lx >= 0 && ly >= 0 && lz >= 0);
  74. dxBox *b = (dxBox*) g;
  75. b->side[0] = lx;
  76. b->side[1] = ly;
  77. b->side[2] = lz;
  78. b->updateZeroSizedFlag(!lx || !ly || !lz);
  79. dGeomMoved (g);
  80. }
  81. void dGeomBoxGetLengths (dGeomID g, dVector3 result)
  82. {
  83. dUASSERT (g && g->type == dBoxClass,"argument not a box");
  84. dxBox *b = (dxBox*) g;
  85. result[0] = b->side[0];
  86. result[1] = b->side[1];
  87. result[2] = b->side[2];
  88. }
  89. dReal dGeomBoxPointDepth (dGeomID g, dReal x, dReal y, dReal z)
  90. {
  91. dUASSERT (g && g->type == dBoxClass,"argument not a box");
  92. g->recomputePosr();
  93. dxBox *b = (dxBox*) g;
  94. // Set p = (x,y,z) relative to box center
  95. //
  96. // This will be (0,0,0) if the point is at (side[0]/2,side[1]/2,side[2]/2)
  97. dVector3 p,q;
  98. p[0] = x - b->final_posr->pos[0];
  99. p[1] = y - b->final_posr->pos[1];
  100. p[2] = z - b->final_posr->pos[2];
  101. // Rotate p into box's coordinate frame, so we can
  102. // treat the OBB as an AABB
  103. dMULTIPLY1_331 (q,b->final_posr->R,p);
  104. // Record distance from point to each successive box side, and see
  105. // if the point is inside all six sides
  106. dReal dist[6];
  107. int i;
  108. bool inside = true;
  109. for (i=0; i < 3; i++) {
  110. dReal side = b->side[i] * REAL(0.5);
  111. dist[i ] = side - q[i];
  112. dist[i+3] = side + q[i];
  113. if ((dist[i] < 0) || (dist[i+3] < 0)) {
  114. inside = false;
  115. }
  116. }
  117. // If point is inside the box, the depth is the smallest positive distance
  118. // to any side
  119. if (inside) {
  120. dReal smallest_dist = (dReal) (unsigned) -1;
  121. for (i=0; i < 6; i++) {
  122. if (dist[i] < smallest_dist) smallest_dist = dist[i];
  123. }
  124. return smallest_dist;
  125. }
  126. // Otherwise, if point is outside the box, the depth is the largest
  127. // distance to any side. This is an approximation to the 'proper'
  128. // solution (the proper solution may be larger in some cases).
  129. dReal largest_dist = 0;
  130. for (i=0; i < 6; i++) {
  131. if (dist[i] > largest_dist) largest_dist = dist[i];
  132. }
  133. return -largest_dist;
  134. }
  135. //****************************************************************************
  136. // box-box collision utility
  137. // find all the intersection points between the 2D rectangle with vertices
  138. // at (+/-h[0],+/-h[1]) and the 2D quadrilateral with vertices (p[0],p[1]),
  139. // (p[2],p[3]),(p[4],p[5]),(p[6],p[7]).
  140. //
  141. // the intersection points are returned as x,y pairs in the 'ret' array.
  142. // the number of intersection points is returned by the function (this will
  143. // be in the range 0 to 8).
  144. static int intersectRectQuad (dReal h[2], dReal p[8], dReal ret[16])
  145. {
  146. // q (and r) contain nq (and nr) coordinate points for the current (and
  147. // chopped) polygons
  148. int nq=4,nr;
  149. dReal buffer[16];
  150. dReal *q = p;
  151. dReal *r = ret;
  152. for (int dir=0; dir <= 1; dir++) {
  153. // direction notation: xy[0] = x axis, xy[1] = y axis
  154. for (int sign=-1; sign <= 1; sign += 2) {
  155. // chop q along the line xy[dir] = sign*h[dir]
  156. dReal *pq = q;
  157. dReal *pr = r;
  158. nr = 0;
  159. for (int i=nq; i > 0; i--) {
  160. // go through all points in q and all lines between adjacent points
  161. if (sign*pq[dir] < h[dir]) {
  162. // this point is inside the chopping line
  163. pr[0] = pq[0];
  164. pr[1] = pq[1];
  165. pr += 2;
  166. nr++;
  167. if (nr & 8) {
  168. q = r;
  169. goto done;
  170. }
  171. }
  172. dReal *nextq = (i > 1) ? pq+2 : q;
  173. if ((sign*pq[dir] < h[dir]) ^ (sign*nextq[dir] < h[dir])) {
  174. // this line crosses the chopping line
  175. pr[1-dir] = pq[1-dir] + (nextq[1-dir]-pq[1-dir]) /
  176. (nextq[dir]-pq[dir]) * (sign*h[dir]-pq[dir]);
  177. pr[dir] = sign*h[dir];
  178. pr += 2;
  179. nr++;
  180. if (nr & 8) {
  181. q = r;
  182. goto done;
  183. }
  184. }
  185. pq += 2;
  186. }
  187. q = r;
  188. r = (q==ret) ? buffer : ret;
  189. nq = nr;
  190. }
  191. }
  192. done:
  193. if (q != ret) memcpy (ret,q,nr*2*sizeof(dReal));
  194. return nr;
  195. }
  196. // given n points in the plane (array p, of size 2*n), generate m points that
  197. // best represent the whole set. the definition of 'best' here is not
  198. // predetermined - the idea is to select points that give good box-box
  199. // collision detection behavior. the chosen point indexes are returned in the
  200. // array iret (of size m). 'i0' is always the first entry in the array.
  201. // n must be in the range [1..8]. m must be in the range [1..n]. i0 must be
  202. // in the range [0..n-1].
  203. void cullPoints (int n, dReal p[], int m, int i0, int iret[])
  204. {
  205. // compute the centroid of the polygon in cx,cy
  206. int i,j;
  207. dReal a,cx,cy,q;
  208. if (n==1) {
  209. cx = p[0];
  210. cy = p[1];
  211. }
  212. else if (n==2) {
  213. cx = REAL(0.5)*(p[0] + p[2]);
  214. cy = REAL(0.5)*(p[1] + p[3]);
  215. }
  216. else {
  217. a = 0;
  218. cx = 0;
  219. cy = 0;
  220. for (i=0; i<(n-1); i++) {
  221. q = p[i*2]*p[i*2+3] - p[i*2+2]*p[i*2+1];
  222. a += q;
  223. cx += q*(p[i*2]+p[i*2+2]);
  224. cy += q*(p[i*2+1]+p[i*2+3]);
  225. }
  226. q = p[n*2-2]*p[1] - p[0]*p[n*2-1];
  227. a = dRecip(REAL(3.0)*(a+q));
  228. cx = a*(cx + q*(p[n*2-2]+p[0]));
  229. cy = a*(cy + q*(p[n*2-1]+p[1]));
  230. }
  231. // compute the angle of each point w.r.t. the centroid
  232. dReal A[8];
  233. for (i=0; i<n; i++) A[i] = dAtan2(p[i*2+1]-cy,p[i*2]-cx);
  234. // search for points that have angles closest to A[i0] + i*(2*pi/m).
  235. int avail[8];
  236. for (i=0; i<n; i++) avail[i] = 1;
  237. avail[i0] = 0;
  238. iret[0] = i0;
  239. iret++;
  240. for (j=1; j<m; j++) {
  241. a = (dReal)(dReal(j)*(2*M_PI/m) + A[i0]);
  242. if (a > M_PI) a -= (dReal)(2*M_PI);
  243. dReal maxdiff=1e9,diff;
  244. #ifndef dNODEBUG
  245. *iret = i0; // iret is not allowed to keep this value
  246. #endif
  247. for (i=0; i<n; i++) {
  248. if (avail[i]) {
  249. diff = dFabs (A[i]-a);
  250. if (diff > M_PI) diff = (dReal) (2*M_PI - diff);
  251. if (diff < maxdiff) {
  252. maxdiff = diff;
  253. *iret = i;
  254. }
  255. }
  256. }
  257. #ifndef dNODEBUG
  258. dIASSERT (*iret != i0); // ensure iret got set
  259. #endif
  260. avail[*iret] = 0;
  261. iret++;
  262. }
  263. }
  264. // given two boxes (p1,R1,side1) and (p2,R2,side2), collide them together and
  265. // generate contact points. this returns 0 if there is no contact otherwise
  266. // it returns the number of contacts generated.
  267. // `normal' returns the contact normal.
  268. // `depth' returns the maximum penetration depth along that normal.
  269. // `return_code' returns a number indicating the type of contact that was
  270. // detected:
  271. // 1,2,3 = box 2 intersects with a face of box 1
  272. // 4,5,6 = box 1 intersects with a face of box 2
  273. // 7..15 = edge-edge contact
  274. // `maxc' is the maximum number of contacts allowed to be generated, i.e.
  275. // the size of the `contact' array.
  276. // `contact' and `skip' are the contact array information provided to the
  277. // collision functions. this function only fills in the position and depth
  278. // fields.
  279. int dBoxBox (const dVector3 p1, const dMatrix3 R1,
  280. const dVector3 side1, const dVector3 p2,
  281. const dMatrix3 R2, const dVector3 side2,
  282. dVector3 normal, dReal *depth, int *return_code,
  283. int flags, dContactGeom *contact, int skip)
  284. {
  285. const dReal fudge_factor = REAL(1.05);
  286. dVector3 p,pp,normalC={0,0,0};
  287. const dReal *normalR = 0;
  288. dReal A[3],B[3],R11,R12,R13,R21,R22,R23,R31,R32,R33,
  289. Q11,Q12,Q13,Q21,Q22,Q23,Q31,Q32,Q33,s,s2,l,expr1_val;
  290. int i,j,invert_normal,code;
  291. // get vector from centers of box 1 to box 2, relative to box 1
  292. p[0] = p2[0] - p1[0];
  293. p[1] = p2[1] - p1[1];
  294. p[2] = p2[2] - p1[2];
  295. dMULTIPLY1_331 (pp,R1,p); // get pp = p relative to body 1
  296. // get side lengths / 2
  297. A[0] = side1[0]*REAL(0.5);
  298. A[1] = side1[1]*REAL(0.5);
  299. A[2] = side1[2]*REAL(0.5);
  300. B[0] = side2[0]*REAL(0.5);
  301. B[1] = side2[1]*REAL(0.5);
  302. B[2] = side2[2]*REAL(0.5);
  303. // Rij is R1'*R2, i.e. the relative rotation between R1 and R2
  304. R11 = dDOT44(R1+0,R2+0); R12 = dDOT44(R1+0,R2+1); R13 = dDOT44(R1+0,R2+2);
  305. R21 = dDOT44(R1+1,R2+0); R22 = dDOT44(R1+1,R2+1); R23 = dDOT44(R1+1,R2+2);
  306. R31 = dDOT44(R1+2,R2+0); R32 = dDOT44(R1+2,R2+1); R33 = dDOT44(R1+2,R2+2);
  307. Q11 = dFabs(R11); Q12 = dFabs(R12); Q13 = dFabs(R13);
  308. Q21 = dFabs(R21); Q22 = dFabs(R22); Q23 = dFabs(R23);
  309. Q31 = dFabs(R31); Q32 = dFabs(R32); Q33 = dFabs(R33);
  310. // for all 15 possible separating axes:
  311. // * see if the axis separates the boxes. if so, return 0.
  312. // * find the depth of the penetration along the separating axis (s2)
  313. // * if this is the largest depth so far, record it.
  314. // the normal vector will be set to the separating axis with the smallest
  315. // depth. note: normalR is set to point to a column of R1 or R2 if that is
  316. // the smallest depth normal so far. otherwise normalR is 0 and normalC is
  317. // set to a vector relative to body 1. invert_normal is 1 if the sign of
  318. // the normal should be flipped.
  319. do {
  320. #define TST(expr1,expr2,norm,cc) \
  321. expr1_val = (expr1); /* Avoid duplicate evaluation of expr1 */ \
  322. s2 = dFabs(expr1_val) - (expr2); \
  323. if (s2 > 0) return 0; \
  324. if (s2 > s) { \
  325. s = s2; \
  326. normalR = norm; \
  327. invert_normal = ((expr1_val) < 0); \
  328. code = (cc); \
  329. if (flags & CONTACTS_UNIMPORTANT) break; \
  330. }
  331. s = -dInfinity;
  332. invert_normal = 0;
  333. code = 0;
  334. // separating axis = u1,u2,u3
  335. TST (pp[0],(A[0] + B[0]*Q11 + B[1]*Q12 + B[2]*Q13),R1+0,1);
  336. TST (pp[1],(A[1] + B[0]*Q21 + B[1]*Q22 + B[2]*Q23),R1+1,2);
  337. TST (pp[2],(A[2] + B[0]*Q31 + B[1]*Q32 + B[2]*Q33),R1+2,3);
  338. // separating axis = v1,v2,v3
  339. TST (dDOT41(R2+0,p),(A[0]*Q11 + A[1]*Q21 + A[2]*Q31 + B[0]),R2+0,4);
  340. TST (dDOT41(R2+1,p),(A[0]*Q12 + A[1]*Q22 + A[2]*Q32 + B[1]),R2+1,5);
  341. TST (dDOT41(R2+2,p),(A[0]*Q13 + A[1]*Q23 + A[2]*Q33 + B[2]),R2+2,6);
  342. // note: cross product axes need to be scaled when s is computed.
  343. // normal (n1,n2,n3) is relative to box 1.
  344. #undef TST
  345. #define TST(expr1,expr2,n1,n2,n3,cc) \
  346. expr1_val = (expr1); /* Avoid duplicate evaluation of expr1 */ \
  347. s2 = dFabs(expr1_val) - (expr2); \
  348. if (s2 > 0) return 0; \
  349. l = dSqrt ((n1)*(n1) + (n2)*(n2) + (n3)*(n3)); \
  350. if (l > 0) { \
  351. s2 /= l; \
  352. if (s2*fudge_factor > s) { \
  353. s = s2; \
  354. normalR = 0; \
  355. normalC[0] = (n1)/l; normalC[1] = (n2)/l; normalC[2] = (n3)/l; \
  356. invert_normal = ((expr1_val) < 0); \
  357. code = (cc); \
  358. if (flags & CONTACTS_UNIMPORTANT) break; \
  359. } \
  360. }
  361. // We only need to check 3 edges per box
  362. // since parallel edges are equivalent.
  363. // separating axis = u1 x (v1,v2,v3)
  364. TST(pp[2]*R21-pp[1]*R31,(A[1]*Q31+A[2]*Q21+B[1]*Q13+B[2]*Q12),0,-R31,R21,7);
  365. TST(pp[2]*R22-pp[1]*R32,(A[1]*Q32+A[2]*Q22+B[0]*Q13+B[2]*Q11),0,-R32,R22,8);
  366. TST(pp[2]*R23-pp[1]*R33,(A[1]*Q33+A[2]*Q23+B[0]*Q12+B[1]*Q11),0,-R33,R23,9);
  367. // separating axis = u2 x (v1,v2,v3)
  368. TST(pp[0]*R31-pp[2]*R11,(A[0]*Q31+A[2]*Q11+B[1]*Q23+B[2]*Q22),R31,0,-R11,10);
  369. TST(pp[0]*R32-pp[2]*R12,(A[0]*Q32+A[2]*Q12+B[0]*Q23+B[2]*Q21),R32,0,-R12,11);
  370. TST(pp[0]*R33-pp[2]*R13,(A[0]*Q33+A[2]*Q13+B[0]*Q22+B[1]*Q21),R33,0,-R13,12);
  371. // separating axis = u3 x (v1,v2,v3)
  372. TST(pp[1]*R11-pp[0]*R21,(A[0]*Q21+A[1]*Q11+B[1]*Q33+B[2]*Q32),-R21,R11,0,13);
  373. TST(pp[1]*R12-pp[0]*R22,(A[0]*Q22+A[1]*Q12+B[0]*Q33+B[2]*Q31),-R22,R12,0,14);
  374. TST(pp[1]*R13-pp[0]*R23,(A[0]*Q23+A[1]*Q13+B[0]*Q32+B[1]*Q31),-R23,R13,0,15);
  375. #undef TST
  376. } while (0);
  377. if (!code) return 0;
  378. // if we get to this point, the boxes interpenetrate. compute the normal
  379. // in global coordinates.
  380. if (normalR) {
  381. normal[0] = normalR[0];
  382. normal[1] = normalR[4];
  383. normal[2] = normalR[8];
  384. }
  385. else {
  386. dMULTIPLY0_331 (normal,R1,normalC);
  387. }
  388. if (invert_normal) {
  389. normal[0] = -normal[0];
  390. normal[1] = -normal[1];
  391. normal[2] = -normal[2];
  392. }
  393. *depth = -s;
  394. // compute contact point(s)
  395. if (code > 6) {
  396. // An edge from box 1 touches an edge from box 2.
  397. // find a point pa on the intersecting edge of box 1
  398. dVector3 pa;
  399. dReal sign;
  400. // Copy p1 into pa
  401. for (i=0; i<3; i++) pa[i] = p1[i]; // why no memcpy?
  402. // Get world position of p2 into pa
  403. for (j=0; j<3; j++) {
  404. sign = (dDOT14(normal,R1+j) > 0) ? REAL(1.0) : REAL(-1.0);
  405. for (i=0; i<3; i++) pa[i] += sign * A[j] * R1[i*4+j];
  406. }
  407. // find a point pb on the intersecting edge of box 2
  408. dVector3 pb;
  409. // Copy p2 into pb
  410. for (i=0; i<3; i++) pb[i] = p2[i]; // why no memcpy?
  411. // Get world position of p2 into pb
  412. for (j=0; j<3; j++) {
  413. sign = (dDOT14(normal,R2+j) > 0) ? REAL(-1.0) : REAL(1.0);
  414. for (i=0; i<3; i++) pb[i] += sign * B[j] * R2[i*4+j];
  415. }
  416. dReal alpha,beta;
  417. dVector3 ua,ub;
  418. // Get direction of first edge
  419. for (i=0; i<3; i++) ua[i] = R1[((code)-7)/3 + i*4];
  420. // Get direction of second edge
  421. for (i=0; i<3; i++) ub[i] = R2[((code)-7)%3 + i*4];
  422. // Get closest points between edges (one at each)
  423. dLineClosestApproach (pa,ua,pb,ub,&alpha,&beta);
  424. for (i=0; i<3; i++) pa[i] += ua[i]*alpha;
  425. for (i=0; i<3; i++) pb[i] += ub[i]*beta;
  426. // Set the contact point as halfway between the 2 closest points
  427. for (i=0; i<3; i++) contact[0].pos[i] = REAL(0.5)*(pa[i]+pb[i]);
  428. contact[0].depth = *depth;
  429. *return_code = code;
  430. return 1;
  431. }
  432. // okay, we have a face-something intersection (because the separating
  433. // axis is perpendicular to a face). define face 'a' to be the reference
  434. // face (i.e. the normal vector is perpendicular to this) and face 'b' to be
  435. // the incident face (the closest face of the other box).
  436. // Note: Unmodified parameter values are being used here
  437. const dReal *Ra,*Rb,*pa,*pb,*Sa,*Sb;
  438. if (code <= 3) { // One of the faces of box 1 is the reference face
  439. Ra = R1; // Rotation of 'a'
  440. Rb = R2; // Rotation of 'b'
  441. pa = p1; // Center (location) of 'a'
  442. pb = p2; // Center (location) of 'b'
  443. Sa = A; // Side Lenght of 'a'
  444. Sb = B; // Side Lenght of 'b'
  445. }
  446. else { // One of the faces of box 2 is the reference face
  447. Ra = R2; // Rotation of 'a'
  448. Rb = R1; // Rotation of 'b'
  449. pa = p2; // Center (location) of 'a'
  450. pb = p1; // Center (location) of 'b'
  451. Sa = B; // Side Lenght of 'a'
  452. Sb = A; // Side Lenght of 'b'
  453. }
  454. // nr = normal vector of reference face dotted with axes of incident box.
  455. // anr = absolute values of nr.
  456. /*
  457. The normal is flipped if necessary so it always points outward from box 'a',
  458. box 'b' is thus always the incident box
  459. */
  460. dVector3 normal2,nr,anr;
  461. if (code <= 3) {
  462. normal2[0] = normal[0];
  463. normal2[1] = normal[1];
  464. normal2[2] = normal[2];
  465. }
  466. else {
  467. normal2[0] = -normal[0];
  468. normal2[1] = -normal[1];
  469. normal2[2] = -normal[2];
  470. }
  471. // Rotate normal2 in incident box opposite direction
  472. dMULTIPLY1_331 (nr,Rb,normal2);
  473. anr[0] = dFabs (nr[0]);
  474. anr[1] = dFabs (nr[1]);
  475. anr[2] = dFabs (nr[2]);
  476. // find the largest compontent of anr: this corresponds to the normal
  477. // for the incident face. the other axis numbers of the incident face
  478. // are stored in a1,a2.
  479. int lanr,a1,a2;
  480. if (anr[1] > anr[0]) {
  481. if (anr[1] > anr[2]) {
  482. a1 = 0;
  483. lanr = 1;
  484. a2 = 2;
  485. }
  486. else {
  487. a1 = 0;
  488. a2 = 1;
  489. lanr = 2;
  490. }
  491. }
  492. else {
  493. if (anr[0] > anr[2]) {
  494. lanr = 0;
  495. a1 = 1;
  496. a2 = 2;
  497. }
  498. else {
  499. a1 = 0;
  500. a2 = 1;
  501. lanr = 2;
  502. }
  503. }
  504. // compute center point of incident face, in reference-face coordinates
  505. dVector3 center;
  506. if (nr[lanr] < 0) {
  507. for (i=0; i<3; i++) center[i] = pb[i] - pa[i] + Sb[lanr] * Rb[i*4+lanr];
  508. }
  509. else {
  510. for (i=0; i<3; i++) center[i] = pb[i] - pa[i] - Sb[lanr] * Rb[i*4+lanr];
  511. }
  512. // find the normal and non-normal axis numbers of the reference box
  513. int codeN,code1,code2;
  514. if (code <= 3) codeN = code-1; else codeN = code-4;
  515. if (codeN==0) {
  516. code1 = 1;
  517. code2 = 2;
  518. }
  519. else if (codeN==1) {
  520. code1 = 0;
  521. code2 = 2;
  522. }
  523. else {
  524. code1 = 0;
  525. code2 = 1;
  526. }
  527. // find the four corners of the incident face, in reference-face coordinates
  528. dReal quad[8]; // 2D coordinate of incident face (x,y pairs)
  529. dReal c1,c2,m11,m12,m21,m22;
  530. c1 = dDOT14 (center,Ra+code1);
  531. c2 = dDOT14 (center,Ra+code2);
  532. // optimize this? - we have already computed this data above, but it is not
  533. // stored in an easy-to-index format. for now it's quicker just to recompute
  534. // the four dot products.
  535. m11 = dDOT44 (Ra+code1,Rb+a1);
  536. m12 = dDOT44 (Ra+code1,Rb+a2);
  537. m21 = dDOT44 (Ra+code2,Rb+a1);
  538. m22 = dDOT44 (Ra+code2,Rb+a2);
  539. {
  540. dReal k1 = m11*Sb[a1];
  541. dReal k2 = m21*Sb[a1];
  542. dReal k3 = m12*Sb[a2];
  543. dReal k4 = m22*Sb[a2];
  544. quad[0] = c1 - k1 - k3;
  545. quad[1] = c2 - k2 - k4;
  546. quad[2] = c1 - k1 + k3;
  547. quad[3] = c2 - k2 + k4;
  548. quad[4] = c1 + k1 + k3;
  549. quad[5] = c2 + k2 + k4;
  550. quad[6] = c1 + k1 - k3;
  551. quad[7] = c2 + k2 - k4;
  552. }
  553. // find the size of the reference face
  554. dReal rect[2];
  555. rect[0] = Sa[code1];
  556. rect[1] = Sa[code2];
  557. // intersect the incident and reference faces
  558. dReal ret[16];
  559. int n = intersectRectQuad (rect,quad,ret);
  560. if (n < 1) return 0; // this should never happen
  561. // convert the intersection points into reference-face coordinates,
  562. // and compute the contact position and depth for each point. only keep
  563. // those points that have a positive (penetrating) depth. delete points in
  564. // the 'ret' array as necessary so that 'point' and 'ret' correspond.
  565. dReal point[3*8]; // penetrating contact points
  566. dReal dep[8]; // depths for those points
  567. dReal det1 = dRecip(m11*m22 - m12*m21);
  568. m11 *= det1;
  569. m12 *= det1;
  570. m21 *= det1;
  571. m22 *= det1;
  572. int cnum = 0; // number of penetrating contact points found
  573. for (j=0; j < n; j++) {
  574. dReal k1 = m22*(ret[j*2]-c1) - m12*(ret[j*2+1]-c2);
  575. dReal k2 = -m21*(ret[j*2]-c1) + m11*(ret[j*2+1]-c2);
  576. for (i=0; i<3; i++) point[cnum*3+i] =
  577. center[i] + k1*Rb[i*4+a1] + k2*Rb[i*4+a2];
  578. dep[cnum] = Sa[codeN] - dDOT(normal2,point+cnum*3);
  579. if (dep[cnum] >= 0) {
  580. ret[cnum*2] = ret[j*2];
  581. ret[cnum*2+1] = ret[j*2+1];
  582. cnum++;
  583. if ((cnum | CONTACTS_UNIMPORTANT) == (flags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) {
  584. break;
  585. }
  586. }
  587. }
  588. if (cnum < 1) {
  589. return 0; // this should not happen, yet does at times (demo_plane2d single precision).
  590. }
  591. // we can't generate more contacts than we actually have
  592. int maxc = flags & NUMC_MASK;
  593. if (maxc > cnum) maxc = cnum;
  594. if (maxc < 1) maxc = 1; // Even though max count must not be zero this check is kept for backward compatibility as this is a public function
  595. if (cnum <= maxc) {
  596. // we have less contacts than we need, so we use them all
  597. for (j=0; j < cnum; j++) {
  598. dContactGeom *con = CONTACT(contact,skip*j);
  599. for (i=0; i<3; i++) con->pos[i] = point[j*3+i] + pa[i];
  600. con->depth = dep[j];
  601. }
  602. }
  603. else {
  604. dIASSERT(!(flags & CONTACTS_UNIMPORTANT)); // cnum should be generated not greater than maxc so that "then" clause is executed
  605. // we have more contacts than are wanted, some of them must be culled.
  606. // find the deepest point, it is always the first contact.
  607. int i1 = 0;
  608. dReal maxdepth = dep[0];
  609. for (i=1; i<cnum; i++) {
  610. if (dep[i] > maxdepth) {
  611. maxdepth = dep[i];
  612. i1 = i;
  613. }
  614. }
  615. int iret[8];
  616. cullPoints (cnum,ret,maxc,i1,iret);
  617. for (j=0; j < maxc; j++) {
  618. dContactGeom *con = CONTACT(contact,skip*j);
  619. for (i=0; i<3; i++) con->pos[i] = point[iret[j]*3+i] + pa[i];
  620. con->depth = dep[iret[j]];
  621. }
  622. cnum = maxc;
  623. }
  624. *return_code = code;
  625. return cnum;
  626. }
  627. int dCollideBoxBox (dxGeom *o1, dxGeom *o2, int flags,
  628. dContactGeom *contact, int skip)
  629. {
  630. dIASSERT (skip >= (int)sizeof(dContactGeom));
  631. dIASSERT (o1->type == dBoxClass);
  632. dIASSERT (o2->type == dBoxClass);
  633. dIASSERT ((flags & NUMC_MASK) >= 1);
  634. dVector3 normal;
  635. dReal depth;
  636. int code;
  637. dxBox *b1 = (dxBox*) o1;
  638. dxBox *b2 = (dxBox*) o2;
  639. int num = dBoxBox (o1->final_posr->pos,o1->final_posr->R,b1->side, o2->final_posr->pos,o2->final_posr->R,b2->side,
  640. normal,&depth,&code,flags,contact,skip);
  641. for (int i=0; i<num; i++) {
  642. CONTACT(contact,i*skip)->normal[0] = -normal[0];
  643. CONTACT(contact,i*skip)->normal[1] = -normal[1];
  644. CONTACT(contact,i*skip)->normal[2] = -normal[2];
  645. CONTACT(contact,i*skip)->g1 = o1;
  646. CONTACT(contact,i*skip)->g2 = o2;
  647. }
  648. return num;
  649. }
  650. int dCollideBoxPlane (dxGeom *o1, dxGeom *o2,
  651. int flags, dContactGeom *contact, int skip)
  652. {
  653. dIASSERT (skip >= (int)sizeof(dContactGeom));
  654. dIASSERT (o1->type == dBoxClass);
  655. dIASSERT (o2->type == dPlaneClass);
  656. dIASSERT ((flags & NUMC_MASK) >= 1);
  657. dxBox *box = (dxBox*) o1;
  658. dxPlane *plane = (dxPlane*) o2;
  659. contact->g1 = o1;
  660. contact->g2 = o2;
  661. int ret = 0;
  662. //@@@ problem: using 4-vector (plane->p) as 3-vector (normal).
  663. const dReal *R = o1->final_posr->R; // rotation of box
  664. const dReal *n = plane->p; // normal vector
  665. // project sides lengths along normal vector, get absolute values
  666. dReal Q1 = dDOT14(n,R+0);
  667. dReal Q2 = dDOT14(n,R+1);
  668. dReal Q3 = dDOT14(n,R+2);
  669. dReal A1 = box->side[0] * Q1;
  670. dReal A2 = box->side[1] * Q2;
  671. dReal A3 = box->side[2] * Q3;
  672. dReal B1 = dFabs(A1);
  673. dReal B2 = dFabs(A2);
  674. dReal B3 = dFabs(A3);
  675. // early exit test
  676. dReal depth = plane->p[3] + REAL(0.5)*(B1+B2+B3) - dDOT(n,o1->final_posr->pos);
  677. if (depth < 0) return 0;
  678. // find number of contacts requested
  679. int maxc = flags & NUMC_MASK;
  680. // if (maxc < 1) maxc = 1; // an assertion is made on entry
  681. if (maxc > 3) maxc = 3; // not more than 3 contacts per box allowed
  682. // find deepest point
  683. dVector3 p;
  684. p[0] = o1->final_posr->pos[0];
  685. p[1] = o1->final_posr->pos[1];
  686. p[2] = o1->final_posr->pos[2];
  687. #define FOO(i,op) \
  688. p[0] op REAL(0.5)*box->side[i] * R[0+i]; \
  689. p[1] op REAL(0.5)*box->side[i] * R[4+i]; \
  690. p[2] op REAL(0.5)*box->side[i] * R[8+i];
  691. #define BAR(i,iinc) if (A ## iinc > 0) { FOO(i,-=) } else { FOO(i,+=) }
  692. BAR(0,1);
  693. BAR(1,2);
  694. BAR(2,3);
  695. #undef FOO
  696. #undef BAR
  697. // the deepest point is the first contact point
  698. contact->pos[0] = p[0];
  699. contact->pos[1] = p[1];
  700. contact->pos[2] = p[2];
  701. contact->normal[0] = n[0];
  702. contact->normal[1] = n[1];
  703. contact->normal[2] = n[2];
  704. contact->depth = depth;
  705. ret = 1; // ret is number of contact points found so far
  706. if (maxc == 1) goto done;
  707. // get the second and third contact points by starting from `p' and going
  708. // along the two sides with the smallest projected length.
  709. #define FOO(i,j,op) \
  710. CONTACT(contact,i*skip)->pos[0] = p[0] op box->side[j] * R[0+j]; \
  711. CONTACT(contact,i*skip)->pos[1] = p[1] op box->side[j] * R[4+j]; \
  712. CONTACT(contact,i*skip)->pos[2] = p[2] op box->side[j] * R[8+j];
  713. #define BAR(ctact,side,sideinc) \
  714. depth -= B ## sideinc; \
  715. if (depth < 0) goto done; \
  716. if (A ## sideinc > 0) { FOO(ctact,side,+); } else { FOO(ctact,side,-); } \
  717. CONTACT(contact,ctact*skip)->depth = depth; \
  718. ret++;
  719. CONTACT(contact,skip)->normal[0] = n[0];
  720. CONTACT(contact,skip)->normal[1] = n[1];
  721. CONTACT(contact,skip)->normal[2] = n[2];
  722. if (maxc == 3) {
  723. CONTACT(contact,2*skip)->normal[0] = n[0];
  724. CONTACT(contact,2*skip)->normal[1] = n[1];
  725. CONTACT(contact,2*skip)->normal[2] = n[2];
  726. }
  727. if (B1 < B2) {
  728. if (B3 < B1) goto use_side_3; else {
  729. BAR(1,0,1); // use side 1
  730. if (maxc == 2) goto done;
  731. if (B2 < B3) goto contact2_2; else goto contact2_3;
  732. }
  733. }
  734. else {
  735. if (B3 < B2) {
  736. use_side_3: // use side 3
  737. BAR(1,2,3);
  738. if (maxc == 2) goto done;
  739. if (B1 < B2) goto contact2_1; else goto contact2_2;
  740. }
  741. else {
  742. BAR(1,1,2); // use side 2
  743. if (maxc == 2) goto done;
  744. if (B1 < B3) goto contact2_1; else goto contact2_3;
  745. }
  746. }
  747. contact2_1: BAR(2,0,1); goto done;
  748. contact2_2: BAR(2,1,2); goto done;
  749. contact2_3: BAR(2,2,3); goto done;
  750. #undef FOO
  751. #undef BAR
  752. done:
  753. for (int i=0; i<ret; i++) {
  754. CONTACT(contact,i*skip)->g1 = o1;
  755. CONTACT(contact,i*skip)->g2 = o2;
  756. }
  757. return ret;
  758. }