collision.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. #include <UnitTest++.h>
  2. #include <ode/ode.h>
  3. TEST(test_collision_trimesh_sphere_exact)
  4. {
  5. /*
  6. * This tests some extreme cases, where a sphere barely touches some triangles
  7. * with zero depth.
  8. */
  9. #ifdef dTRIMESH_GIMPACT
  10. /*
  11. * Although GIMPACT is algorithmically able to handle this extreme case,
  12. * the numerical approximation used for the square root produces inexact results.
  13. */
  14. return;
  15. #endif
  16. {
  17. const int VertexCount = 4;
  18. const int IndexCount = 2*3;
  19. // this is a square on the XY plane
  20. /*
  21. 3 2
  22. +----+
  23. | /|
  24. | / |
  25. | / |
  26. |/ |
  27. +----+
  28. 0 1
  29. */
  30. float vertices[VertexCount * 3] = {
  31. -1,-1,0,
  32. 1,-1,0,
  33. 1,1,0,
  34. -1,1,0
  35. };
  36. dTriIndex indices[IndexCount] = {
  37. 0,1,2,
  38. 0,2,3
  39. };
  40. dTriMeshDataID data = dGeomTriMeshDataCreate();
  41. dGeomTriMeshDataBuildSingle(data,
  42. vertices,
  43. 3 * sizeof(float),
  44. VertexCount,
  45. indices,
  46. IndexCount,
  47. 3 * sizeof(dTriIndex));
  48. dGeomID trimesh = dCreateTriMesh(0, data, 0, 0, 0);
  49. const dReal radius = 4;
  50. dGeomID sphere = dCreateSphere(0, radius);
  51. dContactGeom cg[4];
  52. int nc;
  53. dVector3 trinormal = { 0, 0, -1 };
  54. // Test case: sphere touches the diagonal edge
  55. dGeomSetPosition(sphere, 0,0,radius);
  56. nc = dCollide(trimesh, sphere, 4, &cg[0], sizeof cg[0]);
  57. CHECK_EQUAL(2, nc);
  58. for (int i=0; i<nc; ++i) {
  59. CHECK_EQUAL(0, cg[i].depth);
  60. CHECK_ARRAY_EQUAL(trinormal, cg[i].normal, 3);
  61. }
  62. // now translate both geoms
  63. dGeomSetPosition(trimesh, 10,30,40);
  64. dGeomSetPosition(sphere, 10,30,40+radius);
  65. // check extreme case, again
  66. nc = dCollide(trimesh, sphere, 4, &cg[0], sizeof cg[0]);
  67. CHECK_EQUAL(2, nc);
  68. for (int i=0; i<nc; ++i) {
  69. CHECK_EQUAL(0, cg[i].depth);
  70. CHECK_ARRAY_EQUAL(trinormal, cg[i].normal, 3);
  71. }
  72. // and now, let's rotate the trimesh, 90 degrees on X
  73. dMatrix3 rot = { 1, 0, 0, 0,
  74. 0, 0, -1, 0,
  75. 0, 1, 0, 0 };
  76. dGeomSetPosition(trimesh, 10,30,40);
  77. dGeomSetRotation(trimesh, rot);
  78. dGeomSetPosition(sphere, 10,30-radius,40);
  79. // check extreme case, again
  80. nc = dCollide(trimesh, sphere, 4, &cg[0], sizeof cg[0]);
  81. CHECK_EQUAL(2, nc);
  82. dVector3 rtrinormal = { 0, 1, 0 };
  83. for (int i=0; i<nc; ++i) {
  84. CHECK_EQUAL(0, cg[i].depth);
  85. CHECK_ARRAY_EQUAL(rtrinormal, cg[i].normal, 3);
  86. }
  87. }
  88. }
  89. TEST(test_collision_heightfield_ray_fail)
  90. {
  91. /*
  92. * This test demonstrated a bug in the AABB handling of the
  93. * heightfield.
  94. */
  95. {
  96. // Create quick heightfield with dummy data
  97. dHeightfieldDataID heightfieldData = dGeomHeightfieldDataCreate();
  98. unsigned char dataBuffer[16+1] = "1234567890123456";
  99. dGeomHeightfieldDataBuildByte(heightfieldData, dataBuffer, 0, 4, 4, 4, 4, 1, 0, 0, 0);
  100. dGeomHeightfieldDataSetBounds(heightfieldData, '0', '9');
  101. dGeomID height = dCreateHeightfield(0, heightfieldData, 1);
  102. // Create ray outside bounds
  103. dGeomID ray = dCreateRay(0, 20);
  104. dGeomRaySet(ray, 5, 10, 1, 0, -1, 0);
  105. dContact contactBuf[10];
  106. // Make sure it does not crash!
  107. dCollide(ray, height, 10, &(contactBuf[0].geom), sizeof(dContact));
  108. dGeomDestroy(height);
  109. dGeomDestroy(ray);
  110. dGeomHeightfieldDataDestroy(heightfieldData);
  111. }
  112. }