collision.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. #include <UnitTest++.h>
  2. #include <ode/ode.h>
  3. #include "common.h"
  4. TEST(test_collision_trimesh_sphere_exact)
  5. {
  6. /*
  7. * This tests some extreme cases, where a sphere barely touches some triangles
  8. * with zero depth.
  9. */
  10. #ifdef dTRIMESH_GIMPACT
  11. /*
  12. * Although GIMPACT is algorithmically able to handle this extreme case,
  13. * the numerical approximation used for the square root produces inexact results.
  14. */
  15. return;
  16. #endif
  17. {
  18. const int VertexCount = 4;
  19. const int IndexCount = 2*3;
  20. // this is a square on the XY plane
  21. /*
  22. 3 2
  23. +----+
  24. | /|
  25. | / |
  26. | / |
  27. |/ |
  28. +----+
  29. 0 1
  30. */
  31. float vertices[VertexCount * 3] = {
  32. -1,-1,0,
  33. 1,-1,0,
  34. 1,1,0,
  35. -1,1,0
  36. };
  37. dTriIndex indices[IndexCount] = {
  38. 0,1,2,
  39. 0,2,3
  40. };
  41. dTriMeshDataID data = dGeomTriMeshDataCreate();
  42. dGeomTriMeshDataBuildSingle(data,
  43. vertices,
  44. 3 * sizeof(float),
  45. VertexCount,
  46. indices,
  47. IndexCount,
  48. 3 * sizeof(dTriIndex));
  49. dGeomID trimesh = dCreateTriMesh(0, data, 0, 0, 0);
  50. const dReal radius = 4;
  51. dGeomID sphere = dCreateSphere(0, radius);
  52. dContactGeom cg[4];
  53. int nc;
  54. dVector3 trinormal = { 0, 0, -1 };
  55. // Test case: sphere touches the diagonal edge
  56. dGeomSetPosition(sphere, 0,0,radius);
  57. nc = dCollide(trimesh, sphere, 4, &cg[0], sizeof cg[0]);
  58. CHECK_EQUAL(2, nc);
  59. for (int i=0; i<nc; ++i) {
  60. CHECK_EQUAL(0, cg[i].depth);
  61. CHECK_ARRAY_EQUAL(trinormal, cg[i].normal, 3);
  62. }
  63. // now translate both geoms
  64. dGeomSetPosition(trimesh, 10,30,40);
  65. dGeomSetPosition(sphere, 10,30,40+radius);
  66. // check extreme case, again
  67. nc = dCollide(trimesh, sphere, 4, &cg[0], sizeof cg[0]);
  68. CHECK_EQUAL(2, nc);
  69. for (int i=0; i<nc; ++i) {
  70. CHECK_EQUAL(0, cg[i].depth);
  71. CHECK_ARRAY_EQUAL(trinormal, cg[i].normal, 3);
  72. }
  73. // and now, let's rotate the trimesh, 90 degrees on X
  74. dMatrix3 rot = { 1, 0, 0, 0,
  75. 0, 0, -1, 0,
  76. 0, 1, 0, 0 };
  77. dGeomSetPosition(trimesh, 10,30,40);
  78. dGeomSetRotation(trimesh, rot);
  79. dGeomSetPosition(sphere, 10,30-radius,40);
  80. // check extreme case, again
  81. nc = dCollide(trimesh, sphere, 4, &cg[0], sizeof cg[0]);
  82. CHECK_EQUAL(2, nc);
  83. dVector3 rtrinormal = { 0, 1, 0 };
  84. for (int i=0; i<nc; ++i) {
  85. CHECK_EQUAL(0, cg[i].depth);
  86. CHECK_ARRAY_EQUAL(rtrinormal, cg[i].normal, 3);
  87. }
  88. }
  89. }
  90. TEST(test_collision_heightfield_ray_fail)
  91. {
  92. /*
  93. * This test demonstrated a bug in the AABB handling of the
  94. * heightfield.
  95. */
  96. {
  97. // Create quick heightfield with dummy data
  98. dHeightfieldDataID heightfieldData = dGeomHeightfieldDataCreate();
  99. unsigned char dataBuffer[16+1] = "1234567890123456";
  100. dGeomHeightfieldDataBuildByte(heightfieldData, dataBuffer, 0, 4, 4, 4, 4, 1, 0, 0, 0);
  101. dGeomHeightfieldDataSetBounds(heightfieldData, '0', '9');
  102. dGeomID height = dCreateHeightfield(0, heightfieldData, 1);
  103. // Create ray outside bounds
  104. dGeomID ray = dCreateRay(0, 20);
  105. dGeomRaySet(ray, 5, 10, 1, 0, -1, 0);
  106. dContact contactBuf[10];
  107. // Make sure it does not crash!
  108. dCollide(ray, height, 10, &(contactBuf[0].geom), sizeof(dContact));
  109. dGeomDestroy(height);
  110. dGeomDestroy(ray);
  111. dGeomHeightfieldDataDestroy(heightfieldData);
  112. }
  113. }
  114. #include "../ode/demo/convex_prism.h"
  115. TEST(test_collision_ray_convex)
  116. {
  117. /*
  118. * Issue 55: ray vs convex collider does not consider the position of the convex geometry.
  119. */
  120. {
  121. dContact contact;
  122. // Create convex
  123. dGeomID convex = dCreateConvex(0,
  124. prism_planes,
  125. prism_planecount,
  126. prism_points,
  127. prism_pointcount,
  128. prism_polygons);
  129. dGeomSetPosition(convex,0,0,0);
  130. // Create ray
  131. dGeomID ray = dCreateRay(0, 20);
  132. dGeomRaySet(ray, 0, -10, 0, 0, 1, 0);
  133. int count = dCollide(ray, convex, 1, &contact.geom, sizeof(dContact));
  134. CHECK_EQUAL(1,count);
  135. CHECK_CLOSE(0.0,contact.geom.pos[0], dEpsilon);
  136. CHECK_CLOSE(-1.0,contact.geom.pos[1], dEpsilon);
  137. CHECK_CLOSE(0.0,contact.geom.pos[2], dEpsilon);
  138. CHECK_CLOSE(0.0, contact.geom.normal[0], dEpsilon);
  139. CHECK_CLOSE(-1.0, contact.geom.normal[1], dEpsilon);
  140. CHECK_CLOSE(0.0, contact.geom.normal[2], dEpsilon);
  141. CHECK_CLOSE(9.0, contact.geom.depth, dEpsilon);
  142. // Move Ray
  143. dGeomRaySet(ray, 5, -10, 0, 0, 1, 0);
  144. count = dCollide(ray, convex, 1, &contact.geom, sizeof(dContact));
  145. CHECK_EQUAL(1,count);
  146. CHECK_CLOSE(5.0, contact.geom.pos[0], dEpsilon);
  147. CHECK_CLOSE(-1.0, contact.geom.pos[1], dEpsilon);
  148. CHECK_CLOSE(0.0, contact.geom.pos[2], dEpsilon);
  149. CHECK_CLOSE(0.0, contact.geom.normal[0], dEpsilon);
  150. CHECK_CLOSE(-1.0, contact.geom.normal[1], dEpsilon);
  151. CHECK_CLOSE(0.0, contact.geom.normal[2], dEpsilon);
  152. CHECK_CLOSE(9.0, contact.geom.depth, dEpsilon);
  153. // Rotate Convex
  154. dMatrix3 rotate90z =
  155. {
  156. 0,-1,0,0,
  157. 1,0,0,0,
  158. 0,0,1,0
  159. };
  160. dGeomSetRotation(convex, rotate90z);
  161. count = dCollide(ray, convex, 1, &contact.geom, sizeof(dContact));
  162. CHECK_EQUAL(0,count);
  163. // Move Ray
  164. dGeomRaySet(ray, 10, 0, 0, -1, 0, 0);
  165. count = dCollide(ray, convex, 1, &contact.geom, sizeof(dContact));
  166. CHECK_EQUAL(1,count);
  167. CHECK_CLOSE(1.0, contact.geom.pos[0], dEpsilon);
  168. CHECK_CLOSE(0.0, contact.geom.pos[1], dEpsilon);
  169. CHECK_CLOSE(0.0, contact.geom.pos[2], dEpsilon);
  170. CHECK_CLOSE(1.0, contact.geom.normal[0], dEpsilon);
  171. CHECK_CLOSE(0.0, contact.geom.normal[1], dEpsilon);
  172. CHECK_CLOSE(0.0, contact.geom.normal[2], dEpsilon);
  173. CHECK_CLOSE(9.0,contact.geom.depth, dEpsilon);
  174. // Move Ray
  175. dGeomRaySet(ray, 10, 1000, 1000, -1, 0, 0);
  176. // Move Geom
  177. dGeomSetPosition(convex, 0, 1000, 1000);
  178. count = dCollide(ray, convex, 1, &contact.geom, sizeof(dContact));
  179. CHECK_EQUAL(1, count);
  180. CHECK_CLOSE(1.0, contact.geom.pos[0], dEpsilon);
  181. CHECK_CLOSE(1000.0, contact.geom.pos[1], dEpsilon);
  182. CHECK_CLOSE(1000.0, contact.geom.pos[2], dEpsilon);
  183. CHECK_CLOSE(1.0, contact.geom.normal[0], dEpsilon);
  184. CHECK_CLOSE(0.0, contact.geom.normal[1], dEpsilon);
  185. CHECK_CLOSE(0.0, contact.geom.normal[2], dEpsilon);
  186. CHECK_CLOSE(9.0, contact.geom.depth, dEpsilon);
  187. dGeomDestroy(convex);
  188. dGeomDestroy(ray);
  189. }
  190. }