Skip to content

Commit 75ef144

Browse files
authored
Add max_iterations to additive CCD (#145)
1 parent e0b947c commit 75ef144

File tree

6 files changed

+42
-22
lines changed

6 files changed

+42
-22
lines changed

python/src/ccd/additive_ccd.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@ void define_additive_ccd(py::module_& m)
99
{
1010
py::class_<AdditiveCCD, NarrowPhaseCCD>(m, "AdditiveCCD")
1111
.def(
12-
py::init<const double>(),
12+
py::init<const double, const double>(),
1313
R"ipc_Qu8mg5v7(
1414
Construct a new AdditiveCCD object.
1515
1616
Parameters:
1717
conservative_rescaling: The conservative rescaling of the time of impact.
1818
)ipc_Qu8mg5v7",
19+
py::arg("max_iterations") = AdditiveCCD::DEFAULT_MAX_ITERATIONS,
1920
py::arg("conservative_rescaling") =
2021
AdditiveCCD::DEFAULT_CONSERVATIVE_RESCALING)
2122
.def_readonly_static(

src/ipc/candidates/candidates.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -317,8 +317,8 @@ double Candidates::compute_cfl_stepsize(
317317
// If alpha_F < 0.5 * alpha_C, then we should do full CCD.
318318
if (alpha_F < 0.5 * alpha_C) {
319319
return ipc::compute_collision_free_stepsize(
320-
mesh, vertices_t0, vertices_t1, min_distance, //
321-
broad_phase_method, narrow_phase_ccd);
320+
mesh, vertices_t0, vertices_t1, min_distance, broad_phase_method,
321+
narrow_phase_ccd);
322322
}
323323
return std::min(alpha_C, alpha_F);
324324
}

src/ipc/ccd/additive_ccd.cpp

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// • return true if the initial distance is less than the minimum distance
1010
// • add an explicit tmax parameter rather than relying on the initial value of
1111
// toi
12+
// • add a maximum number of iterations to limit the computation time
1213
//
1314
// NOTE: These methods are provided for reference comparison with [Li et al.
1415
// 2021] and is not utilized by the high-level functionality. In compairson to
@@ -60,8 +61,10 @@ namespace {
6061
}
6162
} // namespace
6263

63-
AdditiveCCD::AdditiveCCD(const double _conservative_rescaling)
64-
: conservative_rescaling(_conservative_rescaling)
64+
AdditiveCCD::AdditiveCCD(
65+
const long _max_iterations, const double _conservative_rescaling)
66+
: max_iterations(_max_iterations)
67+
, conservative_rescaling(_conservative_rescaling)
6568
{
6669
}
6770

