TaperedCylinderShapeTests.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2024 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include "UnitTestFramework.h"
  5. #include "PhysicsTestContext.h"
  6. #include <Jolt/Physics/Collision/Shape/TaperedCylinderShape.h>
  7. #include <Jolt/Physics/Collision/CollisionCollectorImpl.h>
  8. #include <Jolt/Physics/Collision/CollidePointResult.h>
  9. TEST_SUITE("TaperedCylinderShapeTests")
  10. {
  11. TEST_CASE("TestMassAndInertia")
  12. {
  13. const float cDensity = 3.0f;
  14. const float cRadius = 5.0f;
  15. const float cHeight = 7.0f;
  16. TaperedCylinderShapeSettings settings1(0.5f * cHeight, cRadius, 0.0f, 0.0f);
  17. settings1.SetDensity(cDensity);
  18. TaperedCylinderShapeSettings settings2(0.5f * cHeight, 0.0f, cRadius, 0.0f);
  19. settings2.SetDensity(cDensity);
  20. RefConst<TaperedCylinderShape> cylinder1 = StaticCast<TaperedCylinderShape>(settings1.Create().Get());
  21. RefConst<TaperedCylinderShape> cylinder2 = StaticCast<TaperedCylinderShape>(settings2.Create().Get());
  22. // Check accessors
  23. CHECK(cylinder1->GetTopRadius() == cRadius);
  24. CHECK(cylinder1->GetBottomRadius() == 0.0f);
  25. CHECK(cylinder1->GetConvexRadius() == 0.0f);
  26. CHECK_APPROX_EQUAL(cylinder1->GetHalfHeight(), 0.5f * cHeight);
  27. MassProperties m1 = cylinder1->GetMassProperties();
  28. MassProperties m2 = cylinder2->GetMassProperties();
  29. // Mass/inertia is the same for both shapes because they are mirrored versions (inertia is calculated from COM)
  30. CHECK_APPROX_EQUAL(m1.mMass, m2.mMass);
  31. CHECK_APPROX_EQUAL(m1.mInertia, m2.mInertia);
  32. // Center of mass for a cone is at 1/4 h (if cone runs from -h/2 to h/2)
  33. // See: https://www.miniphysics.com/uy1-centre-of-mass-of-a-cone.html
  34. Vec3 expected_com1(0, cHeight / 4.0f, 0);
  35. Vec3 expected_com2 = -expected_com1;
  36. CHECK_APPROX_EQUAL(cylinder1->GetCenterOfMass(), expected_com1);
  37. CHECK_APPROX_EQUAL(cylinder2->GetCenterOfMass(), expected_com2);
  38. // Mass of cone
  39. float expected_mass = cDensity * JPH_PI * Square(cRadius) * cHeight / 3.0f;
  40. CHECK_APPROX_EQUAL(expected_mass, m1.mMass);
  41. // Inertia of cone (according to https://en.wikipedia.org/wiki/List_of_moments_of_inertia)
  42. float expected_inertia_xx = expected_mass * (3.0f / 20.0f * Square(cRadius) + 3.0f / 80.0f * Square(cHeight));
  43. float expected_inertia_yy = expected_mass * (3.0f / 10.0f * Square(cRadius));
  44. CHECK_APPROX_EQUAL(expected_inertia_xx, m1.mInertia(0, 0), 1.0e-3f);
  45. CHECK_APPROX_EQUAL(expected_inertia_yy, m1.mInertia(1, 1), 1.0e-3f);
  46. CHECK_APPROX_EQUAL(expected_inertia_xx, m1.mInertia(2, 2), 1.0e-3f);
  47. }
  48. TEST_CASE("TestCollidePoint")
  49. {
  50. const float cTopRadius = 3.0f;
  51. const float cBottomRadius = 5.0f;
  52. const float cHalfHeight = 3.5f;
  53. RefConst<Shape> shape = TaperedCylinderShapeSettings(cHalfHeight, cTopRadius, cBottomRadius).Create().Get();
  54. auto test_inside = [shape](Vec3Arg inPoint)
  55. {
  56. AllHitCollisionCollector<CollidePointCollector> collector;
  57. shape->CollidePoint(inPoint - shape->GetCenterOfMass(), SubShapeIDCreator(), collector);
  58. CHECK(collector.mHits.size() == 1);
  59. };
  60. auto test_outside = [shape](Vec3Arg inPoint)
  61. {
  62. AllHitCollisionCollector<CollidePointCollector> collector;
  63. shape->CollidePoint(inPoint - shape->GetCenterOfMass(), SubShapeIDCreator(), collector);
  64. CHECK(collector.mHits.size() == 0);
  65. };
  66. constexpr float cEpsilon = 1.0e-3f;
  67. test_inside(Vec3::sZero());
  68. // Top plane
  69. test_inside(Vec3(0, cHalfHeight - cEpsilon, 0));
  70. test_outside(Vec3(0, cHalfHeight + cEpsilon, 0));
  71. // Bottom plane
  72. test_inside(Vec3(0, -cHalfHeight + cEpsilon, 0));
  73. test_outside(Vec3(0, -cHalfHeight - cEpsilon, 0));
  74. // COM plane
  75. test_inside(Vec3(0.5f * (cTopRadius + cBottomRadius) - cEpsilon, 0, 0));
  76. test_outside(Vec3(0.5f * (cTopRadius + cBottomRadius) + cEpsilon, 0, 0));
  77. // At quarter h above COM plane
  78. float h = 0.5f * cHalfHeight;
  79. float r = cBottomRadius + (cTopRadius - cBottomRadius) * (h + cHalfHeight) / (2.0f * cHalfHeight);
  80. test_inside(Vec3(0, h, r - cEpsilon));
  81. test_outside(Vec3(0, h, r + cEpsilon));
  82. }
  83. }