From 918b54d5c8f7b87990d60c69a1847e836d07f7d2 Mon Sep 17 00:00:00 2001 From: Zachary Ferguson Date: Sat, 28 Feb 2026 19:34:56 -0500 Subject: [PATCH 1/3] Refactor Nonlinear CCD Implementation and Update Tests - Introduced a new NonlinearCCD class to encapsulate nonlinear continuous collision detection (CCD) methods. - Updated point-point, point-edge, edge-edge, and point-triangle CCD methods to use the new class structure. - Modified the test cases to utilize the new NonlinearCCD class, ensuring consistency in the testing approach. - Enhanced readability by applying consistent formatting and style changes across the CCD methods. - Updated function signatures to accept Eigen::ConstRef types for better performance and clarity. - Adjusted the conservative rescaling parameter handling in the CCD methods for improved accuracy. - Removed deprecated function signatures and ensured all tests reflect the new method signatures. --- docs/source/tutorials/nonlinear_ccd.rst | 6 +- python/src/ccd/nonlinear_ccd.cpp | 325 +++++++++----------- python/tests/test_ccd.py | 78 +++-- src/ipc/ccd/nonlinear_ccd.cpp | 70 ++--- src/ipc/ccd/nonlinear_ccd.hpp | 237 +++++++------- tests/src/tests/ccd/test_nonlinear_ccd.cpp | 60 ++-- tests/src/tests/ccd/test_point_edge_ccd.cpp | 12 +- tests/src/tests/test_has_intersections.cpp | 4 +- tests/src/tests/utils.hpp | 4 +- 9 files changed, 398 insertions(+), 398 deletions(-) diff --git a/docs/source/tutorials/nonlinear_ccd.rst b/docs/source/tutorials/nonlinear_ccd.rst index 4cbd0e504..347b4a7e6 100644 --- a/docs/source/tutorials/nonlinear_ccd.rst +++ b/docs/source/tutorials/nonlinear_ccd.rst @@ -199,13 +199,13 @@ The following code snippet shows an example of how to use interval arithmetic to .. code-block:: cpp - #include + #include using namespace ipc; Vector2I position( - const VectorMax3d& center, - const VectorMax3d& point, + Eigen::ConstRef center, + Eigen::ConstRef point, const double omega, const Interval& t) { diff --git a/python/src/ccd/nonlinear_ccd.cpp b/python/src/ccd/nonlinear_ccd.cpp index 2f836da10..ede9fa782 100644 --- a/python/src/ccd/nonlinear_ccd.cpp +++ b/python/src/ccd/nonlinear_ccd.cpp @@ -77,185 +77,162 @@ void define_nonlinear_ccd(py::module_& m) "t0"_a, "t1"_a); #endif - m.def( - "point_point_nonlinear_ccd", - [](const NonlinearTrajectory& p0, const NonlinearTrajectory& p1, - const double tmax, const double min_distance, const double tolerance, - const long max_iterations, const double conservative_rescaling) { - double toi; - bool r = point_point_nonlinear_ccd( - p0, p1, toi, tmax, min_distance, tolerance, max_iterations, - conservative_rescaling); - return std::make_tuple(r, toi); - }, - R"ipc_Qu8mg5v7( - Perform nonlinear CCD between two points moving along nonlinear trajectories. - - Parameters: - p0: First point's trajectory - p1: Second point's trajectory - tmax: Maximum time to check for collision - min_distance: Minimum separation distance between the two points - tolerance: Tolerance for the linear CCD algorithm - max_iterations: Maximum number of iterations for the linear CCD algorithm - conservative_rescaling: Conservative rescaling of the time of impact - - Returns: - Tuple of: - True if the two points collide, false otherwise. - Output time of impact - )ipc_Qu8mg5v7", - "p0"_a, "p1"_a, "tmax"_a = 1.0, "min_distance"_a = 0, - "tolerance"_a = TightInclusionCCD::DEFAULT_TOLERANCE, - "max_iterations"_a = TightInclusionCCD::DEFAULT_MAX_ITERATIONS, - "conservative_rescaling"_a = - TightInclusionCCD::DEFAULT_CONSERVATIVE_RESCALING); - - m.def( - "point_edge_nonlinear_ccd", - [](const NonlinearTrajectory& p, const NonlinearTrajectory& e0, - const NonlinearTrajectory& e1, const double tmax, - const double min_distance, const double tolerance, - const long max_iterations, const double conservative_rescaling) { - double toi; - bool r = point_edge_nonlinear_ccd( - p, e0, e1, toi, tmax, min_distance, tolerance, max_iterations, - conservative_rescaling); - return std::make_tuple(r, toi); - }, - R"ipc_Qu8mg5v7( - Perform nonlinear CCD between a point and a linear edge moving along nonlinear trajectories. - - Parameters: - p: Point's trajectory - e0: Edge's first endpoint's trajectory - e1: Edge's second endpoint's trajectory - tmax: Maximum time to check for collision - min_distance: Minimum separation distance between the point and the edge - tolerance: Tolerance for the linear CCD algorithm - max_iterations: Maximum number of iterations for the linear CCD algorithm - conservative_rescaling: Conservative rescaling of the time of impact - - Returns: - Tuple of: - True if the point and edge collide, false otherwise. - Output time of impact - )ipc_Qu8mg5v7", - "p"_a, "e0"_a, "e1"_a, "tmax"_a = 1.0, "min_distance"_a = 0, - "tolerance"_a = TightInclusionCCD::DEFAULT_TOLERANCE, - "max_iterations"_a = TightInclusionCCD::DEFAULT_MAX_ITERATIONS, - "conservative_rescaling"_a = - TightInclusionCCD::DEFAULT_CONSERVATIVE_RESCALING); - - m.def( - "edge_edge_nonlinear_ccd", - [](const NonlinearTrajectory& ea0, const NonlinearTrajectory& ea1, - const NonlinearTrajectory& eb0, const NonlinearTrajectory& eb1, - const double tmax, const double min_distance, const double tolerance, - const long max_iterations, const double conservative_rescaling) { - double toi; - bool r = edge_edge_nonlinear_ccd( - ea0, ea1, eb0, eb1, toi, tmax, min_distance, tolerance, - max_iterations, conservative_rescaling); - return std::make_tuple(r, toi); - }, - R"ipc_Qu8mg5v7( - Perform nonlinear CCD between two linear edges moving along nonlinear trajectories. - - Parameters: - ea0: First edge's first endpoint's trajectory - ea1: First edge's second endpoint's trajectory - eb0: Second edge's first endpoint's trajectory - eb1: Second edge's second endpoint's trajectory - tmax: Maximum time to check for collision - min_distance: Minimum separation distance between the two edges - tolerance: Tolerance for the linear CCD algorithm - max_iterations: Maximum number of iterations for the linear CCD algorithm - conservative_rescaling: Conservative rescaling of the time of impact - - Returns: - Tuple of: - True if the two edges collide, false otherwise. - Output time of impact - )ipc_Qu8mg5v7", - "ea0"_a, "ea1"_a, "eb0"_a, "eb1"_a, "tmax"_a = 1.0, - "min_distance"_a = 0, - "tolerance"_a = TightInclusionCCD::DEFAULT_TOLERANCE, - "max_iterations"_a = TightInclusionCCD::DEFAULT_MAX_ITERATIONS, - "conservative_rescaling"_a = - TightInclusionCCD::DEFAULT_CONSERVATIVE_RESCALING); + py::class_(m, "NonlinearCCD") + .def( + py::init(), + "tolerance"_a = NonlinearCCD::DEFAULT_TOLERANCE, + "max_iterations"_a = NonlinearCCD::DEFAULT_MAX_ITERATIONS, + "conservative_rescaling"_a = + NonlinearCCD::DEFAULT_CONSERVATIVE_RESCALING) + .def_readwrite( + "tolerance", &NonlinearCCD::tolerance, "Solver tolerance.") + .def_readwrite( + "max_iterations", &NonlinearCCD::max_iterations, + "Maximum number of iterations.") + .def_readwrite( + "conservative_rescaling", &NonlinearCCD::conservative_rescaling, + "Conservative rescaling of the time of impact.") + .def( + "point_point_ccd", + [](const NonlinearCCD& self, const NonlinearTrajectory& p0, + const NonlinearTrajectory& p1, const double min_distance, + const double tmax) { + double toi; + bool r = self.point_point_ccd(p0, p1, toi, min_distance, tmax); + return std::make_tuple(r, toi); + }, + R"ipc_Qu8mg5v7( + Perform nonlinear CCD between two points moving along nonlinear trajectories. - m.def( - "point_triangle_nonlinear_ccd", - [](const NonlinearTrajectory& p, const NonlinearTrajectory& t0, - const NonlinearTrajectory& t1, const NonlinearTrajectory& t2, - const double tmax, const double min_distance, const double tolerance, - const long max_iterations, const double conservative_rescaling) { - double toi; - bool r = point_triangle_nonlinear_ccd( - p, t0, t1, t2, toi, tmax, min_distance, tolerance, - max_iterations, conservative_rescaling); - return std::make_tuple(r, toi); - }, - R"ipc_Qu8mg5v7( - Perform nonlinear CCD between a point and a linear triangle moving along nonlinear trajectories. + Parameters: + p0: First point's trajectory + p1: Second point's trajectory + tmax: Maximum time to check for collision + min_distance: Minimum separation distance between the two points + + Returns: + Tuple of: + True if the two points collide, false otherwise. + Output time of impact + )ipc_Qu8mg5v7", + "p0"_a, "p1"_a, "min_distance"_a = 0, "tmax"_a = 1.0) + .def( + "point_edge_ccd", + [](const NonlinearCCD& self, const NonlinearTrajectory& p, + const NonlinearTrajectory& e0, const NonlinearTrajectory& e1, + const double min_distance, const double tmax) { + double toi; + bool r = + self.point_edge_ccd(p, e0, e1, toi, min_distance, tmax); + return std::make_tuple(r, toi); + }, + R"ipc_Qu8mg5v7( + Perform nonlinear CCD between a point and a linear edge moving along nonlinear trajectories. - Parameters: - p: Point's trajectory - t0: Triangle's first vertex's trajectory - t1: Triangle's second vertex's trajectory - t2: Triangle's third vertex's trajectory - tmax: Maximum time to check for collision - min_distance: Minimum separation distance between the two edges - tolerance: Tolerance for the linear CCD algorithm - max_iterations: Maximum number of iterations for the linear CCD algorithm - conservative_rescaling: Conservative rescaling of the time of impact + Parameters: + p: Point's trajectory + e0: Edge's first endpoint's trajectory + e1: Edge's second endpoint's trajectory + min_distance: Minimum separation distance between the point and the edge + tmax: Maximum time to check for collision + + Returns: + Tuple of: + True if the point and edge collide, false otherwise. + Output time of impact + )ipc_Qu8mg5v7", + "p"_a, "e0"_a, "e1"_a, "min_distance"_a = 0, "tmax"_a = 1.0) + .def( + "edge_edge_ccd", + [](const NonlinearCCD& self, const NonlinearTrajectory& ea0, + const NonlinearTrajectory& ea1, const NonlinearTrajectory& eb0, + const NonlinearTrajectory& eb1, const double min_distance, + const double tmax) { + double toi; + bool r = self.edge_edge_ccd( + ea0, ea1, eb0, eb1, toi, min_distance, tmax); + return std::make_tuple(r, toi); + }, + R"ipc_Qu8mg5v7( + Perform nonlinear CCD between two linear edges moving along nonlinear trajectories. - Returns: - Tuple of: - True if the point and triangle collide, false otherwise. - Output time of impact - )ipc_Qu8mg5v7", - "p"_a, "t0"_a, "t1"_a, "t2"_a, "tmax"_a = 1.0, "min_distance"_a = 0, - "tolerance"_a = TightInclusionCCD::DEFAULT_TOLERANCE, - "max_iterations"_a = TightInclusionCCD::DEFAULT_MAX_ITERATIONS, - "conservative_rescaling"_a = - TightInclusionCCD::DEFAULT_CONSERVATIVE_RESCALING); + Parameters: + ea0: First edge's first endpoint's trajectory + ea1: First edge's second endpoint's trajectory + eb0: Second edge's first endpoint's trajectory + eb1: Second edge's second endpoint's trajectory + min_distance: Minimum separation distance between the two edges + tmax: Maximum time to check for collision + + Returns: + Tuple of: + True if the two edges collide, false otherwise. + Output time of impact + )ipc_Qu8mg5v7", + "ea0"_a, "ea1"_a, "eb0"_a, "eb1"_a, "tmax"_a = 1.0, + "min_distance"_a = 0) + .def( + "point_triangle_ccd", + [](const NonlinearCCD& self, const NonlinearTrajectory& p, + const NonlinearTrajectory& t0, const NonlinearTrajectory& t1, + const NonlinearTrajectory& t2, const double min_distance, + const double tmax) { + double toi; + bool r = self.point_triangle_ccd( + p, t0, t1, t2, toi, min_distance, tmax); + return std::make_tuple(r, toi); + }, + R"ipc_Qu8mg5v7( + Perform nonlinear CCD between a point and a linear triangle moving along nonlinear trajectories. - m.def( - "conservative_piecewise_linear_ccd", - [](const std::function& distance, - const std::function& - max_distance_from_linear, - const std::function& - linear_ccd, - const double tmax, const double min_distance, - const double conservative_rescaling) { - double toi; - bool r = conservative_piecewise_linear_ccd( - distance, max_distance_from_linear, linear_ccd, toi, tmax, - min_distance, conservative_rescaling); - return std::make_tuple(r, toi); - }, - R"ipc_Qu8mg5v7( - Perform conservative piecewise linear CCD of a nonlinear trajectories. + Parameters: + p: Point's trajectory + t0: Triangle's first vertex's trajectory + t1: Triangle's second vertex's trajectory + t2: Triangle's third vertex's trajectory + min_distance: Minimum separation distance between the two edges + tmax: Maximum time to check for collision + + Returns: + Tuple of: + True if the point and triangle collide, false otherwise. + Output time of impact + )ipc_Qu8mg5v7", + "p"_a, "t0"_a, "t1"_a, "t2"_a, "min_distance"_a = 0, "tmax"_a = 1.0) + .def_static( + "conservative_piecewise_linear_ccd", + [](const std::function& distance, + const std::function& + max_distance_from_linear, + const std::function& linear_ccd, + const double min_distance, const double tmax, + const double conservative_rescaling) { + double toi; + bool r = NonlinearCCD::conservative_piecewise_linear_ccd( + distance, max_distance_from_linear, linear_ccd, toi, + min_distance, tmax, conservative_rescaling); + return std::make_tuple(r, toi); + }, + R"ipc_Qu8mg5v7( + Perform conservative piecewise linear CCD of a nonlinear trajectories. - Parameters: - distance: Return the distance for a given time in [0, 1]. - max_distance_from_linear: Return the maximum distance from the linearized trajectory for a given time interval. - linear_ccd: Perform linear CCD on a given time interval. - tmax: Maximum time to check for collision. - min_distance: Minimum separation distance between the objects. - conservative_rescaling: Conservative rescaling of the time of impact. + Parameters: + distance: Return the distance for a given time in [0, 1]. + max_distance_from_linear: Return the maximum distance from the linearized trajectory for a given time interval. + linear_ccd: Perform linear CCD on a given time interval. + tmax: Maximum time to check for collision. + min_distance: Minimum separation distance between the objects. + conservative_rescaling: Conservative rescaling of the time of impact. - Returns: - Tuple of: + Returns: + Tuple of: - Output time of impact. - )ipc_Qu8mg5v7", - "distance"_a, "max_distance_from_linear"_a, "linear_ccd"_a, - "tmax"_a = 1.0, "min_distance"_a = 0, - "conservative_rescaling"_a = - TightInclusionCCD::DEFAULT_CONSERVATIVE_RESCALING); + Output time of impact. + )ipc_Qu8mg5v7", + "distance"_a, "max_distance_from_linear"_a, "linear_ccd"_a, + "min_distance"_a = 0, "tmax"_a = 1.0, + "conservative_rescaling"_a = + TightInclusionCCD::DEFAULT_CONSERVATIVE_RESCALING); } diff --git a/python/tests/test_ccd.py b/python/tests/test_ccd.py index a09eee98b..19c500055 100644 --- a/python/tests/test_ccd.py +++ b/python/tests/test_ccd.py @@ -1,8 +1,6 @@ import numpy as np - from find_ipctk import ipctk from ipctk.filib import Interval - from utils import load_mesh @@ -28,16 +26,44 @@ class DumbNarrowPhaseCCD(ipctk.NarrowPhaseCCD): def __init__(self): ipctk.NarrowPhaseCCD.__init__(self) - def point_point_ccd(self, p0_t0, p1_t0, p0_t1, p1_t1, min_distance=0.0, tmax=1.0): + def point_point_ccd( + self, p0_t0, p1_t0, p0_t1, p1_t1, min_distance=0.0, tmax=1.0 + ): return True, 0.0 - def point_edge_ccd(self, p_t0, e0_t0, e1_t0, p_t1, e0_t1, e1_t1, min_distance=0.0, tmax=1.0): + def point_edge_ccd( + self, p_t0, e0_t0, e1_t0, p_t1, e0_t1, e1_t1, min_distance=0.0, tmax=1.0 + ): return True, 0.0 - def point_triangle_ccd(self, p_t0, t0_t0, t1_t0, t2_t0, p_t1, t0_t1, t1_t1, t2_t1, min_distance=0.0, tmax=1.0): + def point_triangle_ccd( + self, + p_t0, + t0_t0, + t1_t0, + t2_t0, + p_t1, + t0_t1, + t1_t1, + t2_t1, + min_distance=0.0, + tmax=1.0, + ): return True, 0.0 - def edge_edge_ccd(self, ea0_t0, ea1_t0, eb0_t0, eb1_t0, ea0_t1, ea1_t1, eb0_t1, eb1_t1, min_distance=0.0, tmax=1.0): + def edge_edge_ccd( + self, + ea0_t0, + ea1_t0, + eb0_t0, + eb1_t0, + ea0_t1, + ea1_t1, + eb0_t1, + eb1_t1, + min_distance=0.0, + tmax=1.0, + ): return True, 0.0 V0, E, F = load_mesh("two-cubes-close.ply") @@ -48,10 +74,12 @@ def edge_edge_ccd(self, ea0_t0, ea1_t0, eb0_t0, eb1_t0, ea0_t1, ea1_t1, eb0_t1, ipctk.set_num_threads(1) assert not ipctk.is_step_collision_free( - mesh, V0, V1, narrow_phase_ccd=DumbNarrowPhaseCCD()) + mesh, V0, V1, narrow_phase_ccd=DumbNarrowPhaseCCD() + ) toi = ipctk.compute_collision_free_stepsize( - mesh, V0, V1, narrow_phase_ccd=DumbNarrowPhaseCCD()) + mesh, V0, V1, narrow_phase_ccd=DumbNarrowPhaseCCD() + ) assert 0 <= toi <= 1 @@ -90,8 +118,7 @@ def detect_face_face_candidates(self): assert ipctk.is_step_collision_free(mesh, V0, V1, broad_phase=broad_phase) - toi = ipctk.compute_collision_free_stepsize( - mesh, V0, V1, broad_phase=broad_phase) + toi = ipctk.compute_collision_free_stepsize(mesh, V0, V1, broad_phase=broad_phase) assert toi == 1 assert not ipctk.has_intersections(mesh, V0, broad_phase=broad_phase) @@ -124,7 +151,9 @@ def max_distance_from_linear(self, t0: float, t1: float): assert p0.max_distance_from_linear(0, 1) == 0 assert p1.max_distance_from_linear(0, 1) == 0 - is_colliding, toi = ipctk.point_point_nonlinear_ccd(p0, p1) + ccd = ipctk.NonlinearCCD() + + is_colliding, toi = ccd.point_point_ccd(p0, p1) assert is_colliding assert 0 < toi < 1 @@ -145,7 +174,7 @@ def max_distance_from_linear(self, t0: float, t1: float): # p0 = IntervalLinearTrajectory(np.array([-1, 0, 0]), np.array([1, 0, 0])) # p1 = IntervalLinearTrajectory(np.array([0, -1, 0]), np.array([0, 1, 0])) - # is_colliding, toi = ipctk.point_point_nonlinear_ccd(p0, p1) + # is_colliding, toi = ccd.point_point_ccd(p0, p1) # assert is_colliding # assert 0 < toi < 1 @@ -153,7 +182,9 @@ def max_distance_from_linear(self, t0: float, t1: float): # BEGIN_RIGID_2D_TRAJECTORY class Rigid2DTrajectory(ipctk.NonlinearTrajectory): - def __init__(self, position, translation, delta_translation, rotation, delta_rotation): + def __init__( + self, position, translation, delta_translation, rotation, delta_rotation + ): ipctk.NonlinearTrajectory.__init__(self) self.position = position self.translation = translation @@ -164,9 +195,11 @@ def __init__(self, position, translation, delta_translation, rotation, delta_rot # BEGIN_RIGID_2D_CALL def __call__(self, t): theta = self.rotation + t * self.delta_rotation - R = np.array([[np.cos(theta), -np.sin(theta)], - [np.sin(theta), np.cos(theta)]]) + R = np.array( + [[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]] + ) return R @ self.position + self.translation + t * self.delta_translation + # END_RIGID_2D_CALL # BEGIN_RIGID_2D_MAX_DISTANCE_FROM_LINEAR @@ -177,20 +210,19 @@ def max_distance_from_linear(self, t0, t1): p_t0 = self(t0) p_t1 = self(t1) return np.linalg.norm(self((t0 + t1) / 2) - ((p_t1 - p_t0) * 0.5 + p_t0)) + # END_RIGID_2D_MAX_DISTANCE_FROM_LINEAR + # END_RIGID_2D_TRAJECTORY # BEGIN_TEST_RIGID_2D_TRAJECTORY - p = Rigid2DTrajectory( - np.array([0, 0.5]), np.zeros(2), np.zeros(2), 0, 0) - e0 = Rigid2DTrajectory( - np.array([-1, 0]), np.zeros(2), np.zeros(2), 0, np.pi) - e1 = Rigid2DTrajectory( - np.array([1, 0]), np.zeros(2), np.zeros(2), 0, np.pi) + p = Rigid2DTrajectory(np.array([0, 0.5]), np.zeros(2), np.zeros(2), 0, 0) + e0 = Rigid2DTrajectory(np.array([-1, 0]), np.zeros(2), np.zeros(2), 0, np.pi) + e1 = Rigid2DTrajectory(np.array([1, 0]), np.zeros(2), np.zeros(2), 0, np.pi) # increase the conservative_rescaling from 0.8 to 0.9 to get a more accurate estimate - collision, toi = ipctk.point_edge_nonlinear_ccd( - p, e0, e1, conservative_rescaling=0.9) + ccd.conservative_rescaling = 0.9 + collision, toi = ccd.point_edge_ccd(p, e0, e1) assert collision assert 0.49 <= toi <= 0.5 # conservative estimate diff --git a/src/ipc/ccd/nonlinear_ccd.cpp b/src/ipc/ccd/nonlinear_ccd.cpp index d7862355a..23246e668 100644 --- a/src/ipc/ccd/nonlinear_ccd.cpp +++ b/src/ipc/ccd/nonlinear_ccd.cpp @@ -51,7 +51,17 @@ double IntervalNonlinearTrajectory::max_distance_from_linear( // ============================================================================ -bool conservative_piecewise_linear_ccd( +NonlinearCCD::NonlinearCCD( + const double _tolerance, + const long _max_iterations, + const double _conservative_rescaling) + : tolerance(_tolerance) + , max_iterations(_max_iterations) + , conservative_rescaling(_conservative_rescaling) +{ +} + +bool NonlinearCCD::conservative_piecewise_linear_ccd( const std::function& distance, const std::function& max_distance_from_linear, @@ -62,15 +72,15 @@ bool conservative_piecewise_linear_ccd( const bool /*no_zero_toi*/, double& /*toi*/)>& linear_ccd, double& toi, + const double min_distance, const double tmax, - const double min_sep_distance, const double conservative_rescaling) { const double distance_t0 = distance(0); - if (check_initial_distance(distance_t0, min_sep_distance, toi)) { + if (check_initial_distance(distance_t0, min_distance, toi)) { return true; } - assert(distance_t0 > min_sep_distance); + assert(distance_t0 > min_distance); double ti0 = 0; std::stack ts; @@ -102,38 +112,38 @@ bool conservative_piecewise_linear_ccd( return true; } - double min_distance = max_distance_from_linear(ti0, ti1); + double min_distance_linear = max_distance_from_linear(ti0, ti1); #ifndef USE_FIXED_PIECES // Check if the minimum distance is too large and we need to subdivide // (Large distances cause the slow CCD) - if ((min_distance + if ((min_distance_linear >= std::min((1 - conservative_rescaling) * distance_ti0, 0.01)) && (num_subdivisions < MAX_NUM_SUBDIVISIONS || ti0 == 0)) { logger().trace( "Subdividing at ti=[{:g}, {:g}] min_distance={:g} distance_ti0={:g}", - ti0, ti1, min_distance, distance_ti0); + ti0, ti1, min_distance_linear, distance_ti0); ts.push((ti1 + ti0) / 2); num_subdivisions++; continue; } #endif - min_distance += min_sep_distance; + min_distance_linear += min_distance; - const bool is_impacting = - linear_ccd(ti0, ti1, min_distance, /*no_zero_toi=*/ti0 == 0, toi); + const bool is_impacting = linear_ccd( + ti0, ti1, min_distance_linear, /*no_zero_toi=*/ti0 == 0, toi); logger().trace( "Evaluated at ti=[{:g}, {:g}] min_distance={:g} distance_ti0={:g}; result={}{}", - ti0, ti1, min_distance, distance_ti0, is_impacting, + ti0, ti1, min_distance_linear, distance_ti0, is_impacting, is_impacting ? fmt::format(" toi={:g}", (ti1 - ti0) * toi + ti0) : ""); if (is_impacting) { toi = (ti1 - ti0) * toi + ti0; if (toi == 0) { - // This is impossible because distance_t0 > min_sep_distance + // This is impossible because distance_t0 > min_distance ts.push((ti1 + ti0) / 2); num_subdivisions++; continue; @@ -150,15 +160,12 @@ bool conservative_piecewise_linear_ccd( // ============================================================================ -bool point_point_nonlinear_ccd( +bool NonlinearCCD::point_point_ccd( const NonlinearTrajectory& p0, const NonlinearTrajectory& p1, double& toi, - const double tmax, const double min_distance, - const double tolerance, - const long max_iterations, - const double conservative_rescaling) + const double tmax) const { return conservative_piecewise_linear_ccd( [&](const double t) { @@ -184,19 +191,16 @@ bool point_point_nonlinear_ccd( output_tolerance, // delta_actual no_zero_toi); // no zero toi }, - toi, tmax, min_distance, conservative_rescaling); + toi, min_distance, tmax, conservative_rescaling); } -bool point_edge_nonlinear_ccd( +bool NonlinearCCD::point_edge_ccd( const NonlinearTrajectory& p, const NonlinearTrajectory& e0, const NonlinearTrajectory& e1, double& toi, - const double tmax, const double min_distance, - const double tolerance, - const long max_iterations, - const double conservative_rescaling) + const double tmax) const { return conservative_piecewise_linear_ccd( [&](const double t) { @@ -223,20 +227,17 @@ bool point_edge_nonlinear_ccd( output_tolerance, // delta_actual no_zero_toi); // no zero toi }, - toi, tmax, min_distance, conservative_rescaling); + toi, min_distance, tmax, conservative_rescaling); } -bool edge_edge_nonlinear_ccd( +bool NonlinearCCD::edge_edge_ccd( const NonlinearTrajectory& ea0, const NonlinearTrajectory& ea1, const NonlinearTrajectory& eb0, const NonlinearTrajectory& eb1, double& toi, - const double tmax, const double min_distance, - const double tolerance, - const long max_iterations, - const double conservative_rescaling) + const double tmax) const { return conservative_piecewise_linear_ccd( [&](const double t) { @@ -265,20 +266,17 @@ bool edge_edge_nonlinear_ccd( output_tolerance, // delta_actual no_zero_toi); // no zero toi }, - toi, tmax, min_distance, conservative_rescaling); + toi, min_distance, tmax, conservative_rescaling); } -bool point_triangle_nonlinear_ccd( +bool NonlinearCCD::point_triangle_ccd( const NonlinearTrajectory& p, const NonlinearTrajectory& t0, const NonlinearTrajectory& t1, const NonlinearTrajectory& t2, double& toi, - const double tmax, const double min_distance, - const double tolerance, - const long max_iterations, - const double conservative_rescaling) + const double tmax) const { return conservative_piecewise_linear_ccd( [&](const double t) { @@ -306,7 +304,7 @@ bool point_triangle_nonlinear_ccd( output_tolerance, // delta_actual no_zero_toi); // no zero toi }, - toi, tmax, min_distance, conservative_rescaling); + toi, min_distance, tmax, conservative_rescaling); } } // namespace ipc diff --git a/src/ipc/ccd/nonlinear_ccd.hpp b/src/ipc/ccd/nonlinear_ccd.hpp index 008ac0aae..912ed01a8 100644 --- a/src/ipc/ccd/nonlinear_ccd.hpp +++ b/src/ipc/ccd/nonlinear_ccd.hpp @@ -48,124 +48,123 @@ class IntervalNonlinearTrajectory : virtual public NonlinearTrajectory { }; #endif -/// @brief Perform nonlinear CCD between two points moving along nonlinear trajectories. -/// @param[in] p0 First point's trajectory -/// @param[in] p1 Second point's trajectory -/// @param[out] toi Output time of impact -/// @param[in] tmax Maximum time to check for collision -/// @param[in] min_distance Minimum separation distance between the two points -/// @param[in] tolerance Tolerance for the linear CCD algorithm -/// @param[in] max_iterations Maximum number of iterations for the linear CCD algorithm -/// @param[in] conservative_rescaling Conservative rescaling of the time of impact -/// @return True if the two points collide, false otherwise. -bool point_point_nonlinear_ccd( - const NonlinearTrajectory& p0, - const NonlinearTrajectory& p1, - double& toi, - const double tmax = 1.0, - const double min_distance = 0, - const double tolerance = TightInclusionCCD::DEFAULT_TOLERANCE, - const long max_iterations = TightInclusionCCD::DEFAULT_MAX_ITERATIONS, - const double conservative_rescaling = - TightInclusionCCD::DEFAULT_CONSERVATIVE_RESCALING); - -/// @brief Perform nonlinear CCD between a point and a linear edge moving along nonlinear trajectories. -/// @param[in] p Point's trajectory -/// @param[in] e0 Edge's first endpoint's trajectory -/// @param[in] e1 Edge's second endpoint's trajectory -/// @param[out] toi Output time of impact -/// @param[in] tmax Maximum time to check for collision -/// @param[in] min_distance Minimum separation distance between the point and the edge -/// @param[in] tolerance Tolerance for the linear CCD algorithm -/// @param[in] max_iterations Maximum number of iterations for the linear CCD algorithm -/// @param[in] conservative_rescaling Conservative rescaling of the time of impact -/// @return True if the point and edge collide, false otherwise. -bool point_edge_nonlinear_ccd( - const NonlinearTrajectory& p, - const NonlinearTrajectory& e0, - const NonlinearTrajectory& e1, - double& toi, - const double tmax = 1.0, - const double min_distance = 0, - const double tolerance = TightInclusionCCD::DEFAULT_TOLERANCE, - const long max_iterations = TightInclusionCCD::DEFAULT_MAX_ITERATIONS, - const double conservative_rescaling = - TightInclusionCCD::DEFAULT_CONSERVATIVE_RESCALING); - -/// @brief Perform nonlinear CCD between two linear edges moving along nonlinear trajectories. -/// @ingroup ccd -/// @param[in] ea0 First edge's first endpoint's trajectory -/// @param[in] ea1 First edge's second endpoint's trajectory -/// @param[in] eb0 Second edge's first endpoint's trajectory -/// @param[in] eb1 Second edge's second endpoint's trajectory -/// @param[out] toi Output time of impact -/// @param[in] tmax Maximum time to check for collision -/// @param[in] min_distance Minimum separation distance between the two edges -/// @param[in] tolerance Tolerance for the linear CCD algorithm -/// @param[in] max_iterations Maximum number of iterations for the linear CCD algorithm -/// @param[in] conservative_rescaling Conservative rescaling of the time of impact -/// @return True if the two edges collide, false otherwise. -bool edge_edge_nonlinear_ccd( - const NonlinearTrajectory& ea0, - const NonlinearTrajectory& ea1, - const NonlinearTrajectory& eb0, - const NonlinearTrajectory& eb1, - double& toi, - const double tmax = 1.0, - const double min_distance = 0, - const double tolerance = TightInclusionCCD::DEFAULT_TOLERANCE, - const long max_iterations = TightInclusionCCD::DEFAULT_MAX_ITERATIONS, - const double conservative_rescaling = - TightInclusionCCD::DEFAULT_CONSERVATIVE_RESCALING); - -/// @brief Perform nonlinear CCD between a point and a linear triangle moving along nonlinear trajectories. -/// @param[in] p Point's trajectory -/// @param[in] t0 Triangle's first vertex's trajectory -/// @param[in] t1 Triangle's second vertex's trajectory -/// @param[in] t2 Triangle's third vertex's trajectory -/// @param[out] toi Output time of impact -/// @param[in] tmax Maximum time to check for collision -/// @param[in] min_distance Minimum separation distance between the two edges -/// @param[in] tolerance Tolerance for the linear CCD algorithm -/// @param[in] max_iterations Maximum number of iterations for the linear CCD algorithm -/// @param[in] conservative_rescaling Conservative rescaling of the time of impact -/// @return True if the point and triangle collide, false otherwise. -bool point_triangle_nonlinear_ccd( - const NonlinearTrajectory& p, - const NonlinearTrajectory& t0, - const NonlinearTrajectory& t1, - const NonlinearTrajectory& t2, - double& toi, - const double tmax = 1.0, - const double min_distance = 0, - const double tolerance = TightInclusionCCD::DEFAULT_TOLERANCE, - const long max_iterations = TightInclusionCCD::DEFAULT_MAX_ITERATIONS, - const double conservative_rescaling = - TightInclusionCCD::DEFAULT_CONSERVATIVE_RESCALING); - -/// @brief Perform conservative piecewise linear CCD of a nonlinear trajectories. -/// @param[in] distance Return the distance for a given time in [0, 1]. -/// @param[in] max_distance_from_linear Return the maximum distance from the linearized trajectory for a given time interval. -/// @param[in] linear_ccd Perform linear CCD on a given time interval. -/// @param[out] toi Output time of impact. -/// @param[in] tmax Maximum time to check for collision. -/// @param[in] min_sep_distance Minimum separation distance between the objects. -/// @param[in] conservative_rescaling Conservative rescaling of the time of impact. -/// @return True if a collision was detected, false otherwise. -bool conservative_piecewise_linear_ccd( - const std::function& distance, - const std::function& - max_distance_from_linear, - const std::function& linear_ccd, - double& toi, - const double tmax = 1.0, - const double min_sep_distance = 0, - const double conservative_rescaling = - TightInclusionCCD::DEFAULT_CONSERVATIVE_RESCALING); +class NonlinearCCD { +public: + /// The default tolerance used with Tight-Inclusion CCD. + static constexpr double DEFAULT_TOLERANCE = 1e-6; + /// The default maximum number of iterations used with Tight-Inclusion CCD. + static constexpr long DEFAULT_MAX_ITERATIONS = 10'000'000l; + /// The default conservative rescaling value used to avoid taking steps + /// exactly to impact. + static constexpr double DEFAULT_CONSERVATIVE_RESCALING = 0.8; + + NonlinearCCD( + const double tolerance = DEFAULT_TOLERANCE, + const long max_iterations = DEFAULT_MAX_ITERATIONS, + const double conservative_rescaling = DEFAULT_CONSERVATIVE_RESCALING); + + virtual ~NonlinearCCD() = default; + + /// @brief Perform nonlinear CCD between two points moving along nonlinear trajectories. + /// @param[in] p0 First point's trajectory + /// @param[in] p1 Second point's trajectory + /// @param[out] toi Output time of impact + /// @param[in] min_distance Minimum separation distance between the two points + /// @param[in] tmax Maximum time to check for collision + /// @return True if the two points collide, false otherwise. + virtual bool point_point_ccd( + const NonlinearTrajectory& p0, + const NonlinearTrajectory& p1, + double& toi, + const double min_distance = 0, + const double tmax = 1.0) const; + + /// @brief Perform nonlinear CCD between a point and a linear edge moving along nonlinear trajectories. + /// @param[in] p Point's trajectory + /// @param[in] e0 Edge's first endpoint's trajectory + /// @param[in] e1 Edge's second endpoint's trajectory + /// @param[out] toi Output time of impact + /// @param[in] min_distance Minimum separation distance between the point and the edge + /// @param[in] tmax Maximum time to check for collision + /// @return True if the point and edge collide, false otherwise. + virtual bool point_edge_ccd( + const NonlinearTrajectory& p, + const NonlinearTrajectory& e0, + const NonlinearTrajectory& e1, + double& toi, + const double min_distance = 0, + const double tmax = 1.0) const; + + /// @brief Perform nonlinear CCD between two linear edges moving along nonlinear trajectories. + /// @ingroup ccd + /// @param[in] ea0 First edge's first endpoint's trajectory + /// @param[in] ea1 First edge's second endpoint's trajectory + /// @param[in] eb0 Second edge's first endpoint's trajectory + /// @param[in] eb1 Second edge's second endpoint's trajectory + /// @param[out] toi Output time of impact + /// @param[in] min_distance Minimum separation distance between the two edges + /// @param[in] tmax Maximum time to check for collision + /// @return True if the two edges collide, false otherwise. + virtual bool edge_edge_ccd( + const NonlinearTrajectory& ea0, + const NonlinearTrajectory& ea1, + const NonlinearTrajectory& eb0, + const NonlinearTrajectory& eb1, + double& toi, + const double min_distance = 0, + const double tmax = 1.0) const; + + /// @brief Perform nonlinear CCD between a point and a linear triangle moving along nonlinear trajectories. + /// @param[in] p Point's trajectory + /// @param[in] t0 Triangle's first vertex's trajectory + /// @param[in] t1 Triangle's second vertex's trajectory + /// @param[in] t2 Triangle's third vertex's trajectory + /// @param[out] toi Output time of impact + /// @param[in] min_distance Minimum separation distance between the two edges + /// @param[in] tmax Maximum time to check for collision + /// @return True if the point and triangle collide, false otherwise. + bool point_triangle_ccd( + const NonlinearTrajectory& p, + const NonlinearTrajectory& t0, + const NonlinearTrajectory& t1, + const NonlinearTrajectory& t2, + double& toi, + const double min_distance = 0.0, + const double tmax = 1.0) const; + + /// @brief Solver tolerance. + double tolerance; + + /// @brief Maximum number of iterations. + long max_iterations; + + /// @brief Conservative rescaling of the time of impact. + double conservative_rescaling; + +public: + /// @brief Perform conservative piecewise linear CCD of a nonlinear trajectories. + /// @param[in] distance Return the distance for a given time in [0, 1]. + /// @param[in] max_distance_from_linear Return the maximum distance from the linearized trajectory for a given time interval. + /// @param[in] linear_ccd Perform linear CCD on a given time interval. + /// @param[out] toi Output time of impact. + /// @param[in] min_distance Minimum separation distance between the objects. + /// @param[in] tmax Maximum time to check for collision. + /// @param[in] conservative_rescaling Conservative rescaling of the time of impact. + /// @return True if a collision was detected, false otherwise. + static bool conservative_piecewise_linear_ccd( + const std::function& distance, + const std::function& + max_distance_from_linear, + const std::function& linear_ccd, + double& toi, + const double min_distance = 0, + const double tmax = 1.0, + const double conservative_rescaling = DEFAULT_CONSERVATIVE_RESCALING); +}; } // namespace ipc diff --git a/tests/src/tests/ccd/test_nonlinear_ccd.cpp b/tests/src/tests/ccd/test_nonlinear_ccd.cpp index cc4cb284a..6236c5009 100644 --- a/tests/src/tests/ccd/test_nonlinear_ccd.cpp +++ b/tests/src/tests/ccd/test_nonlinear_ccd.cpp @@ -12,8 +12,8 @@ using namespace ipc; class RotationalTrajectory : virtual public NonlinearTrajectory { public: RotationalTrajectory( - const VectorMax3d& _point, - const VectorMax3d& _center, + Eigen::ConstRef _point, + Eigen::ConstRef _center, const double _z_angular_velocity) : center(_center) , point(_point) @@ -46,8 +46,8 @@ class RotationalTrajectory : virtual public NonlinearTrajectory { template static VectorMax3 position( - const VectorMax3d& center, - const VectorMax3d& point, + Eigen::ConstRef center, + Eigen::ConstRef point, const double z_angular_velocity, const T& t) { @@ -71,8 +71,8 @@ class IntervalRotationalTrajectory : public RotationalTrajectory, public IntervalNonlinearTrajectory { public: IntervalRotationalTrajectory( - const VectorMax3d& _point, - const VectorMax3d& _center, + Eigen::ConstRef _point, + Eigen::ConstRef _center, const double _z_angular_velocity) : RotationalTrajectory(_point, _center, _z_angular_velocity) { @@ -95,7 +95,7 @@ class IntervalRotationalTrajectory : public RotationalTrajectory, class StaticTrajectory : public NonlinearTrajectory { public: - StaticTrajectory(const VectorMax3d& _point) : point(_point) { } + StaticTrajectory(Eigen::ConstRef _point) : point(_point) { } VectorMax3d operator()(const double t) const override { return point; } @@ -113,9 +113,9 @@ class StaticTrajectory : public NonlinearTrajectory { class Rigid2DTrajectory : virtual public ipc::NonlinearTrajectory { public: Rigid2DTrajectory( - const Eigen::Vector2d& _position, - const Eigen::Vector2d& _translation, - const Eigen::Vector2d& _delta_translation, + Eigen::ConstRef _position, + Eigen::ConstRef _translation, + Eigen::ConstRef _delta_translation, const double _rotation, const double _delta_rotation) : position(_position) @@ -179,12 +179,11 @@ TEST_CASE("Nonlinear Point-Point CCD", "[ccd][nonlinear][point-point]") } #endif + NonlinearCCD ccd; + ccd.conservative_rescaling = 0.9; + double toi; - bool collision = point_point_nonlinear_ccd( - p0, *p1, toi, /*tmax=*/1.0, /*min_distance=*/0, - TightInclusionCCD::DEFAULT_TOLERANCE, - TightInclusionCCD::DEFAULT_MAX_ITERATIONS, - /*conservative_rescaling=*/0.9); + bool collision = ccd.point_point_ccd(p0, *p1, toi); CHECK(collision); CHECK(toi <= 0.5); @@ -199,12 +198,11 @@ TEST_CASE("Nonlinear Point-Edge CCD", "[ccd][nonlinear][point-edge]") const RotationalTrajectory e1( Eigen::Vector2d(1, 0), Eigen::Vector2d::Zero(), 2 * igl::PI); + NonlinearCCD ccd; + ccd.conservative_rescaling = 0.9; + double toi; - bool collision = point_edge_nonlinear_ccd( - p, e0, e1, toi, /*tmax=*/1.0, /*min_distance=*/0, - TightInclusionCCD::DEFAULT_TOLERANCE, - TightInclusionCCD::DEFAULT_MAX_ITERATIONS, - /*conservative_rescaling=*/0.9); + bool collision = ccd.point_edge_ccd(p, e0, e1, toi); CHECK(collision); CHECK(toi <= 0.25); @@ -226,14 +224,11 @@ TEST_CASE("Rigid 2D Trajectory", "[ccd][nonlinear][point-edge]") Eigen::Vector2d(+1, 0), Eigen::Vector2d::Zero(), Eigen::Vector2d::Zero(), 0, igl::PI); + NonlinearCCD ccd; + ccd.conservative_rescaling = 0.9; + double toi; - bool collision = ipc::point_edge_nonlinear_ccd( - p, e0, e1, toi, /*tmax=*/1.0, /*min_distance=*/0, - TightInclusionCCD::DEFAULT_TOLERANCE, - TightInclusionCCD::DEFAULT_MAX_ITERATIONS, - // increase the conservative_rescaling from 0.8 to 0.9 to get a more - // accurate estimate - /*conservative_rescaling=*/0.9); + bool collision = ccd.point_edge_ccd(p, e0, e1, toi); CHECK(collision); CHECK((0.49 <= toi && toi <= 0.5)); // conservative estimate @@ -250,7 +245,7 @@ TEST_CASE("Nonlinear Edge-Edge CCD", "[ccd][nonlinear][edge-edge]") const StaticTrajectory eb1(Eigen::Vector3d(1, 0.5, 0)); double toi; - bool collision = edge_edge_nonlinear_ccd(ea0, ea1, eb0, eb1, toi); + bool collision = NonlinearCCD().edge_edge_ccd(ea0, ea1, eb0, eb1, toi); CHECK(collision); CHECK(toi <= 30 / 360.0); @@ -269,12 +264,11 @@ TEST_CASE("Nonlinear Point-Triangle CCD", "[ccd][nonlinear][point-triangle]") Eigen::Vector3d(x, 0, -1), Eigen::Vector3d::Zero(), igl::PI); const StaticTrajectory p(Eigen::Vector3d(0, 0.5, 0)); + NonlinearCCD ccd; + ccd.conservative_rescaling = 0.9; + double toi; - bool collision = point_triangle_nonlinear_ccd( - p, t0, t1, t2, toi, /*tmax=*/1.0, /*min_distance=*/0, - TightInclusionCCD::DEFAULT_TOLERANCE, - TightInclusionCCD::DEFAULT_MAX_ITERATIONS, - /*conservative_rescaling=*/0.9); + bool collision = ccd.point_triangle_ccd(p, t0, t1, t2, toi); CHECK(collision); CHECK(toi <= 0.5); diff --git a/tests/src/tests/ccd/test_point_edge_ccd.cpp b/tests/src/tests/ccd/test_point_edge_ccd.cpp index b5c330eb0..11f29b6d8 100644 --- a/tests/src/tests/ccd/test_point_edge_ccd.cpp +++ b/tests/src/tests/ccd/test_point_edge_ccd.cpp @@ -12,12 +12,12 @@ namespace { /// Compares the time of impact of different implementations /// against the expected time of impact void check_toi( - const VectorMax3d& p_t0, - const VectorMax3d& e0_t0, - const VectorMax3d& e1_t0, - const VectorMax3d& p_t1, - const VectorMax3d& e0_t1, - const VectorMax3d& e1_t1, + Eigen::ConstRef p_t0, + Eigen::ConstRef e0_t0, + Eigen::ConstRef e1_t0, + Eigen::ConstRef p_t1, + Eigen::ConstRef e0_t1, + Eigen::ConstRef e1_t1, const double toi_expected) { double toi; diff --git a/tests/src/tests/test_has_intersections.cpp b/tests/src/tests/test_has_intersections.cpp index b942a871b..237fb3a28 100644 --- a/tests/src/tests/test_has_intersections.cpp +++ b/tests/src/tests/test_has_intersections.cpp @@ -27,8 +27,8 @@ Eigen::MatrixXi remove_faces_with_degenerate_edges( bool combine_meshes( const std::string& mesh1_name, const std::string& mesh2_name, - const Eigen::Matrix3d& R1, - const Eigen::Matrix3d& R2, + Eigen::ConstRef R1, + Eigen::ConstRef R2, int dim, Eigen::MatrixXd& V, Eigen::MatrixXi& E, diff --git a/tests/src/tests/utils.hpp b/tests/src/tests/utils.hpp index e814d739c..5b126b6b7 100644 --- a/tests/src/tests/utils.hpp +++ b/tests/src/tests/utils.hpp @@ -90,8 +90,8 @@ void print_compare_nonzero( // ============================================================================ -inline Eigen::Vector2d -edge_normal(const Eigen::Vector2d& e0, const Eigen::Vector2d& e1) +inline Eigen::Vector2d edge_normal( + Eigen::ConstRef e0, Eigen::ConstRef e1) { Eigen::Vector2d e = e1 - e0; Eigen::Vector2d normal(-e.y(), e.x()); From 302eba662bbf4ec63601636942ed321dfca640c5 Mon Sep 17 00:00:00 2001 From: Zachary Ferguson Date: Sat, 28 Feb 2026 19:59:52 -0500 Subject: [PATCH 2/3] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- python/src/ccd/nonlinear_ccd.cpp | 6 +++--- src/ipc/ccd/nonlinear_ccd.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python/src/ccd/nonlinear_ccd.cpp b/python/src/ccd/nonlinear_ccd.cpp index ede9fa782..f1adf3a94 100644 --- a/python/src/ccd/nonlinear_ccd.cpp +++ b/python/src/ccd/nonlinear_ccd.cpp @@ -107,8 +107,8 @@ void define_nonlinear_ccd(py::module_& m) Parameters: p0: First point's trajectory p1: Second point's trajectory - tmax: Maximum time to check for collision min_distance: Minimum separation distance between the two points + tmax: Maximum time to check for collision Returns: Tuple of: @@ -169,8 +169,8 @@ void define_nonlinear_ccd(py::module_& m) True if the two edges collide, false otherwise. Output time of impact )ipc_Qu8mg5v7", - "ea0"_a, "ea1"_a, "eb0"_a, "eb1"_a, "tmax"_a = 1.0, - "min_distance"_a = 0) + "ea0"_a, "ea1"_a, "eb0"_a, "eb1"_a, "min_distance"_a = 0, + "tmax"_a = 1.0) .def( "point_triangle_ccd", [](const NonlinearCCD& self, const NonlinearTrajectory& p, diff --git a/src/ipc/ccd/nonlinear_ccd.hpp b/src/ipc/ccd/nonlinear_ccd.hpp index 912ed01a8..4d9a3f20f 100644 --- a/src/ipc/ccd/nonlinear_ccd.hpp +++ b/src/ipc/ccd/nonlinear_ccd.hpp @@ -53,7 +53,7 @@ class NonlinearCCD { /// The default tolerance used with Tight-Inclusion CCD. static constexpr double DEFAULT_TOLERANCE = 1e-6; /// The default maximum number of iterations used with Tight-Inclusion CCD. - static constexpr long DEFAULT_MAX_ITERATIONS = 10'000'000l; + static constexpr long DEFAULT_MAX_ITERATIONS = 10'000'000L; /// The default conservative rescaling value used to avoid taking steps /// exactly to impact. static constexpr double DEFAULT_CONSERVATIVE_RESCALING = 0.8; From a8b56862f7859364b0c4c3ec7da59e352033f670 Mon Sep 17 00:00:00 2001 From: Zachary Ferguson Date: Sat, 28 Feb 2026 20:00:49 -0500 Subject: [PATCH 3/3] Make NonlinearCCD::point_triangle_ccd virtual --- src/ipc/ccd/nonlinear_ccd.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ipc/ccd/nonlinear_ccd.hpp b/src/ipc/ccd/nonlinear_ccd.hpp index 4d9a3f20f..499e5ac7b 100644 --- a/src/ipc/ccd/nonlinear_ccd.hpp +++ b/src/ipc/ccd/nonlinear_ccd.hpp @@ -123,7 +123,7 @@ class NonlinearCCD { /// @param[in] min_distance Minimum separation distance between the two edges /// @param[in] tmax Maximum time to check for collision /// @return True if the point and triangle collide, false otherwise. - bool point_triangle_ccd( + virtual bool point_triangle_ccd( const NonlinearTrajectory& p, const NonlinearTrajectory& t0, const NonlinearTrajectory& t1,