sphere.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  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/rotation.h>
  30. #include "config.h"
  31. #include "matrix.h"
  32. #include "odemath.h"
  33. #include "collision_kernel.h"
  34. #include "collision_std.h"
  35. #include "collision_util.h"
  36. #ifdef _MSC_VER
  37. #pragma warning(disable:4291) // for VC++, no complaints about "no matching operator delete found"
  38. #endif
  39. //****************************************************************************
  40. // sphere public API
  41. dxSphere::dxSphere (dSpaceID space, dReal _radius) : dxGeom (space,1)
  42. {
  43. dAASSERT (_radius >= 0);
  44. type = dSphereClass;
  45. radius = _radius;
  46. updateZeroSizedFlag(!_radius);
  47. }
  48. void dxSphere::computeAABB()
  49. {
  50. aabb[0] = final_posr->pos[0] - radius;
  51. aabb[1] = final_posr->pos[0] + radius;
  52. aabb[2] = final_posr->pos[1] - radius;
  53. aabb[3] = final_posr->pos[1] + radius;
  54. aabb[4] = final_posr->pos[2] - radius;
  55. aabb[5] = final_posr->pos[2] + radius;
  56. }
  57. dGeomID dCreateSphere (dSpaceID space, dReal radius)
  58. {
  59. return new dxSphere (space,radius);
  60. }
  61. void dGeomSphereSetRadius (dGeomID g, dReal radius)
  62. {
  63. dUASSERT (g && g->type == dSphereClass,"argument not a sphere");
  64. dAASSERT (radius >= 0);
  65. dxSphere *s = (dxSphere*) g;
  66. s->radius = radius;
  67. s->updateZeroSizedFlag(!radius);
  68. dGeomMoved (g);
  69. }
  70. dReal dGeomSphereGetRadius (dGeomID g)
  71. {
  72. dUASSERT (g && g->type == dSphereClass,"argument not a sphere");
  73. dxSphere *s = (dxSphere*) g;
  74. return s->radius;
  75. }
  76. dReal dGeomSpherePointDepth (dGeomID g, dReal x, dReal y, dReal z)
  77. {
  78. dUASSERT (g && g->type == dSphereClass,"argument not a sphere");
  79. g->recomputePosr();
  80. dxSphere *s = (dxSphere*) g;
  81. dReal * pos = s->final_posr->pos;
  82. return s->radius - dSqrt ((x-pos[0])*(x-pos[0]) +
  83. (y-pos[1])*(y-pos[1]) +
  84. (z-pos[2])*(z-pos[2]));
  85. }
  86. //****************************************************************************
  87. // pairwise collision functions for standard geom types
  88. int dCollideSphereSphere (dxGeom *o1, dxGeom *o2, int flags,
  89. dContactGeom *contact, int skip)
  90. {
  91. dIASSERT (skip >= (int)sizeof(dContactGeom));
  92. dIASSERT (o1->type == dSphereClass);
  93. dIASSERT (o2->type == dSphereClass);
  94. dIASSERT ((flags & NUMC_MASK) >= 1);
  95. dxSphere *sphere1 = (dxSphere*) o1;
  96. dxSphere *sphere2 = (dxSphere*) o2;
  97. contact->g1 = o1;
  98. contact->g2 = o2;
  99. contact->side1 = -1;
  100. contact->side2 = -1;
  101. return dCollideSpheres (o1->final_posr->pos,sphere1->radius,
  102. o2->final_posr->pos,sphere2->radius,contact);
  103. }
  104. int dCollideSphereBox (dxGeom *o1, dxGeom *o2, int flags,
  105. dContactGeom *contact, int skip)
  106. {
  107. dIASSERT (skip >= (int)sizeof(dContactGeom));
  108. dIASSERT (o1->type == dSphereClass);
  109. dIASSERT (o2->type == dBoxClass);
  110. dIASSERT ((flags & NUMC_MASK) >= 1);
  111. // this is easy. get the sphere center `p' relative to the box, and then clip
  112. // that to the boundary of the box (call that point `q'). if q is on the
  113. // boundary of the box and |p-q| is <= sphere radius, they touch.
  114. // if q is inside the box, the sphere is inside the box, so set a contact
  115. // normal to push the sphere to the closest box face.
  116. dVector3 l,t,p,q,r;
  117. dReal depth;
  118. int onborder = 0;
  119. dxSphere *sphere = (dxSphere*) o1;
  120. dxBox *box = (dxBox*) o2;
  121. contact->g1 = o1;
  122. contact->g2 = o2;
  123. contact->side1 = -1;
  124. contact->side2 = -1;
  125. p[0] = o1->final_posr->pos[0] - o2->final_posr->pos[0];
  126. p[1] = o1->final_posr->pos[1] - o2->final_posr->pos[1];
  127. p[2] = o1->final_posr->pos[2] - o2->final_posr->pos[2];
  128. l[0] = box->side[0]*REAL(0.5);
  129. t[0] = dCalcVectorDot3_14(p,o2->final_posr->R);
  130. if (t[0] < -l[0]) { t[0] = -l[0]; onborder = 1; }
  131. if (t[0] > l[0]) { t[0] = l[0]; onborder = 1; }
  132. l[1] = box->side[1]*REAL(0.5);
  133. t[1] = dCalcVectorDot3_14(p,o2->final_posr->R+1);
  134. if (t[1] < -l[1]) { t[1] = -l[1]; onborder = 1; }
  135. if (t[1] > l[1]) { t[1] = l[1]; onborder = 1; }
  136. t[2] = dCalcVectorDot3_14(p,o2->final_posr->R+2);
  137. l[2] = box->side[2]*REAL(0.5);
  138. if (t[2] < -l[2]) { t[2] = -l[2]; onborder = 1; }
  139. if (t[2] > l[2]) { t[2] = l[2]; onborder = 1; }
  140. if (!onborder) {
  141. // sphere center inside box. find closest face to `t'
  142. dReal min_distance = l[0] - dFabs(t[0]);
  143. int mini = 0;
  144. for (int i=1; i<3; i++) {
  145. dReal face_distance = l[i] - dFabs(t[i]);
  146. if (face_distance < min_distance) {
  147. min_distance = face_distance;
  148. mini = i;
  149. }
  150. }
  151. // contact position = sphere center
  152. contact->pos[0] = o1->final_posr->pos[0];
  153. contact->pos[1] = o1->final_posr->pos[1];
  154. contact->pos[2] = o1->final_posr->pos[2];
  155. // contact normal points to closest face
  156. dVector3 tmp;
  157. tmp[0] = 0;
  158. tmp[1] = 0;
  159. tmp[2] = 0;
  160. tmp[mini] = (t[mini] > 0) ? REAL(1.0) : REAL(-1.0);
  161. dMultiply0_331 (contact->normal,o2->final_posr->R,tmp);
  162. // contact depth = distance to wall along normal plus radius
  163. contact->depth = min_distance + sphere->radius;
  164. return 1;
  165. }
  166. t[3] = 0; //@@@ hmmm
  167. dMultiply0_331 (q,o2->final_posr->R,t);
  168. r[0] = p[0] - q[0];
  169. r[1] = p[1] - q[1];
  170. r[2] = p[2] - q[2];
  171. depth = sphere->radius - dSqrt(dCalcVectorDot3(r,r));
  172. if (depth < 0) return 0;
  173. contact->pos[0] = q[0] + o2->final_posr->pos[0];
  174. contact->pos[1] = q[1] + o2->final_posr->pos[1];
  175. contact->pos[2] = q[2] + o2->final_posr->pos[2];
  176. contact->normal[0] = r[0];
  177. contact->normal[1] = r[1];
  178. contact->normal[2] = r[2];
  179. dNormalize3 (contact->normal);
  180. contact->depth = depth;
  181. return 1;
  182. }
  183. int dCollideSpherePlane (dxGeom *o1, dxGeom *o2, int flags,
  184. dContactGeom *contact, int skip)
  185. {
  186. dIASSERT (skip >= (int)sizeof(dContactGeom));
  187. dIASSERT (o1->type == dSphereClass);
  188. dIASSERT (o2->type == dPlaneClass);
  189. dIASSERT ((flags & NUMC_MASK) >= 1);
  190. dxSphere *sphere = (dxSphere*) o1;
  191. dxPlane *plane = (dxPlane*) o2;
  192. contact->g1 = o1;
  193. contact->g2 = o2;
  194. contact->side1 = -1;
  195. contact->side2 = -1;
  196. dReal k = dCalcVectorDot3 (o1->final_posr->pos,plane->p);
  197. dReal depth = plane->p[3] - k + sphere->radius;
  198. if (depth >= 0) {
  199. contact->normal[0] = plane->p[0];
  200. contact->normal[1] = plane->p[1];
  201. contact->normal[2] = plane->p[2];
  202. contact->pos[0] = o1->final_posr->pos[0] - plane->p[0] * sphere->radius;
  203. contact->pos[1] = o1->final_posr->pos[1] - plane->p[1] * sphere->radius;
  204. contact->pos[2] = o1->final_posr->pos[2] - plane->p[2] * sphere->radius;
  205. contact->depth = depth;
  206. return 1;
  207. }
  208. else return 0;
  209. }