@@ -72,8 +75,7 @@ bool AdditiveCCD::additive_ccd(
7275
const double max_disp_mag,
7376
double& toi,
7477
const double min_distance,
75-
const double tmax,
76-
const double conservative_rescaling)
78+
const double tmax) const
7779
{
7880
assert(conservative_rescaling > 0 && conservative_rescaling <= 1);
7981

@@ -87,9 +89,14 @@ bool AdditiveCCD::additive_ccd(
8789
assert(d_func > 0);
8890
const double gap = // (d - ξ) = (d² - ξ²) / (d + ξ)
8991
(1 - conservative_rescaling) * d_func / (d + min_distance);
92+
if (gap < std::numeric_limits<double>::epsilon()) {
93+
logger().warn(
94+
"Small gap {:g} ≤ ε in Additive CCD can lead to missed collisions",
95+
gap);
96+
}
9097

9198
toi = 0;
92-
while (true) {
99+
for (long i = 0; max_iterations < 0 || i < max_iterations; ++i) {
93100
// tₗ = η ⋅ (d - ξ) / lₚ = η ⋅ (d² - ξ²) / (lₚ ⋅ (d + ξ))
94101
const double toi_lower_bound = conservative_rescaling * d_func
95102
/ ((d + min_distance) * max_disp_mag);
@@ -108,6 +115,12 @@ bool AdditiveCCD::additive_ccd(
108115
if (toi > tmax) {
109116
return false; // collision occurs after tmax
110117
}
118+
119+
if (max_iterations < 0 && i == DEFAULT_MAX_ITERATIONS) {
120+
logger().warn(
121+
"Slow convergence in Additive CCD. Perhaps the gap is too small (gap={:g})?",
122+
gap);
123+
}
111124
}
112125

113126
return true;
@@ -151,8 +164,7 @@ bool AdditiveCCD::point_point_ccd(
151164
const VectorMax12d dx = stack(dp0, dp1);
152165

153166
return additive_ccd(
154-
x, dx, distance_squared, max_disp_mag, toi, min_distance, tmax,
155-
conservative_rescaling);
167+
x, dx, distance_squared, max_disp_mag, toi, min_distance, tmax);
156168
}
157169

158170
bool AdditiveCCD::point_edge_ccd(
@@ -199,8 +211,7 @@ bool AdditiveCCD::point_edge_ccd(
199211
const VectorMax12d dx = stack(dp, de0, de1);
200212

201213
return additive_ccd(
202-
x, dx, distance_squared, max_disp_mag, toi, min_distance, tmax,
203-
conservative_rescaling);
214+
x, dx, distance_squared, max_disp_mag, toi, min_distance, tmax);
204215
}
205216

206217
bool AdditiveCCD::point_triangle_ccd(
@@ -248,8 +259,7 @@ bool AdditiveCCD::point_triangle_ccd(
248259
const VectorMax12d dx = stack(dp, dt0, dt1, dt2);
249260

250261
return additive_ccd(
251-
x, dx, distance_squared, max_disp_mag, toi, min_distance, tmax,
252-
conservative_rescaling);
262+
x, dx, distance_squared, max_disp_mag, toi, min_distance, tmax);
253263
}
254264

255265
bool AdditiveCCD::edge_edge_ccd(
@@ -310,8 +320,7 @@ bool AdditiveCCD::edge_edge_ccd(
310320
const VectorMax12d dx = stack(dea0, dea1, deb0, deb1);
311321

312322
return additive_ccd(
313-
x, dx, distance_squared, max_disp_mag, toi, min_distance, tmax,
314-
conservative_rescaling);
323+
x, dx, distance_squared, max_disp_mag, toi, min_distance, tmax);
315324
}
316325

317326
} // namespace ipc

src/ipc/ccd/additive_ccd.hpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,18 @@ namespace ipc {
1717
/// @brief Additive Continuous Collision Detection (CCD) from [Li et al. 2021].
1818
class AdditiveCCD : public NarrowPhaseCCD {
1919
public:
20+
/// The default maximum number of iterations used with Tight-Inclusion CCD.
21+
static constexpr long DEFAULT_MAX_ITERATIONS = 10'000'000l;
22+
/// Unlimitted number of iterations.
23+
static constexpr long UNLIMITTED_ITERATIONS = -1;
2024
/// The default conservative rescaling value used to avoid taking steps
2125
/// exactly to impact. Value choosen to based on [Li et al. 2021].
2226
static constexpr double DEFAULT_CONSERVATIVE_RESCALING = 0.9;
2327

2428
/// @brief Construct a new AdditiveCCD object.
2529
/// @param conservative_rescaling The conservative rescaling of the time of impact.
2630
AdditiveCCD(
31+
const long max_iterations = UNLIMITTED_ITERATIONS,
2732
const double conservative_rescaling = DEFAULT_CONSERVATIVE_RESCALING);
2833

2934
/// @brief Computes the time of impact between two points using continuous collision detection.
@@ -122,6 +127,9 @@ class AdditiveCCD : public NarrowPhaseCCD {
122127
const double min_distance = 0.0,
123128
const double tmax = 1.0) const override;
124129

130+
/// @brief Maximum number of iterations.
131+
long max_iterations;
132+
125133
/// @brief The conservative rescaling value used to avoid taking steps exactly to impact.
126134
double conservative_rescaling;
127135

@@ -133,15 +141,14 @@ class AdditiveCCD : public NarrowPhaseCCD {
133141
/// @param tmax The maximum time to check for collisions.
134142
/// @param conservative_rescaling The amount to rescale the objects by to ensure conservative advancement.
135143
/// @return True if a collision was detected, false otherwise.
136-
static bool additive_ccd(
144+
bool additive_ccd(
137145
VectorMax12d x,
138146
const VectorMax12d& dx,
139147
const std::function<double(const VectorMax12d&)>& distance_squared,
140148
const double max_disp_mag,
141149
double& toi,
142150
const double min_distance = 0.0,
143-
const double tmax = 1.0,
144-
const double conservative_rescaling = DEFAULT_CONSERVATIVE_RESCALING);
151+
const double tmax = 1.0) const;
145152
};
146153

147154
} // namespace ipc

tests/src/tests/ccd/test_point_edge_ccd.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ void check_toi(
2929
CHECK(is_colliding);
3030
CHECK(toi <= toi_expected);
3131

32-
const AdditiveCCD additive_ccd(/*conservative_rescaling=*/0.99);
32+
const AdditiveCCD additive_ccd(
33+
AdditiveCCD::UNLIMITTED_ITERATIONS, /*conservative_rescaling=*/0.99);
3334
is_colliding = additive_ccd.point_edge_ccd(
3435
p_t0, e0_t0, e1_t0, p_t1, e0_t1, e1_t1, toi);
3536
CHECK(is_colliding);
@@ -170,7 +171,8 @@ TEST_CASE("Point-edge CCD", "[ccd][point-edge]")
170171
// CHECK(toi <= toi_expected);
171172
// }
172173

173-
const AdditiveCCD additive_ccd(/*conservative_rescaling=*/0.99);
174+
const AdditiveCCD additive_ccd(
175+
AdditiveCCD::DEFAULT_MAX_ITERATIONS, /*conservative_rescaling=*/0.99);
174176
is_colliding = additive_ccd.point_edge_ccd(
175177
p_t0, e0_t0, e1_t0, p_t1, e0_t1, e1_t1, toi);
176178
REQUIRE(is_colliding == is_collision_expected);

tests/src/tests/ccd/test_point_point_ccd.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ TEST_CASE("Point-point CCD", "[ccd][point-point]")
2828
CHECK(is_colliding);
2929
CHECK(toi == Catch::Approx(0.5).margin(1e-3));
3030

31-
const AdditiveCCD additive_ccd(/*conservative_rescaling=*/0.999);
31+
const AdditiveCCD additive_ccd(
32+
AdditiveCCD::UNLIMITTED_ITERATIONS, /*conservative_rescaling=*/0.999);
3233
is_colliding = additive_ccd.point_point_ccd(
3334
p0_t0, p1_t0, p0_t1, p1_t1, toi, min_distance);
3435

0 commit comments

Comments
 (0)