Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions python/src/ipc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ void define_ipc(py::module_& m)

Note:
Assumes the trajectory is linear.
When using SweepAndTiniestQueue broad phase, tolerance and
max_iterations are extracted from TightInclusionCCD if provided,
otherwise defaults are used.

Parameters:
mesh: The collision mesh.
Expand Down
15 changes: 10 additions & 5 deletions src/ipc/ipc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <ipc/config.hpp>
#include <ipc/broad_phase/default_broad_phase.hpp>
#include <ipc/candidates/candidates.hpp>
#include <ipc/ccd/tight_inclusion_ccd.hpp>
#include <ipc/geometry/intersection.hpp>
#include <ipc/utils/world_bbox_diagonal_length.hpp>

Expand Down Expand Up @@ -61,11 +62,15 @@ double compute_collision_free_stepsize(
throw std::runtime_error(
"Sweep and Tiniest Queue is only supported in 3D!");
}
// TODO: Use correct min_distance
// TODO: Expose tolerance and max_iterations
constexpr double tolerance = TightInclusionCCD::DEFAULT_TOLERANCE;
constexpr long max_iterations =
TightInclusionCCD::DEFAULT_MAX_ITERATIONS;
// Extract tolerance and max_iterations from narrow_phase_ccd if it's
// TightInclusionCCD
double tolerance = TightInclusionCCD::DEFAULT_TOLERANCE;
long max_iterations = TightInclusionCCD::DEFAULT_MAX_ITERATIONS;
if (const TightInclusionCCD* ti_ccd =
dynamic_cast<const TightInclusionCCD*>(&narrow_phase_ccd)) {
tolerance = ti_ccd->tolerance;
max_iterations = ti_ccd->max_iterations;
}
const double step_size = scalable_ccd::cuda::ipc_ccd_strategy(
vertices_t0, vertices_t1, mesh.edges(), mesh.faces(),
/*min_distance=*/0.0, max_iterations, tolerance);
Expand Down
3 changes: 3 additions & 0 deletions src/ipc/ipc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ bool is_step_collision_free(

/// @brief Computes a maximal step size that is collision free.
/// @note Assumes the trajectory is linear.
/// @note When using SweepAndTiniestQueue broad phase, tolerance and
/// max_iterations are extracted from TightInclusionCCD if provided,
/// otherwise defaults are used.
/// @param mesh The collision mesh.
/// @param vertices_t0 Vertex vertices at start as rows of a matrix. Assumes vertices_t0 is intersection free.
/// @param vertices_t1 Surface vertex vertices at end as rows of a matrix.
Expand Down
98 changes: 98 additions & 0 deletions tests/src/tests/ccd/test_gpu_ccd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include <ipc/ipc.hpp>
#include <ipc/broad_phase/sweep_and_prune.hpp>
#include <ipc/broad_phase/sweep_and_tiniest_queue.hpp>
#include <ipc/ccd/tight_inclusion_ccd.hpp>
#include <ipc/ccd/additive_ccd.hpp>

using namespace ipc;

Expand Down Expand Up @@ -61,4 +63,100 @@ TEST_CASE("GPU CCD", "[ccd][gpu]")
CHECK(toi_gpu == Catch::Approx(3.05175781250000017e-6));
}

TEST_CASE("GPU CCD parameter extraction", "[ccd][gpu]")
{
Eigen::MatrixXd V0, V1;
Eigen::MatrixXi E, F;

if (!tests::load_mesh("cloth_ball92.ply", V0, E, F)
|| !tests::load_mesh("cloth_ball93.ply", V1, E, F)) {
SKIP("Cloth-ball meshes are not available");
}

CollisionMesh mesh = CollisionMesh::build_from_full_mesh(V0, E, F);
// Discard codimensional/internal vertices
V0 = mesh.vertices(V0);
V1 = mesh.vertices(V1);

const double min_distance = 0;
SweepAndTiniestQueue stq;

// Test 1: Custom TightInclusionCCD parameters should be extracted and used
SECTION("Custom TightInclusionCCD parameters")
{
// Different from default (1e-6)
const double custom_tolerance = 1e-5;
// Different from default (10M)
const long custom_max_iterations = 5'000'000L;

const double toi_custom = compute_collision_free_stepsize(
mesh, V0, V1, min_distance, &stq,
TightInclusionCCD(custom_tolerance, custom_max_iterations));

// Should produce a valid result (not crash)
CHECK(toi_custom >= 0.0);
CHECK(toi_custom <= 1.0);
}

// Test 2: Default TightInclusionCCD should use default parameters
SECTION("Default TightInclusionCCD")
{
const double toi_default = compute_collision_free_stepsize(
mesh, V0, V1, min_distance, &stq, TightInclusionCCD());

// Should produce a valid result
CHECK(toi_default >= 0.0);
CHECK(toi_default <= 1.0);
}

// Test 3: Non-TightInclusionCCD should fall back to defaults
SECTION("Non-TightInclusionCCD fallback to defaults")
{
const double toi_additive = compute_collision_free_stepsize(
mesh, V0, V1, min_distance, &stq, AdditiveCCD());

// Should produce a valid result (fallback to defaults should work)
CHECK(toi_additive >= 0.0);
CHECK(toi_additive <= 1.0);
}

// Test 4: Verify that different tolerance values can produce different
// results
SECTION("Different tolerance values")
{
// Use default tolerance explicitly - should match default constructor
const double toi_explicit_default = compute_collision_free_stepsize(
mesh, V0, V1, min_distance, &stq,
TightInclusionCCD(
TightInclusionCCD::DEFAULT_TOLERANCE,
TightInclusionCCD::DEFAULT_MAX_ITERATIONS));

const double toi_implicit_default = compute_collision_free_stepsize(
mesh, V0, V1, min_distance, &stq, TightInclusionCCD());

// Explicit default should match implicit default (verifies parameter
// extraction works)
CHECK(toi_explicit_default == Catch::Approx(toi_implicit_default));

// Use different tolerance - may produce different result
const double toi_loose = compute_collision_free_stepsize(
mesh, V0, V1, min_distance, &stq,
TightInclusionCCD(1e-4, TightInclusionCCD::DEFAULT_MAX_ITERATIONS));

// All should be valid
CHECK(toi_explicit_default >= 0.0);
CHECK(toi_explicit_default <= 1.0);
CHECK(toi_implicit_default >= 0.0);
CHECK(toi_implicit_default <= 1.0);
CHECK(toi_loose >= 0.0);
CHECK(toi_loose <= 1.0);

// Verify parameters are being used: different tolerance should
// potentially produce different results (though they may be the same
// if no collisions or if difference is within numerical precision)
// The key is that explicit default matches implicit default, proving
// parameter extraction works
}
}

#endif
Loading