dCone.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. //Benoit CHAPEROT 2003-2004 www.jstarlab.com
  2. //some code inspired by Magic Software
  3. #include <ode/common.h>
  4. #include <ode/collision.h>
  5. #include <ode/matrix.h>
  6. #include <ode/rotation.h>
  7. #include <ode/odemath.h>
  8. #include "collision_kernel.h"
  9. #include "collision_std.h"
  10. #include "collision_std_internal.h"
  11. #include "collision_util.h"
  12. #include <drawstuff/drawstuff.h>
  13. #include "windows.h"
  14. #include "ode\ode.h"
  15. #define CONTACT(p,skip) ((dContactGeom*) (((char*)p) + (skip)))
  16. const dReal fEPSILON = 1e-9f;
  17. dxCone::dxCone (dSpaceID space, dReal _radius,dReal _length) :
  18. dxGeom (space,1)
  19. {
  20. dAASSERT(_radius > 0.f);
  21. dAASSERT(_length > 0.f);
  22. type = dConeClass;
  23. radius = _radius;
  24. lz = _length;
  25. }
  26. dxCone::~dxCone()
  27. {
  28. }
  29. void dxCone::computeAABB()
  30. {
  31. const dMatrix3& R = final_posr->R;
  32. const dVector3& pos = final_posr->pos;
  33. dReal xrange = dFabs(R[2] * lz) + radius;
  34. dReal yrange = dFabs(R[6] * lz) + radius;
  35. dReal zrange = dFabs(R[10] * lz) + radius;
  36. aabb[0] = pos[0] - xrange;
  37. aabb[1] = pos[0] + xrange;
  38. aabb[2] = pos[1] - yrange;
  39. aabb[3] = pos[1] + yrange;
  40. aabb[4] = pos[2] - zrange;
  41. aabb[5] = pos[2] + zrange;
  42. }
  43. dGeomID dCreateCone(dSpaceID space, dReal _radius,dReal _length)
  44. {
  45. return new dxCone(space,_radius,_length);
  46. }
  47. void dGeomConeSetParams (dGeomID g, dReal _radius, dReal _length)
  48. {
  49. dUASSERT (g && g->type == dConeClass,"argument not a cone");
  50. dAASSERT (_radius > 0.f);
  51. dAASSERT (_length > 0.f);
  52. g->recomputePosr();
  53. dxCone *c = (dxCone*) g;
  54. c->radius = _radius;
  55. c->lz = _length;
  56. dGeomMoved (g);
  57. }
  58. void dGeomConeGetParams (dGeomID g, dReal *_radius, dReal *_length)
  59. {
  60. dUASSERT (g && g->type == dConeClass,"argument not a cone");
  61. g->recomputePosr();
  62. dxCone *c = (dxCone*) g;
  63. *_radius = c->radius;
  64. *_length = c->lz;
  65. }
  66. //positive inside
  67. dReal dGeomConePointDepth(dGeomID g, dReal x, dReal y, dReal z)
  68. {
  69. dUASSERT (g && g->type == dConeClass,"argument not a cone");
  70. g->recomputePosr();
  71. dxCone *cone = (dxCone*) g;
  72. dVector3 tmp,q;
  73. tmp[0] = x - cone->final_posr->pos[0];
  74. tmp[1] = y - cone->final_posr->pos[1];
  75. tmp[2] = z - cone->final_posr->pos[2];
  76. dMULTIPLY1_331 (q,cone->final_posr->R,tmp);
  77. dReal r = cone->radius;
  78. dReal h = cone->lz;
  79. dReal d0 = (r - r*q[2]/h) - dSqrt(q[0]*q[0]+q[1]*q[1]);
  80. dReal d1 = q[2];
  81. dReal d2 = h-q[2];
  82. if (d0 < d1) {
  83. if (d0 < d2) return d0; else return d2;
  84. }
  85. else {
  86. if (d1 < d2) return d1; else return d2;
  87. }
  88. }
  89. //plane plane
  90. bool FindIntersectionPlanePlane(const dReal Plane0[4], const dReal Plane1[4],
  91. dVector3 LinePos,dVector3 LineDir)
  92. {
  93. // If Cross(N0,N1) is zero, then either planes are parallel and separated
  94. // or the same plane. In both cases, 'false' is returned. Otherwise,
  95. // the intersection line is
  96. //
  97. // L(t) = t*Cross(N0,N1) + c0*N0 + c1*N1
  98. //
  99. // for some coefficients c0 and c1 and for t any real number (the line
  100. // parameter). Taking dot products with the normals,
  101. //
  102. // d0 = Dot(N0,L) = c0*Dot(N0,N0) + c1*Dot(N0,N1)
  103. // d1 = Dot(N1,L) = c0*Dot(N0,N1) + c1*Dot(N1,N1)
  104. //
  105. // which are two equations in two unknowns. The solution is
  106. //
  107. // c0 = (Dot(N1,N1)*d0 - Dot(N0,N1)*d1)/det
  108. // c1 = (Dot(N0,N0)*d1 - Dot(N0,N1)*d0)/det
  109. //
  110. // where det = Dot(N0,N0)*Dot(N1,N1)-Dot(N0,N1)^2.
  111. /*
  112. Real fN00 = rkPlane0.Normal().SquaredLength();
  113. Real fN01 = rkPlane0.Normal().Dot(rkPlane1.Normal());
  114. Real fN11 = rkPlane1.Normal().SquaredLength();
  115. Real fDet = fN00*fN11 - fN01*fN01;
  116. if ( Math::FAbs(fDet) < gs_fEpsilon )
  117. return false;
  118. Real fInvDet = 1.0f/fDet;
  119. Real fC0 = (fN11*rkPlane0.Constant() - fN01*rkPlane1.Constant())*fInvDet;
  120. Real fC1 = (fN00*rkPlane1.Constant() - fN01*rkPlane0.Constant())*fInvDet;
  121. rkLine.Direction() = rkPlane0.Normal().Cross(rkPlane1.Normal());
  122. rkLine.Origin() = fC0*rkPlane0.Normal() + fC1*rkPlane1.Normal();
  123. return true;
  124. */
  125. dReal fN00 = dLENGTHSQUARED(Plane0);
  126. dReal fN01 = dDOT(Plane0,Plane1);
  127. dReal fN11 = dLENGTHSQUARED(Plane1);
  128. dReal fDet = fN00*fN11 - fN01*fN01;
  129. if ( fabs(fDet) < fEPSILON)
  130. return false;
  131. dReal fInvDet = 1.0f/fDet;
  132. dReal fC0 = (fN11*Plane0[3] - fN01*Plane1[3])*fInvDet;
  133. dReal fC1 = (fN00*Plane1[3] - fN01*Plane0[3])*fInvDet;
  134. dCROSS(LineDir,=,Plane0,Plane1);
  135. dNormalize3(LineDir);
  136. dVector3 Temp0,Temp1;
  137. dOPC(Temp0,*,Plane0,fC0);
  138. dOPC(Temp1,*,Plane1,fC1);
  139. dOP(LinePos,+,Temp0,Temp1);
  140. return true;
  141. }
  142. //plane ray
  143. bool FindIntersectionPlaneRay(const dReal Plane[4],
  144. const dVector3 &LinePos,const dVector3 &LineDir,
  145. dReal &u,dVector3 &Pos)
  146. {
  147. /*
  148. u = (A*X1 + B*Y1 + C*Z1 + D) / (A*(X1-X2) + B*(Y1-Y2)+C*(Z1-Z2))
  149. */
  150. dReal fDet = -dDot(Plane,LineDir,3);
  151. if ( fabs(fDet) < fEPSILON)
  152. return false;
  153. u = (dDot(Plane,LinePos,3) - Plane[3]) / fDet;
  154. dOPC(Pos,*,LineDir,u);
  155. dOPE(Pos,+=,LinePos);
  156. return true;
  157. }
  158. int SolveQuadraticPolynomial(dReal a,dReal b,dReal c,dReal &x0,dReal &x1)
  159. {
  160. dReal d = b*b - 4*a*c;
  161. int NumRoots = 0;
  162. dReal dr;
  163. if (d < 0.f)
  164. return NumRoots;
  165. if (d == 0.f)
  166. {
  167. NumRoots = 1;
  168. dr = 0.f;
  169. }
  170. else
  171. {
  172. NumRoots = 2;
  173. dr = sqrtf(d);
  174. }
  175. x0 = (-b -dr) / (2.f * a);
  176. x1 = (-b +dr) / (2.f * a);
  177. return NumRoots;
  178. }
  179. /*
  180. const int VALID_INTERSECTION = 1<<0;
  181. const int POS_TEST_FAILEDT0 = 1<<0;
  182. const int POS_TEST_FAILEDT1 = 1<<1;
  183. */
  184. int ProcessConeRayIntersectionPoint( dReal r,dReal h,
  185. const dVector3 &q,const dVector3 &v,dReal t,
  186. dVector3 &p,
  187. dVector3 &n,
  188. int &f)
  189. {
  190. dOPC(p,*,v,t);
  191. dOPE(p,+=,q);
  192. n[0] = 2*p[0];
  193. n[1] = 2*p[1];
  194. n[2] = -2*p[2]*r*r/(h*h);
  195. f = 0;
  196. if (p[2] > h) return 0;
  197. if (p[2] < 0) return 0;
  198. if (t > 1) return 0;
  199. if (t < 0) return 0;
  200. return 1;
  201. }
  202. //cone ray
  203. //line in cone space (position,direction)
  204. //distance from line position (direction normalized)(if any)
  205. //return the number of intersection
  206. int FindIntersectionConeRay(dReal r,dReal h,
  207. const dVector3 &q,const dVector3 &v,dContactGeom *pContact)
  208. {
  209. dVector3 qp,vp;
  210. dOPE(qp,=,q);
  211. dOPE(vp,=,v);
  212. qp[2] = h-q[2];
  213. vp[2] = -v[2];
  214. dReal ts = (r/h);
  215. ts *= ts;
  216. dReal a = vp[0]*vp[0] + vp[1]*vp[1] - ts*vp[2]*vp[2];
  217. dReal b = 2.f*qp[0]*vp[0] + 2.f*qp[1]*vp[1] - 2.f*ts*qp[2]*vp[2];
  218. dReal c = qp[0]*qp[0] + qp[1]*qp[1] - ts*qp[2]*qp[2];
  219. /*
  220. dReal a = v[0]*v[0] + v[1]*v[1] - (v[2]*v[2]*r*r) / (h*h);
  221. dReal b = 2.f*q[0]*v[0] + 2.f*q[1]*v[1] + 2.f*r*r*v[2]/h - 2*r*r*q[0]*v[0]/(h*h);
  222. dReal c = q[0]*q[0] + q[1]*q[1] + 2*r*r*q[2]/h - r*r*q[2]/(h*h) - r*r;
  223. */
  224. int nNumRoots=SolveQuadraticPolynomial(a,b,c,pContact[0].depth,pContact[1].depth);
  225. int flag = 0;
  226. dContactGeom ValidContact[2];
  227. int nNumValidContacts = 0;
  228. for (int i=0;i<nNumRoots;i++)
  229. {
  230. if (ProcessConeRayIntersectionPoint(r,h,q,v,pContact[i].depth,pContact[i].pos,
  231. pContact[i].normal,flag))
  232. {
  233. ValidContact[nNumValidContacts] = pContact[i];
  234. nNumValidContacts++;
  235. }
  236. }
  237. dOP(qp,+,q,v);
  238. if ((nNumValidContacts < 2) && (v[2] != 0.f))
  239. {
  240. dReal d = (0.f-q[2]) / (v[2]);
  241. if ((d>=0) && (d<=1))
  242. {
  243. dOPC(vp,*,v,d);
  244. dOP(qp,+,q,vp);
  245. if (qp[0]*qp[0]+qp[1]*qp[1] < r*r)
  246. {
  247. dOPE(ValidContact[nNumValidContacts].pos,=,qp);
  248. ValidContact[nNumValidContacts].normal[0] = 0.f;
  249. ValidContact[nNumValidContacts].normal[1] = 0.f;
  250. ValidContact[nNumValidContacts].normal[2] = -1.f;
  251. ValidContact[nNumValidContacts].depth = d;
  252. nNumValidContacts++;
  253. }
  254. }
  255. }
  256. if (nNumValidContacts == 2)
  257. {
  258. if (ValidContact[0].depth > ValidContact[1].depth)
  259. {
  260. pContact[0] = ValidContact[1];
  261. pContact[1] = ValidContact[0];
  262. }
  263. else
  264. {
  265. pContact[0] = ValidContact[0];
  266. pContact[1] = ValidContact[1];
  267. }
  268. }
  269. else if (nNumValidContacts == 1)
  270. {
  271. pContact[0] = ValidContact[0];
  272. }
  273. return nNumValidContacts;
  274. }
  275. int dCollideConePlane (dxGeom *o1, dxGeom *o2, int flags,
  276. dContactGeom *contact, int skip)
  277. {
  278. dIASSERT (skip >= (int)sizeof(dContactGeom));
  279. dIASSERT (o1->type == dConeClass);
  280. dIASSERT (o2->type == dPlaneClass);
  281. dxCone *cone = (dxCone*) o1;
  282. dxPlane *plane = (dxPlane*) o2;
  283. contact->g1 = o1;
  284. contact->g2 = o2;
  285. dVector3 p0,p1,pp0,pp1;
  286. dOPE(p0,=,cone->final_posr->pos);
  287. p1[0] = cone->final_posr->R[0*4+2] * cone->lz + p0[0];
  288. p1[1] = cone->final_posr->R[1*4+2] * cone->lz + p0[1];
  289. p1[2] = cone->final_posr->R[2*4+2] * cone->lz + p0[2];
  290. dReal u;
  291. FindIntersectionPlaneRay(plane->p,p0,plane->p,u,pp0);
  292. FindIntersectionPlaneRay(plane->p,p1,plane->p,u,pp1);
  293. if (dDISTANCE(pp0,pp1) < fEPSILON)
  294. {
  295. p1[0] = cone->final_posr->R[0*4+0] * cone->lz + p0[0];
  296. p1[1] = cone->final_posr->R[1*4+0] * cone->lz + p0[1];
  297. p1[2] = cone->final_posr->R[2*4+0] * cone->lz + p0[2];
  298. FindIntersectionPlaneRay(plane->p,p1,plane->p,u,pp1);
  299. dIASSERT(dDISTANCE(pp0,pp1) >= fEPSILON);
  300. }
  301. dVector3 h,r0,r1;
  302. h[0] = cone->final_posr->R[0*4+2];
  303. h[1] = cone->final_posr->R[1*4+2];
  304. h[2] = cone->final_posr->R[2*4+2];
  305. dOP(r0,-,pp0,pp1);
  306. dCROSS(r1,=,h,r0);
  307. dCROSS(r0,=,r1,h);
  308. dNormalize3(r0);
  309. dOPEC(h,*=,cone->lz);
  310. dOPEC(r0,*=,cone->radius);
  311. dVector3 p[3];
  312. dOP(p[0],+,cone->final_posr->pos,h);
  313. dOP(p[1],+,cone->final_posr->pos,r0);
  314. dOP(p[2],-,cone->final_posr->pos,r0);
  315. int numMaxContacts = flags & 0xffff;
  316. if (numMaxContacts == 0)
  317. numMaxContacts = 1;
  318. int n=0;
  319. for (int i=0;i<3;i++)
  320. {
  321. dReal d = dGeomPlanePointDepth(o2, p[i][0], p[i][1], p[i][2]);
  322. if (d>0.f)
  323. {
  324. CONTACT(contact,n*skip)->g1 = o1;
  325. CONTACT(contact,n*skip)->g2 = o2;
  326. dOPE(CONTACT(contact,n*skip)->normal,=,plane->p);
  327. dOPE(CONTACT(contact,n*skip)->pos,=,p[i]);
  328. CONTACT(contact,n*skip)->depth = d;
  329. n++;
  330. if (n == numMaxContacts)
  331. return n;
  332. }
  333. }
  334. return n;
  335. }
  336. int dCollideRayCone (dxGeom *o1, dxGeom *o2, int flags,
  337. dContactGeom *contact, int skip)
  338. {
  339. dIASSERT (skip >= (int)sizeof(dContactGeom));
  340. dIASSERT (o1->type == dRayClass);
  341. dIASSERT (o2->type == dConeClass);
  342. dxRay *ray = (dxRay*) o1;
  343. dxCone *cone = (dxCone*) o2;
  344. contact->g1 = o1;
  345. contact->g2 = o2;
  346. dVector3 tmp,q,v;
  347. tmp[0] = ray->final_posr->pos[0] - cone->final_posr->pos[0];
  348. tmp[1] = ray->final_posr->pos[1] - cone->final_posr->pos[1];
  349. tmp[2] = ray->final_posr->pos[2] - cone->final_posr->pos[2];
  350. dMULTIPLY1_331 (q,cone->final_posr->R,tmp);
  351. tmp[0] = ray->final_posr->R[0*4+2] * ray->length;
  352. tmp[1] = ray->final_posr->R[1*4+2] * ray->length;
  353. tmp[2] = ray->final_posr->R[2*4+2] * ray->length;
  354. dMULTIPLY1_331 (v,cone->final_posr->R,tmp);
  355. dReal r = cone->radius;
  356. dReal h = cone->lz;
  357. dContactGeom Contact[2];
  358. if (FindIntersectionConeRay(r,h,q,v,Contact))
  359. {
  360. dMULTIPLY0_331(contact->normal,cone->final_posr->R,Contact[0].normal);
  361. dMULTIPLY0_331(contact->pos,cone->final_posr->R,Contact[0].pos);
  362. dOPE(contact->pos,+=,cone->final_posr->pos);
  363. contact->depth = Contact[0].depth * dLENGTH(v);
  364. /*
  365. dMatrix3 RI;
  366. dRSetIdentity (RI);
  367. dVector3 ss;
  368. ss[0] = 0.01f;
  369. ss[1] = 0.01f;
  370. ss[2] = 0.01f;
  371. dsSetColorAlpha (1,0,0,0.8f);
  372. dsDrawBox(contact->pos,RI,ss);
  373. */
  374. return 1;
  375. }
  376. return 0;
  377. }
  378. int dCollideConeSphere(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip)
  379. {
  380. dIASSERT (skip >= (int)sizeof(dContactGeom));
  381. dIASSERT (o1->type == dConeClass);
  382. dIASSERT (o2->type == dSphereClass);
  383. dxCone *cone = (dxCone*) o1;
  384. dxSphere ASphere(0,cone->radius);
  385. dGeomSetRotation(&ASphere,cone->final_posr->R);
  386. dGeomSetPosition(&ASphere,cone->final_posr->pos[0],cone->final_posr->pos[1],cone->final_posr->pos[2]);
  387. return dCollideSphereSphere(&ASphere, o2, flags, contact, skip);
  388. }
  389. int dCollideConeBox(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip)
  390. {
  391. dIASSERT (skip >= (int)sizeof(dContactGeom));
  392. dIASSERT (o1->type == dConeClass);
  393. dIASSERT (o2->type == dBoxClass);
  394. dxCone *cone = (dxCone*) o1;
  395. dxSphere ASphere(0,cone->radius);
  396. dGeomSetRotation(&ASphere,cone->final_posr->R);
  397. dGeomSetPosition(&ASphere,cone->final_posr->pos[0],cone->final_posr->pos[1],cone->final_posr->pos[2]);
  398. return dCollideSphereBox(&ASphere, o2, flags, contact, skip);
  399. }
  400. int dCollideCCylinderCone(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip)
  401. {
  402. dIASSERT (skip >= (int)sizeof(dContactGeom));
  403. dIASSERT (o1->type == dCCylinderClass);
  404. dIASSERT (o2->type == dConeClass);
  405. dxCone *cone = (dxCone*) o2;
  406. dxSphere ASphere(0,cone->radius);
  407. dGeomSetRotation(&ASphere,cone->final_posr->R);
  408. dGeomSetPosition(&ASphere,cone->final_posr->pos[0],cone->final_posr->pos[1],cone->final_posr->pos[2]);
  409. return dCollideCCylinderSphere(o1, &ASphere, flags, contact, skip);
  410. }
  411. extern int dCollideSTL(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip);
  412. int dCollideTriMeshCone(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip)
  413. {
  414. dIASSERT (skip >= (int)sizeof(dContactGeom));
  415. dIASSERT (o1->type == dTriMeshClass);
  416. dIASSERT (o2->type == dConeClass);
  417. dxCone *cone = (dxCone*) o2;
  418. dxSphere ASphere(0,cone->radius);
  419. dGeomSetRotation(&ASphere,cone->final_posr->R);
  420. dGeomSetPosition(&ASphere,cone->final_posr->pos[0],cone->final_posr->pos[1],cone->final_posr->pos[2]);
  421. return dCollideSTL(o1, &ASphere, flags, contact, skip);
  422. }