// Extra collision tests: Simplex, MeshCollider, EPA #include #include #include #include #include using namespace omath; using namespace omath::collision; TEST(SimplexTest, HandleEmptySimplex) { Simplex> simplex; Vector3 direction{1, 0, 0}; EXPECT_EQ(simplex.size(), 0); EXPECT_FALSE(simplex.handle(direction)); } TEST(SimplexTest, HandleLineCollinearWithXAxis) { using Vec3 = Vector3; Simplex simplex; simplex.push_front(Vec3{1, 0, 0}); simplex.push_front(Vec3{-1, 0, 0}); Vec3 direction{}; std::ignore = simplex.handle(direction); EXPECT_NEAR(direction.x, 0.f, 1e-6f); } TEST(CollisionExtra, SimplexLineHandle) { Simplex> s; s = {Vector3{1.f, 0.f, 0.f}, Vector3{2.f, 0.f, 0.f}}; Vector3 dir{0, 0, 0}; EXPECT_FALSE(s.handle(dir)); // direction should not be zero EXPECT_GT(dir.length_sqr(), 0.0f); } TEST(CollisionExtra, SimplexTriangleHandle) { Simplex> s; s = {Vector3{1.f, 0.f, 0.f}, Vector3{0.f, 1.f, 0.f}, Vector3{0.f, 0.f, 1.f}}; Vector3 dir{0, 0, 0}; EXPECT_FALSE(s.handle(dir)); EXPECT_GT(dir.length_sqr(), 0.0f); } TEST(CollisionExtra, SimplexTetrahedronInside) { Simplex> s; // tetra that surrounds origin roughly s = {Vector3{1.f, 0.f, 0.f}, Vector3{0.f, 1.f, 0.f}, Vector3{0.f, 0.f, 1.f}, Vector3{-1.f, -1.f, -1.f}}; Vector3 dir{0, 0, 0}; // if origin inside, handle returns true const bool inside = s.handle(dir); EXPECT_TRUE(inside); } TEST(CollisionExtra, MeshColliderOriginAndFurthest) { source_engine::Mesh mesh = { std::vector>{{{1.f, 1.f, 1.f}, {}, {}}, {{-1.f, -1.f, -1.f}, {}, {}}}, {}}; mesh.set_origin({0, 2, 0}); source_engine::MeshCollider collider(mesh); EXPECT_EQ(collider.get_origin(), omath::Vector3(0, 2, 0)); collider.set_origin({1, 2, 3}); EXPECT_EQ(collider.get_origin(), omath::Vector3(1, 2, 3)); const auto v = collider.find_abs_furthest_vertex_position({1.f, 0.f, 0.f}); // the original vertex at (1,1,1) translated by origin (1,2,3) becomes (2,3,4) EXPECT_EQ(v, omath::Vector3(2.f, 3.f, 4.f)); } TEST(CollisionExtra, EPAConvergesOnSimpleCase) { // Build two simple colliders using simple meshes that overlap source_engine::Mesh meshA = { std::vector>{{{0.f, 0.f, 0.f}, {}, {}}, {{1.f, 0.f, 0.f}, {}, {}}}, {}}; source_engine::Mesh mesh_b = meshA; mesh_b.set_origin({0.5f, 0.f, 0.f}); // translate to overlap source_engine::MeshCollider a(meshA); source_engine::MeshCollider b(mesh_b); // Create a simplex that approximately contains the origin in Minkowski space Simplex> simplex; simplex = {omath::Vector3{0.5f, 0.f, 0.f}, omath::Vector3{-0.5f, 0.f, 0.f}, omath::Vector3{0.f, 0.5f, 0.f}, omath::Vector3{0.f, -0.5f, 0.f}}; auto pool = std::pmr::monotonic_buffer_resource(1024); auto res = Epa::solve(a, b, simplex, {}, pool); // EPA may or may not converge depending on numerics; ensure it returns optionally // but if it does, fields should be finite if (res.has_value()) { auto r = *res; EXPECT_TRUE(std::isfinite(r.depth)); EXPECT_GT(r.normal.length_sqr(), 0.0f); } }