scrapbook.cpp_deprecated 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. /*
  2. this is code that was once useful but has now been obseleted.
  3. this file should not be compiled as part of ODE!
  4. */
  5. //***************************************************************************
  6. // intersect a line segment with a plane
  7. extern "C" int dClipLineToBox (const dVector3 p1, const dVector3 p2,
  8. const dVector3 p, const dMatrix3 R,
  9. const dVector3 side)
  10. {
  11. // compute the start and end of the line (p1 and p2) relative to the box.
  12. // we will do all subsequent computations in this box-relative coordinate
  13. // system. we have to do a translation and rotation for each point.
  14. dVector3 tmp,s,e;
  15. tmp[0] = p1[0] - p[0];
  16. tmp[1] = p1[1] - p[1];
  17. tmp[2] = p1[2] - p[2];
  18. dMULTIPLY1_331 (s,R,tmp);
  19. tmp[0] = p2[0] - p[0];
  20. tmp[1] = p2[1] - p[1];
  21. tmp[2] = p2[2] - p[2];
  22. dMULTIPLY1_331 (e,R,tmp);
  23. // compute the vector 'v' from the start point to the end point
  24. dVector3 v;
  25. v[0] = e[0] - s[0];
  26. v[1] = e[1] - s[1];
  27. v[2] = e[2] - s[2];
  28. // a point on the line is defined by the parameter 't'. t=0 corresponds
  29. // to the start of the line, t=1 corresponds to the end of the line.
  30. // we will clip the line to the box by finding the range of t where a
  31. // point on the line is inside the box. the currently known bounds for
  32. // t and tlo..thi.
  33. dReal tlo=0,thi=1;
  34. // clip in the X/Y/Z direction
  35. for (int i=0; i<3; i++) {
  36. // first adjust s,e for the current t range. this is redundant for the
  37. // first iteration, but never mind.
  38. e[i] = s[i] + thi*v[i];
  39. s[i] = s[i] + tlo*v[i];
  40. // compute where t intersects the positive and negative sides.
  41. dReal tp = ( side[i] - s[i])/v[i]; // @@@ handle case where denom=0
  42. dReal tm = (-side[i] - s[i])/v[i];
  43. // handle 9 intersection cases
  44. if (s[i] <= -side[i]) {
  45. tlo = tm;
  46. if (e[i] <= -side[i]) return 0;
  47. else if (e[i] >= side[i]) thi = tp;
  48. }
  49. else if (s[i] <= side[i]) {
  50. if (e[i] <= -side[i]) thi = tm;
  51. else if (e[i] >= side[i]) thi = tp;
  52. }
  53. else {
  54. tlo = tp;
  55. if (e[i] <= -side[i]) thi = tm;
  56. else if (e[i] >= side[i]) return 0;
  57. }
  58. }
  59. //... @@@ AT HERE @@@
  60. return 1;
  61. }
  62. //***************************************************************************
  63. // a nice try at C-B collision. unfortunately it doesn't work. the logic
  64. // for testing for line-box intersection is correct, but unfortunately the
  65. // closest-point distance estimates are often too large. as a result contact
  66. // points are placed incorrectly.
  67. int dCollideCB (const dxGeom *o1, const dxGeom *o2, int flags,
  68. dContactGeom *contact, int skip)
  69. {
  70. int i;
  71. dIASSERT (skip >= (int)sizeof(dContactGeom));
  72. dIASSERT (o1->_class->num == dCCylinderClass);
  73. dIASSERT (o2->_class->num == dBoxClass);
  74. contact->g1 = const_cast<dxGeom*> (o1);
  75. contact->g2 = const_cast<dxGeom*> (o2);
  76. dxCCylinder *cyl = (dxCCylinder*) CLASSDATA(o1);
  77. dxBox *box = (dxBox*) CLASSDATA(o2);
  78. // get p1,p2 = cylinder axis endpoints, get radius
  79. dVector3 p1,p2;
  80. dReal clen = cyl->lz * REAL(0.5);
  81. p1[0] = o1->pos[0] + clen * o1->R[2];
  82. p1[1] = o1->pos[1] + clen * o1->R[6];
  83. p1[2] = o1->pos[2] + clen * o1->R[10];
  84. p2[0] = o1->pos[0] - clen * o1->R[2];
  85. p2[1] = o1->pos[1] - clen * o1->R[6];
  86. p2[2] = o1->pos[2] - clen * o1->R[10];
  87. dReal radius = cyl->radius;
  88. // copy out box center, rotation matrix, and side array
  89. dReal *c = o2->pos;
  90. dReal *R = o2->R;
  91. dReal *side = box->side;
  92. // compute the start and end of the line (p1 and p2) relative to the box.
  93. // we will do all subsequent computations in this box-relative coordinate
  94. // system. we have to do a translation and rotation for each point.
  95. dVector3 tmp3,s,e;
  96. tmp3[0] = p1[0] - c[0];
  97. tmp3[1] = p1[1] - c[1];
  98. tmp3[2] = p1[2] - c[2];
  99. dMULTIPLY1_331 (s,R,tmp3);
  100. tmp3[0] = p2[0] - c[0];
  101. tmp3[1] = p2[1] - c[1];
  102. tmp3[2] = p2[2] - c[2];
  103. dMULTIPLY1_331 (e,R,tmp3);
  104. // compute the vector 'v' from the start point to the end point
  105. dVector3 v;
  106. v[0] = e[0] - s[0];
  107. v[1] = e[1] - s[1];
  108. v[2] = e[2] - s[2];
  109. // compute the half-sides of the box
  110. dReal S0 = side[0] * REAL(0.5);
  111. dReal S1 = side[1] * REAL(0.5);
  112. dReal S2 = side[2] * REAL(0.5);
  113. // compute the size of the bounding box around the line segment
  114. dReal B0 = dFabs (v[0]);
  115. dReal B1 = dFabs (v[1]);
  116. dReal B2 = dFabs (v[2]);
  117. // for all 6 separation axes, measure the penetration depth. if any depth is
  118. // less than 0 then the objects don't penetrate at all so we can just
  119. // return 0. find the axis with the smallest depth, and record its normal.
  120. // note: normalR is set to point to a column of R if that is the smallest
  121. // depth normal so far. otherwise normalR is 0 and normalC is set to a
  122. // vector relative to the box. invert_normal is 1 if the sign of the normal
  123. // should be flipped.
  124. dReal depth,trial_depth,tmp,length;
  125. const dReal *normalR=0;
  126. dVector3 normalC;
  127. int invert_normal = 0;
  128. int code = 0; // 0=no contact, 1-3=face contact, 4-6=edge contact
  129. depth = dInfinity;
  130. // look at face-normal axes
  131. #undef TEST
  132. #define TEST(center,depth_expr,norm,contact_code) \
  133. tmp = (center); \
  134. trial_depth = radius + REAL(0.5) * ((depth_expr) - dFabs(tmp)); \
  135. if (trial_depth < 0) return 0; \
  136. if (trial_depth < depth) { \
  137. depth = trial_depth; \
  138. normalR = (norm); \
  139. invert_normal = (tmp < 0); \
  140. code = contact_code; \
  141. }
  142. TEST (s[0]+e[0], side[0] + B0, R+0, 1);
  143. TEST (s[1]+e[1], side[1] + B1, R+1, 2);
  144. TEST (s[2]+e[2], side[2] + B2, R+2, 3);
  145. // look at v x box-edge axes
  146. #undef TEST
  147. #define TEST(box_radius,line_offset,nx,ny,nz,contact_code) \
  148. tmp = (line_offset); \
  149. trial_depth = (box_radius) - dFabs(tmp); \
  150. length = dSqrt ((nx)*(nx) + (ny)*(ny) + (nz)*(nz)); \
  151. if (length > 0) { \
  152. length = dRecip(length); \
  153. trial_depth = trial_depth * length + radius; \
  154. if (trial_depth < 0) return 0; \
  155. if (trial_depth < depth) { \
  156. depth = trial_depth; \
  157. normalR = 0; \
  158. normalC[0] = (nx)*length; \
  159. normalC[1] = (ny)*length; \
  160. normalC[2] = (nz)*length; \
  161. invert_normal = (tmp < 0); \
  162. code = contact_code; \
  163. } \
  164. }
  165. TEST (B2*S1+B1*S2,v[1]*s[2]-v[2]*s[1], 0,-v[2],v[1], 4);
  166. TEST (B2*S0+B0*S2,v[2]*s[0]-v[0]*s[2], v[2],0,-v[0], 5);
  167. TEST (B1*S0+B0*S1,v[0]*s[1]-v[1]*s[0], -v[1],v[0],0, 6);
  168. #undef TEST
  169. // if we get to this point, the box and ccylinder interpenetrate.
  170. // compute the normal in global coordinates.
  171. dReal *normal = contact[0].normal;
  172. if (normalR) {
  173. normal[0] = normalR[0];
  174. normal[1] = normalR[4];
  175. normal[2] = normalR[8];
  176. }
  177. else {
  178. dMULTIPLY0_331 (normal,R,normalC);
  179. }
  180. if (invert_normal) {
  181. normal[0] = -normal[0];
  182. normal[1] = -normal[1];
  183. normal[2] = -normal[2];
  184. }
  185. // set the depth
  186. contact[0].depth = depth;
  187. if (code == 0) {
  188. return 0; // should never get here
  189. }
  190. else if (code >= 4) {
  191. // handle edge contacts
  192. // find an endpoint q1 on the intersecting edge of the box
  193. dVector3 q1;
  194. dReal sign[3];
  195. for (i=0; i<3; i++) q1[i] = c[i];
  196. sign[0] = (dDOT14(normal,R+0) > 0) ? REAL(1.0) : REAL(-1.0);
  197. for (i=0; i<3; i++) q1[i] += sign[0] * S0 * R[i*4];
  198. sign[1] = (dDOT14(normal,R+1) > 0) ? REAL(1.0) : REAL(-1.0);
  199. for (i=0; i<3; i++) q1[i] += sign[1] * S1 * R[i*4+1];
  200. sign[2] = (dDOT14(normal,R+2) > 0) ? REAL(1.0) : REAL(-1.0);
  201. for (i=0; i<3; i++) q1[i] += sign[2] * S2 * R[i*4+2];
  202. // find the other endpoint q2 of the intersecting edge
  203. dVector3 q2;
  204. for (i=0; i<3; i++)
  205. q2[i] = q1[i] - R[code-4 + i*4] * (sign[code-4] * side[code-4]);
  206. // determine the closest point between the box edge and the line segment
  207. dVector3 cp1,cp2;
  208. dClosestLineSegmentPoints (q1,q2, p1,p2, cp1,cp2);
  209. for (i=0; i<3; i++) contact[0].pos[i] = cp1[i] - REAL(0.5)*normal[i]*depth;
  210. return 1;
  211. }
  212. else {
  213. // handle face contacts.
  214. // @@@ temporary: make deepest vertex on the line the contact point.
  215. // @@@ this kind of works, but we sometimes need two contact points for
  216. // @@@ stability.
  217. // compute 'v' in global coordinates
  218. dVector3 gv;
  219. for (i=0; i<3; i++) gv[i] = p2[i] - p1[i];
  220. if (dDOT (normal,gv) > 0) {
  221. for (i=0; i<3; i++)
  222. contact[0].pos[i] = p1[i] + (depth*REAL(0.5)-radius)*normal[i];
  223. }
  224. else {
  225. for (i=0; i<3; i++)
  226. contact[0].pos[i] = p2[i] + (depth*REAL(0.5)-radius)*normal[i];
  227. }
  228. return 1;
  229. }
  230. }
  231. //***************************************************************************
  232. // this function works, it's just not being used for anything at the moment:
  233. // given a box (R,side), `R' is the rotation matrix for the box, and `side'
  234. // is a vector of x/y/z side lengths, return the size of the interval of the
  235. // box projected along the given axis. if the axis has unit length then the
  236. // return value will be the actual diameter, otherwise the result will be
  237. // scaled by the axis length.
  238. static inline dReal boxDiameter (const dMatrix3 R, const dVector3 side,
  239. const dVector3 axis)
  240. {
  241. dVector3 q;
  242. dMULTIPLY1_331 (q,R,axis); // transform axis to body-relative
  243. return dFabs(q[0])*side[0] + dFabs(q[1])*side[1] + dFabs(q[2])*side[2];
  244. }
  245. //***************************************************************************
  246. // the old capped cylinder to capped cylinder collision code. this fails to
  247. // detect cap-to-cap contact points when the cylinder axis are aligned, but
  248. // other that that it is pretty robust.
  249. // this returns at most one contact point when the two cylinder's axes are not
  250. // aligned, and at most two (for stability) when they are aligned.
  251. // the algorithm minimizes the distance between two "sample spheres" that are
  252. // positioned along the cylinder axes according to:
  253. // sphere1 = pos1 + alpha1 * axis1
  254. // sphere2 = pos2 + alpha2 * axis2
  255. // alpha1 and alpha2 are limited to +/- half the length of the cylinders.
  256. // the algorithm works by finding a solution that has both alphas free, or
  257. // a solution that has one or both alphas fixed to the ends of the cylinder.
  258. int dCollideCCylinderCCylinder (dxGeom *o1, dxGeom *o2,
  259. int flags, dContactGeom *contact, int skip)
  260. {
  261. int i;
  262. const dReal tolerance = REAL(1e-5);
  263. dIASSERT (skip >= (int)sizeof(dContactGeom));
  264. dIASSERT (o1->type == dCCylinderClass);
  265. dIASSERT (o2->type == dCCylinderClass);
  266. dxCCylinder *cyl1 = (dxCCylinder*) o1;
  267. dxCCylinder *cyl2 = (dxCCylinder*) o2;
  268. contact->g1 = o1;
  269. contact->g2 = o2;
  270. // copy out some variables, for convenience
  271. dReal lz1 = cyl1->lz * REAL(0.5);
  272. dReal lz2 = cyl2->lz * REAL(0.5);
  273. dReal *pos1 = o1->pos;
  274. dReal *pos2 = o2->pos;
  275. dReal axis1[3],axis2[3];
  276. axis1[0] = o1->R[2];
  277. axis1[1] = o1->R[6];
  278. axis1[2] = o1->R[10];
  279. axis2[0] = o2->R[2];
  280. axis2[1] = o2->R[6];
  281. axis2[2] = o2->R[10];
  282. dReal alpha1,alpha2,sphere1[3],sphere2[3];
  283. int fix1 = 0; // 0 if alpha1 is free, +/-1 to fix at +/- lz1
  284. int fix2 = 0; // 0 if alpha2 is free, +/-1 to fix at +/- lz2
  285. for (int count=0; count<9; count++) {
  286. // find a trial solution by fixing or not fixing the alphas
  287. if (fix1) {
  288. if (fix2) {
  289. // alpha1 and alpha2 are fixed, so the solution is easy
  290. if (fix1 > 0) alpha1 = lz1; else alpha1 = -lz1;
  291. if (fix2 > 0) alpha2 = lz2; else alpha2 = -lz2;
  292. for (i=0; i<3; i++) sphere1[i] = pos1[i] + alpha1*axis1[i];
  293. for (i=0; i<3; i++) sphere2[i] = pos2[i] + alpha2*axis2[i];
  294. }
  295. else {
  296. // fix alpha1 but let alpha2 be free
  297. if (fix1 > 0) alpha1 = lz1; else alpha1 = -lz1;
  298. for (i=0; i<3; i++) sphere1[i] = pos1[i] + alpha1*axis1[i];
  299. alpha2 = (axis2[0]*(sphere1[0]-pos2[0]) +
  300. axis2[1]*(sphere1[1]-pos2[1]) +
  301. axis2[2]*(sphere1[2]-pos2[2]));
  302. for (i=0; i<3; i++) sphere2[i] = pos2[i] + alpha2*axis2[i];
  303. }
  304. }
  305. else {
  306. if (fix2) {
  307. // fix alpha2 but let alpha1 be free
  308. if (fix2 > 0) alpha2 = lz2; else alpha2 = -lz2;
  309. for (i=0; i<3; i++) sphere2[i] = pos2[i] + alpha2*axis2[i];
  310. alpha1 = (axis1[0]*(sphere2[0]-pos1[0]) +
  311. axis1[1]*(sphere2[1]-pos1[1]) +
  312. axis1[2]*(sphere2[2]-pos1[2]));
  313. for (i=0; i<3; i++) sphere1[i] = pos1[i] + alpha1*axis1[i];
  314. }
  315. else {
  316. // let alpha1 and alpha2 be free
  317. // compute determinant of d(d^2)\d(alpha) jacobian
  318. dReal a1a2 = dDOT (axis1,axis2);
  319. dReal det = REAL(1.0)-a1a2*a1a2;
  320. if (det < tolerance) {
  321. // the cylinder axes (almost) parallel, so we will generate up to two
  322. // contacts. the solution matrix is rank deficient so alpha1 and
  323. // alpha2 are related by:
  324. // alpha2 = alpha1 + (pos1-pos2)'*axis1 (if axis1==axis2)
  325. // or alpha2 = -(alpha1 + (pos1-pos2)'*axis1) (if axis1==-axis2)
  326. // first compute where the two cylinders overlap in alpha1 space:
  327. if (a1a2 < 0) {
  328. axis2[0] = -axis2[0];
  329. axis2[1] = -axis2[1];
  330. axis2[2] = -axis2[2];
  331. }
  332. dReal q[3];
  333. for (i=0; i<3; i++) q[i] = pos1[i]-pos2[i];
  334. dReal k = dDOT (axis1,q);
  335. dReal a1lo = -lz1;
  336. dReal a1hi = lz1;
  337. dReal a2lo = -lz2 - k;
  338. dReal a2hi = lz2 - k;
  339. dReal lo = (a1lo > a2lo) ? a1lo : a2lo;
  340. dReal hi = (a1hi < a2hi) ? a1hi : a2hi;
  341. if (lo <= hi) {
  342. int num_contacts = flags & NUMC_MASK;
  343. if (num_contacts >= 2 && lo < hi) {
  344. // generate up to two contacts. if one of those contacts is
  345. // not made, fall back on the one-contact strategy.
  346. for (i=0; i<3; i++) sphere1[i] = pos1[i] + lo*axis1[i];
  347. for (i=0; i<3; i++) sphere2[i] = pos2[i] + (lo+k)*axis2[i];
  348. int n1 = dCollideSpheres (sphere1,cyl1->radius,
  349. sphere2,cyl2->radius,contact);
  350. if (n1) {
  351. for (i=0; i<3; i++) sphere1[i] = pos1[i] + hi*axis1[i];
  352. for (i=0; i<3; i++) sphere2[i] = pos2[i] + (hi+k)*axis2[i];
  353. dContactGeom *c2 = CONTACT(contact,skip);
  354. int n2 = dCollideSpheres (sphere1,cyl1->radius,
  355. sphere2,cyl2->radius, c2);
  356. if (n2) {
  357. c2->g1 = o1;
  358. c2->g2 = o2;
  359. return 2;
  360. }
  361. }
  362. }
  363. // just one contact to generate, so put it in the middle of
  364. // the range
  365. alpha1 = (lo + hi) * REAL(0.5);
  366. alpha2 = alpha1 + k;
  367. for (i=0; i<3; i++) sphere1[i] = pos1[i] + alpha1*axis1[i];
  368. for (i=0; i<3; i++) sphere2[i] = pos2[i] + alpha2*axis2[i];
  369. return dCollideSpheres (sphere1,cyl1->radius,
  370. sphere2,cyl2->radius,contact);
  371. }
  372. else return 0;
  373. }
  374. det = REAL(1.0)/det;
  375. dReal delta[3];
  376. for (i=0; i<3; i++) delta[i] = pos1[i] - pos2[i];
  377. dReal q1 = dDOT (delta,axis1);
  378. dReal q2 = dDOT (delta,axis2);
  379. alpha1 = det*(a1a2*q2-q1);
  380. alpha2 = det*(q2-a1a2*q1);
  381. for (i=0; i<3; i++) sphere1[i] = pos1[i] + alpha1*axis1[i];
  382. for (i=0; i<3; i++) sphere2[i] = pos2[i] + alpha2*axis2[i];
  383. }
  384. }
  385. // if the alphas are outside their allowed ranges then fix them and
  386. // try again
  387. if (fix1==0) {
  388. if (alpha1 < -lz1) {
  389. fix1 = -1;
  390. continue;
  391. }
  392. if (alpha1 > lz1) {
  393. fix1 = 1;
  394. continue;
  395. }
  396. }
  397. if (fix2==0) {
  398. if (alpha2 < -lz2) {
  399. fix2 = -1;
  400. continue;
  401. }
  402. if (alpha2 > lz2) {
  403. fix2 = 1;
  404. continue;
  405. }
  406. }
  407. // unfix the alpha variables if the local distance gradient indicates
  408. // that we are not yet at the minimum
  409. dReal tmp[3];
  410. for (i=0; i<3; i++) tmp[i] = sphere1[i] - sphere2[i];
  411. if (fix1) {
  412. dReal gradient = dDOT (tmp,axis1);
  413. if ((fix1 > 0 && gradient > 0) || (fix1 < 0 && gradient < 0)) {
  414. fix1 = 0;
  415. continue;
  416. }
  417. }
  418. if (fix2) {
  419. dReal gradient = -dDOT (tmp,axis2);
  420. if ((fix2 > 0 && gradient > 0) || (fix2 < 0 && gradient < 0)) {
  421. fix2 = 0;
  422. continue;
  423. }
  424. }
  425. return dCollideSpheres (sphere1,cyl1->radius,sphere2,cyl2->radius,contact);
  426. }
  427. // if we go through the loop too much, then give up. we should NEVER get to
  428. // this point (i hope).
  429. dMessage (0,"dCollideCC(): too many iterations");
  430. return 0;
  431. }