From 959aa11521f102f74de46f3b14462ecff40ed6c7 Mon Sep 17 00:00:00 2001 From: Zachary Ferguson Date: Mon, 30 Oct 2023 18:46:05 -0400 Subject: [PATCH 01/10] Update Python bindings --- python/CMakeLists.txt | 1 + python/src/barrier/barrier.cpp | 27 +- python/src/bindings.cpp | 3 +- python/src/broad_phase/aabb.cpp | 35 ++- python/src/broad_phase/bindings.hpp | 2 +- python/src/broad_phase/broad_phase.cpp | 28 +- python/src/broad_phase/brute_force.cpp | 11 +- python/src/broad_phase/bvh.cpp | 5 +- python/src/broad_phase/hash_grid.cpp | 31 ++- python/src/broad_phase/spatial_hash.cpp | 37 ++- .../broad_phase/sweep_and_tiniest_queue.cpp | 44 +++- .../src/broad_phase/voxel_size_heuristic.cpp | 9 +- python/src/candidates/candidates.cpp | 19 +- .../continuous_collision_candidate.cpp | 13 +- python/src/candidates/edge_edge.cpp | 66 +---- python/src/candidates/edge_face.cpp | 6 +- python/src/candidates/edge_vertex.cpp | 58 +--- python/src/candidates/face_vertex.cpp | 40 +-- python/src/candidates/vertex_vertex.cpp | 21 +- python/src/ccd/aabb.cpp | 23 +- python/src/ccd/additive_ccd.cpp | 35 ++- python/src/ccd/bindings.hpp | 1 + python/src/ccd/ccd.cpp | 57 +++- python/src/ccd/inexact_point_edge.cpp | 5 +- python/src/ccd/nonlinear_ccd.cpp | 247 ++++++++++++++++++ python/src/ccd/point_static_plane.cpp | 2 +- python/src/collision_mesh.cpp | 47 ++-- .../src/collisions/collision_constraint.cpp | 13 +- .../src/collisions/collision_constraints.cpp | 7 +- python/src/collisions/edge_edge.cpp | 45 +++- python/src/collisions/edge_vertex.cpp | 12 +- python/src/collisions/face_vertex.cpp | 8 +- python/src/collisions/plane_vertex.cpp | 14 +- python/src/collisions/vertex_vertex.cpp | 8 +- python/src/distance/distance_type.cpp | 38 ++- python/src/distance/edge_edge.cpp | 30 +-- python/src/distance/edge_edge_mollifier.cpp | 74 +++--- python/src/distance/line_line.cpp | 24 +- python/src/distance/point_edge.cpp | 30 +-- python/src/distance/point_line.cpp | 18 +- python/src/distance/point_plane.cpp | 42 +-- python/src/distance/point_point.cpp | 16 +- python/src/distance/point_triangle.cpp | 40 +-- python/src/friction/closest_point.cpp | 40 +-- python/src/friction/constraints/edge_edge.cpp | 4 +- .../src/friction/constraints/edge_vertex.cpp | 4 +- .../src/friction/constraints/face_vertex.cpp | 4 +- .../constraints/friction_constraint.cpp | 12 +- .../friction/constraints/vertex_vertex.cpp | 6 +- python/src/friction/friction_constraints.cpp | 32 +-- .../src/friction/normal_force_magnitude.cpp | 8 +- python/src/friction/relative_velocity.cpp | 14 +- .../friction/smooth_friction_mollifier.cpp | 2 + python/src/friction/tangent_basis.cpp | 58 ++-- python/src/ipc.cpp | 14 +- python/src/utils/eigen_ext.cpp | 23 +- python/src/utils/intersection.cpp | 2 +- python/src/utils/vertex_to_min_edge.cpp | 2 +- src/ipc/barrier/barrier.hpp | 2 +- src/ipc/broad_phase/aabb.hpp | 21 +- src/ipc/broad_phase/hash_grid.hpp | 6 +- src/ipc/candidates/edge_edge.hpp | 6 +- src/ipc/candidates/edge_face.hpp | 6 +- src/ipc/candidates/edge_vertex.hpp | 6 +- src/ipc/candidates/face_vertex.hpp | 6 +- src/ipc/candidates/vertex_vertex.hpp | 6 +- src/ipc/distance/distance_type.hpp | 34 ++- src/ipc/implicits/plane.hpp | 18 +- 68 files changed, 1032 insertions(+), 596 deletions(-) create mode 100644 python/src/ccd/nonlinear_ccd.cpp diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index adf7c6975..5c009ad53 100755 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -30,6 +30,7 @@ pybind11_add_module(ipctk src/ccd/ccd.cpp src/ccd/additive_ccd.cpp src/ccd/inexact_point_edge.cpp + src/ccd/nonlinear_ccd.cpp src/ccd/point_static_plane.cpp src/collisions/collision_constraint.cpp diff --git a/python/src/barrier/barrier.cpp b/python/src/barrier/barrier.cpp index 4053a0f31..47b8f380e 100644 --- a/python/src/barrier/barrier.cpp +++ b/python/src/barrier/barrier.cpp @@ -12,15 +12,16 @@ void define_barrier(py::module_& m) R"ipc_Qu8mg5v7( Function that grows to infinity as d approaches 0 from the right. - .. math:: b(d) = -(d-\hat{d})^2\ln\left(\frac{d}{\hat{d}}\right) + .. math:: + + b(d) = -(d-\hat{d})^2\ln\left(\frac{d}{\hat{d}}\right) Parameters: - d: distance - dhat: activation distance of the barrier + d: The distance. + dhat: Activation distance of the barrier. Returns: The value of the barrier function at d. - )ipc_Qu8mg5v7", py::arg("d"), py::arg("dhat")); @@ -29,11 +30,14 @@ void define_barrier(py::module_& m) R"ipc_Qu8mg5v7( Derivative of the barrier function. - .. math:: b'(d) = (\hat{d}-d) \left( 2\ln\left( \frac{d}{\hat{d}} \right) - \frac{\hat{d}}{d} + 1\right) + .. math:: + + b'(d) = (\hat{d}-d) \left( 2\ln\left( \frac{d}{\hat{d}} \right) - + \frac{\hat{d}}{d} + 1\right) Parameters: - d: distance - dhat: activation distance of the barrier + d: The distance. + dhat: Activation distance of the barrier. Returns: The derivative of the barrier wrt d. @@ -45,11 +49,14 @@ void define_barrier(py::module_& m) R"ipc_Qu8mg5v7( Second derivative of the barrier function. - .. math:: b''(d) = \left( \frac{\hat{d}}{d} + 2 \right) \frac{\hat{d}}{d} - 2\ln\left( \frac{d}{\hat{d}} \right) - 3 + .. math:: + + b''(d) = \left( \frac{\hat{d}}{d} + 2 \right) \frac{\hat{d}}{d} - + 2\ln\left( \frac{d}{\hat{d}} \right) - 3 Parameters: - d: distance - dhat: activation distance of the barrier + d: The distance. + dhat: Activation distance of the barrier. Returns: The second derivative of the barrier wrt d. diff --git a/python/src/bindings.cpp b/python/src/bindings.cpp index 5793649fb..254dc9515 100644 --- a/python/src/bindings.cpp +++ b/python/src/bindings.cpp @@ -21,7 +21,7 @@ PYBIND11_MODULE(ipctk, m) define_bvh(m); define_hash_grid(m); define_spatial_hash(m); - define_sweep(m); + define_sweep_and_tiniest_queue(m); define_voxel_size_heuristic(m); // candidates @@ -39,6 +39,7 @@ PYBIND11_MODULE(ipctk, m) define_ccd(m); define_additive_ccd(m); define_inexact_point_edge(m); + define_nonlinear_ccd(m); define_point_static_plane(m); // collisions diff --git a/python/src/broad_phase/aabb.cpp b/python/src/broad_phase/aabb.cpp index cafaae794..8c7bc6685 100644 --- a/python/src/broad_phase/aabb.cpp +++ b/python/src/broad_phase/aabb.cpp @@ -8,22 +8,22 @@ using namespace ipc; void define_aabb(py::module_& m) { py::class_(m, "AABB") - .def(py::init(), "") + .def(py::init()) .def( - py::init(), "", - py::arg("min"), py::arg("max")) + py::init(), py::arg("min"), + py::arg("max")) .def( - py::init(), "", py::arg("aabb1"), + py::init(), py::arg("aabb1"), py::arg("aabb2")) .def( - py::init(), "", - py::arg("aabb1"), py::arg("aabb2"), py::arg("aabb3")) + py::init(), py::arg("aabb1"), + py::arg("aabb2"), py::arg("aabb3")) .def_static( "from_point", py::overload_cast( &AABB::from_point), R"ipc_Qu8mg5v7( - Compute a AABB for a static point. + Construct a AABB for a static point. Parameters: p: The point's position. @@ -39,7 +39,7 @@ void define_aabb(py::module_& m) const VectorMax3d&, const VectorMax3d&, const double>( &AABB::from_point), R"ipc_Qu8mg5v7( - Compute a AABB for a moving point (i.e. temporal edge). + Construct a AABB for a moving point (i.e. temporal edge). Parameters: p_t0: The point's position at time t=0. @@ -83,8 +83,17 @@ void define_aabb(py::module_& m) build_vertex_boxes(vertices, vertex_boxes, inflation_radius); return vertex_boxes; }, - "Build one AABB per vertex position (row of V).", py::arg("vertices"), - py::arg("inflation_radius") = 0); + R"ipc_Qu8mg5v7( + Build one AABB per vertex position (row of V). + + Parameters: + vertices: Vertex positions (rowwise). + inflation_radius: Radius of a sphere around the points which the AABBs enclose. + + Returns: + Vertex AABBs. + )ipc_Qu8mg5v7", + py::arg("vertices"), py::arg("inflation_radius") = 0); m.def( "build_vertex_boxes", @@ -96,7 +105,7 @@ void define_aabb(py::module_& m) vertices_t0, vertices_t1, vertex_boxes, inflation_radius); return vertex_boxes; }, - "", py::arg("vertices_t0"), py::arg("vertices_t1"), + py::arg("vertices_t0"), py::arg("vertices_t1"), py::arg("inflation_radius") = 0); m.def( @@ -107,7 +116,7 @@ void define_aabb(py::module_& m) build_edge_boxes(vertex_boxes, edges, edge_boxes); return edge_boxes; }, - "", py::arg("vertex_boxes"), py::arg("edges")); + py::arg("vertex_boxes"), py::arg("edges")); m.def( "build_face_boxes", @@ -117,5 +126,5 @@ void define_aabb(py::module_& m) build_face_boxes(vertex_boxes, faces, face_boxes); return face_boxes; }, - "", py::arg("vertex_boxes"), py::arg("faces")); + py::arg("vertex_boxes"), py::arg("faces")); } diff --git a/python/src/broad_phase/bindings.hpp b/python/src/broad_phase/bindings.hpp index 8f6dd60de..f66a9443d 100644 --- a/python/src/broad_phase/bindings.hpp +++ b/python/src/broad_phase/bindings.hpp @@ -10,5 +10,5 @@ void define_brute_force(py::module_& m); void define_bvh(py::module_& m); void define_hash_grid(py::module_& m); void define_spatial_hash(py::module_& m); -void define_sweep(py::module_& m); +void define_sweep_and_tiniest_queue(py::module_& m); void define_voxel_size_heuristic(py::module_& m); diff --git a/python/src/broad_phase/broad_phase.cpp b/python/src/broad_phase/broad_phase.cpp index 80e73e50c..bb1c995ee 100644 --- a/python/src/broad_phase/broad_phase.cpp +++ b/python/src/broad_phase/broad_phase.cpp @@ -34,12 +34,12 @@ void define_broad_phase(py::module_& m) Returns: The constructed broad phase object. )ipc_Qu8mg5v7", - py::arg("broad_phase_method")) + py::arg("method")) .def( "build", py::overload_cast< const Eigen::MatrixXd&, const Eigen::MatrixXi&, - const Eigen::MatrixXi&, double>(&BroadPhase::build), + const Eigen::MatrixXi&, const double>(&BroadPhase::build), R"ipc_Qu8mg5v7( Build the broad phase for static collision detection. @@ -55,7 +55,7 @@ void define_broad_phase(py::module_& m) "build", py::overload_cast< const Eigen::MatrixXd&, const Eigen::MatrixXd&, - const Eigen::MatrixXi&, const Eigen::MatrixXi&, double>( + const Eigen::MatrixXi&, const Eigen::MatrixXi&, const double>( &BroadPhase::build), R"ipc_Qu8mg5v7( Build the broad phase for continuous collision detection. @@ -70,6 +70,19 @@ void define_broad_phase(py::module_& m) py::arg("vertices_t0"), py::arg("vertices_t1"), py::arg("edges"), py::arg("faces"), py::arg("inflation_radius") = 0) .def("clear", &BroadPhase::clear, "Clear any built data.") + .def( + "detect_vertex_vertex_candidates", + [](BroadPhase& self) { + std::vector candidates; + self.detect_vertex_vertex_candidates(candidates); + return candidates; + }, + R"ipc_Qu8mg5v7( + Find the candidate vertex-vertex collisions. + + Returns: + The candidate vertex-vertex collisions. + )ipc_Qu8mg5v7") .def( "detect_edge_vertex_candidates", [](BroadPhase& self) { @@ -78,10 +91,10 @@ void define_broad_phase(py::module_& m) return candidates; }, R"ipc_Qu8mg5v7( - Find the candidate edge-vertex collisisons. + Find the candidate edge-vertex collisions. Returns: - The candidate edge-vertex collisisons. + The candidate edge-vertex collisions. )ipc_Qu8mg5v7") .def( "detect_edge_edge_candidates", @@ -94,7 +107,7 @@ void define_broad_phase(py::module_& m) Find the candidate edge-edge collisions. Returns: - The candidate edge-edge collisisons. + The candidate edge-edge collisions. )ipc_Qu8mg5v7") .def( "detect_face_vertex_candidates", @@ -107,7 +120,7 @@ void define_broad_phase(py::module_& m) Find the candidate face-vertex collisions. Returns: - The candidate face-vertex collisisons. + The candidate face-vertex collisions. )ipc_Qu8mg5v7") .def( "detect_edge_face_candidates", @@ -134,6 +147,7 @@ void define_broad_phase(py::module_& m) Parameters: dim: The dimension of the simulation (i.e., 2 or 3). + candidates: The detected collision candidates. )ipc_Qu8mg5v7", py::arg("dim")) .def_readwrite( diff --git a/python/src/broad_phase/brute_force.cpp b/python/src/broad_phase/brute_force.cpp index 89e157eeb..8f957f4ef 100644 --- a/python/src/broad_phase/brute_force.cpp +++ b/python/src/broad_phase/brute_force.cpp @@ -8,7 +8,14 @@ using namespace ipc; void define_brute_force(py::module_& m) { py::class_(m, "BruteForce") - .def(py::init()) + .def( + "detect_vertex_vertex_candidates", + [](BruteForce& self) { + std::vector candidates; + self.detect_vertex_vertex_candidates(candidates); + return candidates; + }, + "Find the candidate vertex-vertex collisions.") .def( "detect_edge_vertex_candidates", [](BruteForce& self) { @@ -16,7 +23,7 @@ void define_brute_force(py::module_& m) self.detect_edge_vertex_candidates(candidates); return candidates; }, - "Find the candidate edge-vertex collisisons.") + "Find the candidate edge-vertex collisions.") .def( "detect_edge_edge_candidates", [](BruteForce& self) { diff --git a/python/src/broad_phase/bvh.cpp b/python/src/broad_phase/bvh.cpp index de6eb1d07..91a5665f2 100644 --- a/python/src/broad_phase/bvh.cpp +++ b/python/src/broad_phase/bvh.cpp @@ -1,7 +1,4 @@ -#include -#include -#include -#include +#include #include diff --git a/python/src/broad_phase/hash_grid.cpp b/python/src/broad_phase/hash_grid.cpp index a4f0822ae..1d76df276 100644 --- a/python/src/broad_phase/hash_grid.cpp +++ b/python/src/broad_phase/hash_grid.cpp @@ -29,7 +29,7 @@ void define_hash_grid(py::module_& m) Build the broad phase for static collision detection. Parameters: - vertices_t0: Vertex positions + vertices: Vertex positions edges: Collision mesh edges faces: Collision mesh faces inflation_radius: Radius of inflation around all elements. @@ -55,6 +55,14 @@ void define_hash_grid(py::module_& m) py::arg("vertices_t0"), py::arg("vertices_t1"), py::arg("edges"), py::arg("faces"), py::arg("inflation_radius") = 0) .def("clear", &HashGrid::clear, "Clear the hash grid.") + .def( + "detect_vertex_vertex_candidates", + [](HashGrid& self) { + std::vector candidates; + self.detect_vertex_vertex_candidates(candidates); + return candidates; + }, + "Find the candidate vertex-vertex collisions.") .def( "detect_edge_vertex_candidates", [](HashGrid& self) { @@ -63,10 +71,10 @@ void define_hash_grid(py::module_& m) return candidates; }, R"ipc_Qu8mg5v7( - Find the candidate edge-vertex collisisons. + Find the candidate edge-vertex collisions. Returns: - The candidate edge-vertex collisisons. + The candidate edge-vertex collisions. )ipc_Qu8mg5v7") .def( "detect_edge_edge_candidates", @@ -79,7 +87,7 @@ void define_hash_grid(py::module_& m) Find the candidate edge-edge collisions. Returns: - The candidate edge-edge collisisons. + The candidate edge-edge collisions. )ipc_Qu8mg5v7") .def( "detect_face_vertex_candidates", @@ -92,7 +100,7 @@ void define_hash_grid(py::module_& m) Find the candidate face-vertex collisions. Returns: - The candidate face-vertex collisisons. + The candidate face-vertex collisions. )ipc_Qu8mg5v7") .def( "detect_edge_face_candidates", @@ -107,8 +115,13 @@ void define_hash_grid(py::module_& m) Returns: The candidate edge-face intersections. )ipc_Qu8mg5v7") - .def("cellSize", &HashGrid::cellSize, "") - .def("gridSize", &HashGrid::gridSize, "") - .def("domainMin", &HashGrid::domainMin, "") - .def("domainMax", &HashGrid::domainMax, ""); + .def("cellSize", &HashGrid::cellSize) + .def( + "gridSize", &HashGrid::gridSize, py::return_value_policy::reference) + .def( + "domainMin", &HashGrid::domainMin, + py::return_value_policy::reference) + .def( + "domainMax", &HashGrid::domainMax, + py::return_value_policy::reference); } diff --git a/python/src/broad_phase/spatial_hash.cpp b/python/src/broad_phase/spatial_hash.cpp index 9eb1963c7..2d0af8b7c 100644 --- a/python/src/broad_phase/spatial_hash.cpp +++ b/python/src/broad_phase/spatial_hash.cpp @@ -13,22 +13,22 @@ void define_spatial_hash(py::module_& m) py::init< const Eigen::MatrixXd&, const Eigen::MatrixXi&, const Eigen::MatrixXi&, double, double>(), - "", py::arg("vertices"), py::arg("edges"), py::arg("faces"), + py::arg("vertices"), py::arg("edges"), py::arg("faces"), py::arg("inflation_radius") = 0, py::arg("voxel_size") = -1) .def( py::init< const Eigen::MatrixXd&, const Eigen::MatrixXd&, const Eigen::MatrixXi&, const Eigen::MatrixXi&, double, double>(), - "", py::arg("vertices_t0"), py::arg("vertices_t1"), - py::arg("edges"), py::arg("faces"), py::arg("inflation_radius") = 0, + py::arg("vertices_t0"), py::arg("vertices_t1"), py::arg("edges"), + py::arg("faces"), py::arg("inflation_radius") = 0, py::arg("voxel_size") = -1) .def( "build", py::overload_cast< const Eigen::MatrixXd&, const Eigen::MatrixXi&, const Eigen::MatrixXi&, double, double>(&SpatialHash::build), - "", py::arg("vertices"), py::arg("edges"), py::arg("faces"), + py::arg("vertices"), py::arg("edges"), py::arg("faces"), py::arg("inflation_radius") = 0, py::arg("voxel_size") = -1) .def( "build", @@ -36,10 +36,33 @@ void define_spatial_hash(py::module_& m) const Eigen::MatrixXd&, const Eigen::MatrixXd&, const Eigen::MatrixXi&, const Eigen::MatrixXi&, double, double>( &SpatialHash::build), - "", py::arg("vertices_t0"), py::arg("vertices_t1"), - py::arg("edges"), py::arg("faces"), py::arg("inflation_radius") = 0, + py::arg("vertices_t0"), py::arg("vertices_t1"), py::arg("edges"), + py::arg("faces"), py::arg("inflation_radius") = 0, py::arg("voxel_size") = -1) .def("clear", &SpatialHash::clear) + .def( + "is_vertex_index", &SpatialHash::is_vertex_index, + "Check if primitive index refers to a vertex.", py::arg("idx")) + .def( + "is_edge_index", &SpatialHash::is_edge_index, + "Check if primitive index refers to an edge.", py::arg("idx")) + .def( + "is_triangle_index", &SpatialHash::is_triangle_index, + "Check if primitive index refers to a triangle.", py::arg("idx")) + .def( + "to_edge_index", &SpatialHash::to_edge_index, + "Convert a primitive index to an edge index.", py::arg("idx")) + .def( + "to_triangle_index", &SpatialHash::to_triangle_index, + "Convert a primitive index to a triangle index.", py::arg("idx")) + .def( + "detect_vertex_vertex_candidates", + [](SpatialHash& self) { + std::vector candidates; + self.detect_vertex_vertex_candidates(candidates); + return candidates; + }, + "Find the candidate vertex-vertex collisions.") .def( "detect_edge_vertex_candidates", [](SpatialHash& self) { @@ -47,7 +70,7 @@ void define_spatial_hash(py::module_& m) self.detect_edge_vertex_candidates(candidates); return candidates; }, - "Find the candidate edge-vertex collisisons.") + "Find the candidate edge-vertex collisions.") .def( "detect_edge_edge_candidates", [](SpatialHash& self) { diff --git a/python/src/broad_phase/sweep_and_tiniest_queue.cpp b/python/src/broad_phase/sweep_and_tiniest_queue.cpp index 14b7d09d8..757f70fb7 100644 --- a/python/src/broad_phase/sweep_and_tiniest_queue.cpp +++ b/python/src/broad_phase/sweep_and_tiniest_queue.cpp @@ -5,7 +5,7 @@ namespace py = pybind11; using namespace ipc; -void define_sweep(py::module_& m) +void define_sweep_and_tiniest_queue(py::module_& m) { py::class_(m, "CopyMeshBroadPhase"); @@ -47,6 +47,19 @@ void define_sweep(py::module_& m) py::arg("vertices_t0"), py::arg("vertices_t1"), py::arg("edges"), py::arg("faces"), py::arg("inflation_radius") = 0) .def("clear", &SweepAndTiniestQueue::clear, "Clear any built data.") + .def( + "detect_vertex_vertex_candidates", + [](SweepAndTiniestQueue& self) { + std::vector candidates; + self.detect_vertex_vertex_candidates(candidates); + return candidates; + }, + R"ipc_Qu8mg5v7( + Find the candidate vertex-vertex collisions. + + Returns: + The candidate vertex-vertex collisions. + )ipc_Qu8mg5v7") .def( "detect_edge_vertex_candidates", [](SweepAndTiniestQueue& self) { @@ -55,10 +68,10 @@ void define_sweep(py::module_& m) return candidates; }, R"ipc_Qu8mg5v7( - Find the candidate edge-vertex collisisons. + Find the candidate edge-vertex collisions. Returns: - The candidate edge-vertex collisisons. + The candidate edge-vertex collisions. )ipc_Qu8mg5v7") .def( "detect_edge_edge_candidates", @@ -71,7 +84,7 @@ void define_sweep(py::module_& m) Find the candidate edge-edge collisions. Returns: - The candidate edge-edge collisisons. + The candidate edge-edge collisions. )ipc_Qu8mg5v7") .def( "detect_face_vertex_candidates", @@ -84,7 +97,7 @@ void define_sweep(py::module_& m) Find the candidate face-vertex collisions. Returns: - The candidate face-vertex collisisons. + The candidate face-vertex collisions. )ipc_Qu8mg5v7") .def( "detect_edge_face_candidates", @@ -140,6 +153,19 @@ void define_sweep(py::module_& m) py::arg("vertices_t0"), py::arg("vertices_t1"), py::arg("edges"), py::arg("faces"), py::arg("inflation_radius") = 0) .def("clear", &SweepAndTiniestQueueGPU::clear, "Clear any built data.") + .def( + "detect_vertex_vertex_candidates", + [](SweepAndTiniestQueueGPU& self) { + std::vector candidates; + self.detect_vertex_vertex_candidates(candidates); + return candidates; + }, + R"ipc_Qu8mg5v7( + Find the candidate vertex-vertex collisions. + + Returns: + The candidate vertex-vertex collisions. + )ipc_Qu8mg5v7") .def( "detect_edge_vertex_candidates", [](SweepAndTiniestQueueGPU& self) { @@ -148,10 +174,10 @@ void define_sweep(py::module_& m) return candidates; }, R"ipc_Qu8mg5v7( - Find the candidate edge-vertex collisisons. + Find the candidate edge-vertex collisions. Returns: - The candidate edge-vertex collisisons. + The candidate edge-vertex collisions. )ipc_Qu8mg5v7") .def( "detect_edge_edge_candidates", @@ -164,7 +190,7 @@ void define_sweep(py::module_& m) Find the candidate edge-edge collisions. Returns: - The candidate edge-edge collisisons. + The candidate edge-edge collisions. )ipc_Qu8mg5v7") .def( "detect_face_vertex_candidates", @@ -177,7 +203,7 @@ void define_sweep(py::module_& m) Find the candidate face-vertex collisions. Returns: - The candidate face-vertex collisisons. + The candidate face-vertex collisions. )ipc_Qu8mg5v7") .def( "detect_edge_face_candidates", diff --git a/python/src/broad_phase/voxel_size_heuristic.cpp b/python/src/broad_phase/voxel_size_heuristic.cpp index 3a1d9726f..40b779da4 100644 --- a/python/src/broad_phase/voxel_size_heuristic.cpp +++ b/python/src/broad_phase/voxel_size_heuristic.cpp @@ -10,17 +10,16 @@ void define_voxel_size_heuristic(py::module_& m) m.def( "suggest_good_voxel_size", py::overload_cast< - const Eigen::MatrixXd&, const Eigen::MatrixXi&, double>( + const Eigen::MatrixXd&, const Eigen::MatrixXi&, const double>( &suggest_good_voxel_size), - "", py::arg("vertices"), py::arg("edges"), - py::arg("inflation_radius") = 0); + py::arg("vertices"), py::arg("edges"), py::arg("inflation_radius") = 0); m.def( "suggest_good_voxel_size", py::overload_cast< const Eigen::MatrixXd&, const Eigen::MatrixXd&, - const Eigen::MatrixXi&, double>(&suggest_good_voxel_size), - "", py::arg("vertices_t0"), py::arg("vertices_t1"), py::arg("edges"), + const Eigen::MatrixXi&, const double>(&suggest_good_voxel_size), + py::arg("vertices_t0"), py::arg("vertices_t1"), py::arg("edges"), py::arg("inflation_radius") = 0); m.def( diff --git a/python/src/candidates/candidates.cpp b/python/src/candidates/candidates.cpp index 82549e3df..5021fff31 100644 --- a/python/src/candidates/candidates.cpp +++ b/python/src/candidates/candidates.cpp @@ -8,7 +8,7 @@ using namespace ipc; void define_candidates(py::module_& m) { py::class_(m, "Candidates") - .def(py::init(), "") + .def(py::init()) .def( "build", py::overload_cast< @@ -48,9 +48,9 @@ void define_candidates(py::module_& m) py::arg("mesh"), py::arg("vertices_t0"), py::arg("vertices_t1"), py::arg("inflation_radius") = 0, py::arg("broad_phase_method") = DEFAULT_BROAD_PHASE_METHOD) - .def("__len__", &Candidates::size, "") - .def("empty", &Candidates::empty, "") - .def("clear", &Candidates::clear, "") + .def("__len__", &Candidates::size) + .def("empty", &Candidates::empty) + .def("clear", &Candidates::clear) .def( "__getitem__", [](Candidates& self, size_t idx) -> ContinuousCollisionCandidate& { @@ -98,7 +98,7 @@ void define_candidates(py::module_& m) max_iterations: The maximum number of iterations for the CCD algorithm. Returns: - A step-size $\in [0, 1]$ that is collision free. A value of 1.0 if a full step and 0.0 is no step. + A step-size :math:`\in [0, 1]` that is collision free. A value of 1.0 if a full step and 0.0 is no step. )ipc_Qu8mg5v7", py::arg("mesh"), py::arg("vertices_t0"), py::arg("vertices_t1"), py::arg("min_distance") = 0.0, @@ -137,9 +137,10 @@ void define_candidates(py::module_& m) py::arg("tolerance") = DEFAULT_CCD_TOLERANCE, py::arg("max_iterations") = DEFAULT_CCD_MAX_ITERATIONS) .def( - "save_obj", &Candidates::save_obj, "", py::arg("filename"), + "save_obj", &Candidates::save_obj, py::arg("filename"), py::arg("vertices"), py::arg("edges"), py::arg("faces")) - .def_readwrite("ev_candidates", &Candidates::ev_candidates, "") - .def_readwrite("ee_candidates", &Candidates::ee_candidates, "") - .def_readwrite("fv_candidates", &Candidates::fv_candidates, ""); + .def_readwrite("vv_candidates", &Candidates::vv_candidates) + .def_readwrite("ev_candidates", &Candidates::ev_candidates) + .def_readwrite("ee_candidates", &Candidates::ee_candidates) + .def_readwrite("fv_candidates", &Candidates::fv_candidates); } diff --git a/python/src/candidates/continuous_collision_candidate.cpp b/python/src/candidates/continuous_collision_candidate.cpp index 3f75cf7b9..bb656243c 100644 --- a/python/src/candidates/continuous_collision_candidate.cpp +++ b/python/src/candidates/continuous_collision_candidate.cpp @@ -59,6 +59,15 @@ void define_continuous_collision_candidate(py::module_& m) self.write_ccd_query( std::cout, vertices_t0, vertices_t1, edges, faces); }, - "", py::arg("vertices_t0"), py::arg("vertices_t1"), - py::arg("edges"), py::arg("faces")); + R"ipc_Qu8mg5v7( + Print the CCD query to cout. + + Parameters: + vertices_t0: Mesh vertices at the start of the time step. + vertices_t1: Mesh vertices at the end of the time step. + edges: Collision mesh edges as rows of indicies into vertices. + faces: Collision mesh triangular faces as rows of indicies into vertices. + )ipc_Qu8mg5v7", + py::arg("vertices_t0"), py::arg("vertices_t1"), py::arg("edges"), + py::arg("faces")); } diff --git a/python/src/candidates/edge_edge.cpp b/python/src/candidates/edge_edge.cpp index 6d46b98a8..dd191dea4 100644 --- a/python/src/candidates/edge_edge.cpp +++ b/python/src/candidates/edge_edge.cpp @@ -10,9 +10,7 @@ void define_edge_edge_candidate(py::module_& m) py::class_< EdgeEdgeCandidate, CollisionStencil, ContinuousCollisionCandidate>( m, "EdgeEdgeCandidate") - .def( - py::init(), "", py::arg("edge0_id"), - py::arg("edge1_id")) + .def(py::init(), py::arg("edge0_id"), py::arg("edge1_id")) .def( "__str__", [](const EdgeEdgeCandidate& ev) { @@ -24,67 +22,17 @@ void define_edge_edge_candidate(py::module_& m) return fmt::format( "EdgeEdgeCandidate({:d}, {:d})", ev.edge0_id, ev.edge1_id); }) - .def("num_vertices", &EdgeEdgeCandidate::num_vertices, "") + .def("num_vertices", &EdgeEdgeCandidate::num_vertices) .def( - "vertex_ids", &EdgeEdgeCandidate::vertex_ids, "", py::arg("edges"), + "vertex_ids", &EdgeEdgeCandidate::vertex_ids, py::arg("edges"), py::arg("faces")) - .def( - "ccd", - [](EdgeEdgeCandidate& self, const Eigen::MatrixXd& vertices_t0, - const Eigen::MatrixXd& vertices_t1, const Eigen::MatrixXi& edges, - const Eigen::MatrixXi& faces, const double min_distance = 0.0, - const double tmax = 1.0, - const double tolerance = DEFAULT_CCD_TOLERANCE, - const long max_iterations = DEFAULT_CCD_MAX_ITERATIONS, - const double conservative_rescaling = - DEFAULT_CCD_CONSERVATIVE_RESCALING) { - double toi; - bool r = self.ccd( - vertices_t0, vertices_t1, edges, faces, toi, min_distance, - tmax, tolerance, max_iterations, conservative_rescaling); - return std::make_tuple(r, toi); - }, - R"ipc_Qu8mg5v7( - Perform narrow-phase CCD on the candidate. - - Parameters: - vertices_t0: Mesh vertices at the start of the time step. - vertices_t1: Mesh vertices at the end of the time step. - edges: Collision mesh edges as rows of indicies into vertices. - faces: Collision mesh triangular faces as rows of indicies into vertices. - tmax: Maximum time (normalized) to look for collisions. Should be in [0, 1]. - tolerance: CCD tolerance used by Tight-Inclusion CCD. - max_iterations: Maximum iterations used by Tight-Inclusion CCD. - conservative_rescaling: Conservative rescaling value used to avoid taking steps exactly to impact. - - Returns: - Tuple of: - If the candidate had a collision over the time interval. - Computed time of impact (normalized). - )ipc_Qu8mg5v7", - py::arg("vertices_t0"), py::arg("vertices_t1"), py::arg("edges"), - py::arg("faces"), py::arg("min_distance") = 0.0, - py::arg("tmax") = 1.0, py::arg("tolerance") = DEFAULT_CCD_TOLERANCE, - py::arg("max_iterations") = DEFAULT_CCD_MAX_ITERATIONS, - py::arg("conservative_rescaling") = - DEFAULT_CCD_CONSERVATIVE_RESCALING) - .def( - "print_ccd_query", - [](EdgeEdgeCandidate& self, const Eigen::MatrixXd& vertices_t0, - const Eigen::MatrixXd& vertices_t1, const Eigen::MatrixXi& edges, - const Eigen::MatrixXi& faces) -> void { - self.write_ccd_query( - std::cout, vertices_t0, vertices_t1, edges, faces); - }, - "", py::arg("vertices_t0"), py::arg("vertices_t1"), - py::arg("edges"), py::arg("faces")) - .def("__eq__", &EdgeEdgeCandidate::operator==, "", py::arg("other")) - .def("__ne__", &EdgeEdgeCandidate::operator!=, "", py::arg("other")) + .def("__eq__", &EdgeEdgeCandidate::operator==, py::arg("other")) + .def("__ne__", &EdgeEdgeCandidate::operator!=, py::arg("other")) .def( "__lt__", &EdgeEdgeCandidate::operator<, "Compare EdgeEdgeCandidates for sorting.", py::arg("other")) .def_readwrite( - "edge0_id", &EdgeEdgeCandidate::edge0_id, "ID of the first edge") + "edge0_id", &EdgeEdgeCandidate::edge0_id, "ID of the first edge.") .def_readwrite( - "edge1_id", &EdgeEdgeCandidate::edge1_id, "ID of the second edge"); + "edge1_id", &EdgeEdgeCandidate::edge1_id, "ID of the second edge."); } diff --git a/python/src/candidates/edge_face.cpp b/python/src/candidates/edge_face.cpp index 992172f72..daf69ca97 100644 --- a/python/src/candidates/edge_face.cpp +++ b/python/src/candidates/edge_face.cpp @@ -8,7 +8,7 @@ using namespace ipc; void define_edge_face_candidate(py::module_& m) { py::class_(m, "EdgeFaceCandidate") - .def(py::init(), "", py::arg("edge_id"), py::arg("face_id")) + .def(py::init(), py::arg("edge_id"), py::arg("face_id")) .def( "__str__", [](const EdgeFaceCandidate& ev) { @@ -20,8 +20,8 @@ void define_edge_face_candidate(py::module_& m) return fmt::format( "EdgeFaceCandidate({:d}, {:d})", ev.edge_id, ev.face_id); }) - .def("__eq__", &EdgeFaceCandidate::operator==, "", py::arg("other")) - .def("__ne__", &EdgeFaceCandidate::operator!=, "", py::arg("other")) + .def("__eq__", &EdgeFaceCandidate::operator==, py::arg("other")) + .def("__ne__", &EdgeFaceCandidate::operator!=, py::arg("other")) .def( "__lt__", &EdgeFaceCandidate::operator<, "Compare EdgeFaceCandidate for sorting.", py::arg("other")) diff --git a/python/src/candidates/edge_vertex.cpp b/python/src/candidates/edge_vertex.cpp index 17ee2d762..82e64b9f1 100644 --- a/python/src/candidates/edge_vertex.cpp +++ b/python/src/candidates/edge_vertex.cpp @@ -10,9 +10,7 @@ void define_edge_vertex_candidate(py::module_& m) py::class_< EdgeVertexCandidate, CollisionStencil, ContinuousCollisionCandidate>( m, "EdgeVertexCandidate") - .def( - py::init(), "", py::arg("edge_id"), - py::arg("vertex_id")) + .def(py::init(), py::arg("edge_id"), py::arg("vertex_id")) .def( "__str__", [](const EdgeVertexCandidate& ev) { @@ -25,50 +23,10 @@ void define_edge_vertex_candidate(py::module_& m) "EdgeVertexCandidate({:d}, {:d})", ev.edge_id, ev.vertex_id); }) - .def("num_vertices", &EdgeVertexCandidate::num_vertices, "") + .def("num_vertices", &EdgeVertexCandidate::num_vertices) .def( - "vertex_ids", &EdgeVertexCandidate::vertex_ids, "", - py::arg("edges"), py::arg("faces")) - .def( - "ccd", - [](EdgeVertexCandidate& self, const Eigen::MatrixXd& vertices_t0, - const Eigen::MatrixXd& vertices_t1, const Eigen::MatrixXi& edges, - const Eigen::MatrixXi& faces, const double min_distance = 0.0, - const double tmax = 1.0, - const double tolerance = DEFAULT_CCD_TOLERANCE, - const long max_iterations = DEFAULT_CCD_MAX_ITERATIONS, - const double conservative_rescaling = - DEFAULT_CCD_CONSERVATIVE_RESCALING) { - double toi; - bool r = self.ccd( - vertices_t0, vertices_t1, edges, faces, toi, min_distance, - tmax, tolerance, max_iterations, conservative_rescaling); - return std::make_tuple(r, toi); - }, - R"ipc_Qu8mg5v7( - Perform narrow-phase CCD on the candidate. - - Parameters: - vertices_t0: Mesh vertices at the start of the time step. - vertices_t1: Mesh vertices at the end of the time step. - edges: Collision mesh edges as rows of indicies into vertices. - faces: Collision mesh triangular faces as rows of indicies into vertices. - tmax: Maximum time (normalized) to look for collisions. Should be in [0, 1]. - tolerance: CCD tolerance used by Tight-Inclusion CCD. - max_iterations: Maximum iterations used by Tight-Inclusion CCD. - conservative_rescaling: Conservative rescaling value used to avoid taking steps exactly to impact. - - Returns: - Tuple of: - If the candidate had a collision over the time interval. - Computed time of impact (normalized). - )ipc_Qu8mg5v7", - py::arg("vertices_t0"), py::arg("vertices_t1"), py::arg("edges"), - py::arg("faces"), py::arg("min_distance") = 0.0, - py::arg("tmax") = 1.0, py::arg("tolerance") = DEFAULT_CCD_TOLERANCE, - py::arg("max_iterations") = DEFAULT_CCD_MAX_ITERATIONS, - py::arg("conservative_rescaling") = - DEFAULT_CCD_CONSERVATIVE_RESCALING) + "vertex_ids", &EdgeVertexCandidate::vertex_ids, py::arg("edges"), + py::arg("faces")) .def( "print_ccd_query", [](EdgeVertexCandidate& self, const Eigen::MatrixXd& vertices_t0, @@ -77,10 +35,10 @@ void define_edge_vertex_candidate(py::module_& m) self.write_ccd_query( std::cout, vertices_t0, vertices_t1, edges, faces); }, - "", py::arg("vertices_t0"), py::arg("vertices_t1"), - py::arg("edges"), py::arg("faces")) - .def("__eq__", &EdgeVertexCandidate::operator==, "", py::arg("other")) - .def("__ne__", &EdgeVertexCandidate::operator!=, "", py::arg("other")) + py::arg("vertices_t0"), py::arg("vertices_t1"), py::arg("edges"), + py::arg("faces")) + .def("__eq__", &EdgeVertexCandidate::operator==, py::arg("other")) + .def("__ne__", &EdgeVertexCandidate::operator!=, py::arg("other")) .def( "__lt__", &EdgeVertexCandidate::operator<, "Compare EdgeVertexCandidates for sorting.", py::arg("other")) diff --git a/python/src/candidates/face_vertex.cpp b/python/src/candidates/face_vertex.cpp index 18adfe534..2b6fd6ec7 100644 --- a/python/src/candidates/face_vertex.cpp +++ b/python/src/candidates/face_vertex.cpp @@ -10,9 +10,7 @@ void define_face_vertex_candidate(py::module_& m) py::class_< FaceVertexCandidate, CollisionStencil, ContinuousCollisionCandidate>( m, "FaceVertexCandidate") - .def( - py::init(), "", py::arg("face_id"), - py::arg("vertex_id")) + .def(py::init(), py::arg("face_id"), py::arg("vertex_id")) .def( "__str__", [](const FaceVertexCandidate& ev) { @@ -25,32 +23,10 @@ void define_face_vertex_candidate(py::module_& m) "FaceVertexCandidate({:d}, {:d})", ev.face_id, ev.vertex_id); }) - .def("num_vertices", &FaceVertexCandidate::num_vertices, "") - .def( - "vertex_ids", &FaceVertexCandidate::vertex_ids, "", - py::arg("edges"), py::arg("faces")) + .def("num_vertices", &FaceVertexCandidate::num_vertices) .def( - "ccd", - [](FaceVertexCandidate& self, const Eigen::MatrixXd& vertices_t0, - const Eigen::MatrixXd& vertices_t1, const Eigen::MatrixXi& edges, - const Eigen::MatrixXi& faces, const double min_distance = 0.0, - const double tmax = 1.0, - const double tolerance = DEFAULT_CCD_TOLERANCE, - const long max_iterations = DEFAULT_CCD_MAX_ITERATIONS, - const double conservative_rescaling = - DEFAULT_CCD_CONSERVATIVE_RESCALING) { - double toi; - bool r = self.ccd( - vertices_t0, vertices_t1, edges, faces, toi, min_distance, - tmax, tolerance, max_iterations, conservative_rescaling); - return std::make_tuple(r, toi); - }, - "", py::arg("vertices_t0"), py::arg("vertices_t1"), - py::arg("edges"), py::arg("faces"), py::arg("min_distance") = 0.0, - py::arg("tmax") = 1.0, py::arg("tolerance") = DEFAULT_CCD_TOLERANCE, - py::arg("max_iterations") = DEFAULT_CCD_MAX_ITERATIONS, - py::arg("conservative_rescaling") = - DEFAULT_CCD_CONSERVATIVE_RESCALING) + "vertex_ids", &FaceVertexCandidate::vertex_ids, py::arg("edges"), + py::arg("faces")) .def( "print_ccd_query", [](FaceVertexCandidate& self, const Eigen::MatrixXd& vertices_t0, @@ -59,10 +35,10 @@ void define_face_vertex_candidate(py::module_& m) self.write_ccd_query( std::cout, vertices_t0, vertices_t1, edges, faces); }, - "", py::arg("vertices_t0"), py::arg("vertices_t1"), - py::arg("edges"), py::arg("faces")) - .def("__eq__", &FaceVertexCandidate::operator==, "", py::arg("other")) - .def("__ne__", &FaceVertexCandidate::operator!=, "", py::arg("other")) + py::arg("vertices_t0"), py::arg("vertices_t1"), py::arg("edges"), + py::arg("faces")) + .def("__eq__", &FaceVertexCandidate::operator==, py::arg("other")) + .def("__ne__", &FaceVertexCandidate::operator!=, py::arg("other")) .def( "__lt__", &FaceVertexCandidate::operator<, "Compare FaceVertexCandidate for sorting.", py::arg("other")) diff --git a/python/src/candidates/vertex_vertex.cpp b/python/src/candidates/vertex_vertex.cpp index 7c8f34263..dcd59da47 100644 --- a/python/src/candidates/vertex_vertex.cpp +++ b/python/src/candidates/vertex_vertex.cpp @@ -7,10 +7,11 @@ using namespace ipc; void define_vertex_vertex_candidate(py::module_& m) { - py::class_( + py::class_< + VertexVertexCandidate, CollisionStencil, ContinuousCollisionCandidate>( m, "VertexVertexCandidate") .def( - py::init(), "", py::arg("vertex0_id"), + py::init(), py::arg("vertex0_id"), py::arg("vertex1_id")) .def( "__str__", @@ -25,7 +26,7 @@ void define_vertex_vertex_candidate(py::module_& m) "VertexVertexCandidate({:d}, {:d})", ev.vertex0_id, ev.vertex1_id); }) - .def("num_vertices", &VertexVertexCandidate::num_vertices, "") + .def("num_vertices", &VertexVertexCandidate::num_vertices) .def( "vertex_ids", &VertexVertexCandidate::vertex_ids, R"ipc_Qu8mg5v7( @@ -39,8 +40,18 @@ void define_vertex_vertex_candidate(py::module_& m) List of vertex indices )ipc_Qu8mg5v7", py::arg("edges"), py::arg("faces")) - .def("__eq__", &VertexVertexCandidate::operator==, "", py::arg("other")) - .def("__ne__", &VertexVertexCandidate::operator!=, "", py::arg("other")) + .def( + "print_ccd_query", + [](VertexVertexCandidate& self, const Eigen::MatrixXd& vertices_t0, + const Eigen::MatrixXd& vertices_t1, const Eigen::MatrixXi& edges, + const Eigen::MatrixXi& faces) { + self.write_ccd_query( + std::cout, vertices_t0, vertices_t1, edges, faces); + }, + py::arg("vertices_t0"), py::arg("vertices_t1"), py::arg("edges"), + py::arg("faces")) + .def("__eq__", &VertexVertexCandidate::operator==, py::arg("other")) + .def("__ne__", &VertexVertexCandidate::operator!=, py::arg("other")) .def( "__lt__", &VertexVertexCandidate::operator<, "Compare EdgeVertexCandidates for sorting.", py::arg("other")) diff --git a/python/src/ccd/aabb.cpp b/python/src/ccd/aabb.cpp index 5f74fdf3a..3d1306727 100644 --- a/python/src/ccd/aabb.cpp +++ b/python/src/ccd/aabb.cpp @@ -8,36 +8,35 @@ using namespace ipc; void define_ccd_aabb(py::module_& m) { m.def( - "point_edge_aabb_cd", &point_edge_aabb_cd, "", py::arg("p"), - py::arg("e0"), py::arg("e1"), py::arg("dist")); + "point_edge_aabb_cd", &point_edge_aabb_cd, py::arg("p"), py::arg("e0"), + py::arg("e1"), py::arg("dist")); m.def( - "edge_edge_aabb_cd", &edge_edge_aabb_cd, "", py::arg("ea0"), - py::arg("ea1"), py::arg("eb0"), py::arg("eb1"), py::arg("dist")); + "edge_edge_aabb_cd", &edge_edge_aabb_cd, py::arg("ea0"), py::arg("ea1"), + py::arg("eb0"), py::arg("eb1"), py::arg("dist")); m.def( - "point_triangle_aabb_cd", &point_triangle_aabb_cd, "", py::arg("p"), + "point_triangle_aabb_cd", &point_triangle_aabb_cd, py::arg("p"), py::arg("t0"), py::arg("t1"), py::arg("t2"), py::arg("dist")); m.def( - "edge_triangle_aabb_cd", &edge_triangle_aabb_cd, "", py::arg("e0"), + "edge_triangle_aabb_cd", &edge_triangle_aabb_cd, py::arg("e0"), py::arg("e1"), py::arg("t0"), py::arg("t1"), py::arg("t2"), py::arg("dist")); m.def( - "point_edge_aabb_ccd", &point_edge_aabb_ccd, "", py::arg("p_t0"), + "point_edge_aabb_ccd", &point_edge_aabb_ccd, py::arg("p_t0"), py::arg("e0_t0"), py::arg("e1_t0"), py::arg("p_t1"), py::arg("e0_t1"), py::arg("e1_t1"), py::arg("dist")); m.def( - "edge_edge_aabb_ccd", &edge_edge_aabb_ccd, "", py::arg("ea0_t0"), + "edge_edge_aabb_ccd", &edge_edge_aabb_ccd, py::arg("ea0_t0"), py::arg("ea1_t0"), py::arg("eb0_t0"), py::arg("eb1_t0"), py::arg("ea0_t1"), py::arg("ea1_t1"), py::arg("eb0_t1"), py::arg("eb1_t1"), py::arg("dist")); m.def( - "point_triangle_aabb_ccd", &point_triangle_aabb_ccd, "", - py::arg("p_t0"), py::arg("t0_t0"), py::arg("t1_t0"), py::arg("t2_t0"), - py::arg("p_t1"), py::arg("t0_t1"), py::arg("t1_t1"), py::arg("t2_t1"), - py::arg("dist")); + "point_triangle_aabb_ccd", &point_triangle_aabb_ccd, py::arg("p_t0"), + py::arg("t0_t0"), py::arg("t1_t0"), py::arg("t2_t0"), py::arg("p_t1"), + py::arg("t0_t1"), py::arg("t1_t1"), py::arg("t2_t1"), py::arg("dist")); } diff --git a/python/src/ccd/additive_ccd.cpp b/python/src/ccd/additive_ccd.cpp index 885c85227..b431b7471 100644 --- a/python/src/ccd/additive_ccd.cpp +++ b/python/src/ccd/additive_ccd.cpp @@ -166,4 +166,37 @@ void define_additive_ccd(py::module_& m) py::arg("eb0_t1"), py::arg("eb1_t1"), py::arg("min_distance") = 0.0, py::arg("tmax") = 1.0, py::arg("conservative_rescaling") = DEFAULT_CCD_CONSERVATIVE_RESCALING); -} \ No newline at end of file + + m_accd.def( + "additive_ccd", + [](VectorMax12d x, const VectorMax12d& dx, + const std::function& distance_squared, + const double max_disp_mag, const double min_distance = 0.0, + const double tmax = 1.0, + const double conservative_rescaling = + DEFAULT_CCD_CONSERVATIVE_RESCALING) { + double toi; + bool r = ipc::additive_ccd::additive_ccd( + x, dx, distance_squared, max_disp_mag, toi, min_distance, tmax, + conservative_rescaling); + return std::make_tuple(r, toi); + }, + R"ipc_Qu8mg5v7( + Computes the time of impact between two objects using additive continuous collision detection. + + Parameters: + distance_squared: A function that computes the squared distance between the two objects at a given time. + min_distance: The minimum distance between the objects. + tmax: The maximum time to check for collisions. + conservative_rescaling: The amount to rescale the objects by to ensure conservative advancement. + + Returns: + Tuple of: + True if a collision was detected, false otherwise. + The time of impact between the two objects. + )ipc_Qu8mg5v7", + py::arg("x"), py::arg("dx"), py::arg("distance_squared"), + py::arg("max_disp_mag"), py::arg("min_distance") = 0.0, + py::arg("tmax") = 1.0, + py::arg("conservative_rescaling") = DEFAULT_CCD_CONSERVATIVE_RESCALING); +} diff --git a/python/src/ccd/bindings.hpp b/python/src/ccd/bindings.hpp index fb2398c57..3244a47e4 100644 --- a/python/src/ccd/bindings.hpp +++ b/python/src/ccd/bindings.hpp @@ -7,4 +7,5 @@ void define_ccd_aabb(py::module_& m); void define_ccd(py::module_& m); void define_additive_ccd(py::module_& m); void define_inexact_point_edge(py::module_& m); +void define_nonlinear_ccd(py::module_& m); void define_point_static_plane(py::module_& m); \ No newline at end of file diff --git a/python/src/ccd/ccd.cpp b/python/src/ccd/ccd.cpp index ab08bc678..5ad3bbc65 100644 --- a/python/src/ccd/ccd.cpp +++ b/python/src/ccd/ccd.cpp @@ -30,7 +30,7 @@ void define_ccd(py::module_& m) p1_t0: The initial position of the second point. p0_t1: The final position of the first point. p1_t1: The final position of the second point. - min_distance: The minimum distance between the objects. + min_distance: The minimum distance between the points. tmax: The maximum time to check for collisions. tolerance: The error tolerance for the time of impact. max_iterations: The maximum number of iterations to perform. @@ -109,7 +109,7 @@ void define_ccd(py::module_& m) return std::make_tuple(r, toi); }, R"ipc_Qu8mg5v7( - Computes the time of impact between two edges using continuous collision detection. + Computes the time of impact between two edges in 3D using continuous collision detection. Parameters: ea0_t0: The initial position of the first endpoint of the first edge. @@ -157,7 +157,7 @@ void define_ccd(py::module_& m) return std::make_tuple(r, toi); }, R"ipc_Qu8mg5v7( - Computes the time of impact between a point and a triangle using continuous collision detection. + Computes the time of impact between a point and a triangle in 3D using continuous collision detection. Parameters: p_t0: The initial position of the point. @@ -185,4 +185,55 @@ void define_ccd(py::module_& m) py::arg("tolerance") = DEFAULT_CCD_TOLERANCE, py::arg("max_iterations") = DEFAULT_CCD_MAX_ITERATIONS, py::arg("conservative_rescaling") = DEFAULT_CCD_CONSERVATIVE_RESCALING); + + m.def( + "ccd_strategy", + [](const std::function& ccd, + const long max_iterations, const double min_distance, + const double initial_distance, const double conservative_rescaling) { + double toi; + bool r = ccd_strategy( + ccd, max_iterations, min_distance, initial_distance, + conservative_rescaling, toi); + return std::make_tuple(r, toi); + }, + R"ipc_Qu8mg5v7( + Perform the CCD strategy outlined by Li et al. [2020]. + + Parameters: + ccd: The continuous collision detection function. + max_iterations: The maximum number of iterations to perform. + min_distance: The minimum distance between the objects. + initial_distance: The initial distance between the objects. + conservative_rescaling: The conservative rescaling of the time of impact. + + Returns: + Tuple of: + True if a collision was detected, false otherwise. + Output time of impact. + )ipc_Qu8mg5v7", + py::arg("ccd"), py::arg("max_iterations"), py::arg("min_distance"), + py::arg("initial_distance"), py::arg("conservative_rescaling")); + + m.def( + "check_initial_distance", + [](const double initial_distance, const double min_distance) { + double toi; + bool r = + check_initial_distance(initial_distance, min_distance, toi); + return std::make_tuple(r, toi); + }, + R"ipc_Qu8mg5v7( + Helper function to check if the initial distance is less than the minimum distance. + + Parameters: + initial_distance: The initial distance between the objects. + min_distance: The minimum distance between the objects. + + Returns: + Tuple of: + True if the initial distance is less than the minimum distance, false otherwise. + Set to 0 if the initial distance is less than the minimum distance. + )ipc_Qu8mg5v7", + py::arg("initial_distance"), py::arg("min_distance")); } diff --git a/python/src/ccd/inexact_point_edge.cpp b/python/src/ccd/inexact_point_edge.cpp index 402020c16..d6c02a345 100644 --- a/python/src/ccd/inexact_point_edge.cpp +++ b/python/src/ccd/inexact_point_edge.cpp @@ -19,7 +19,6 @@ void define_inexact_point_edge(py::module_& m) conservative_rescaling); return std::make_tuple(r, toi); }, - "", py::arg("p_t0"), py::arg("e0_t0"), py::arg("e1_t0"), - py::arg("p_t1"), py::arg("e0_t1"), py::arg("e1_t1"), - py::arg("conservative_rescaling")); + py::arg("p_t0"), py::arg("e0_t0"), py::arg("e1_t0"), py::arg("p_t1"), + py::arg("e0_t1"), py::arg("e1_t1"), py::arg("conservative_rescaling")); } diff --git a/python/src/ccd/nonlinear_ccd.cpp b/python/src/ccd/nonlinear_ccd.cpp new file mode 100644 index 000000000..db3ebcda0 --- /dev/null +++ b/python/src/ccd/nonlinear_ccd.cpp @@ -0,0 +1,247 @@ +#include + +#include + +namespace py = pybind11; +using namespace ipc; + +void define_nonlinear_ccd(py::module_& m) +{ + py::class_(m, "NonlinearTrajectory") + .def( + "__call__", &NonlinearTrajectory::operator(), + "Compute the point's position at time t", py::arg("t")) + .def( + "max_distance_from_linear", + &NonlinearTrajectory::max_distance_from_linear, + R"ipc_Qu8mg5v7( + Compute the maximum distance from the nonlinear trajectory to a linearized trajectory + + Note: + This uses interval arithmetic to compute the maximum distance. If you know a tighter bound on the maximum distance, it is recommended to override this function. + + Parameters: + t0: Start time of the trajectory + t1: End time of the trajectory + )ipc_Qu8mg5v7", + py::arg("t0"), py::arg("t1")); + +#ifdef IPC_TOOLKIT_WITH_FILIB + py::class_( + m, "IntervalNonlinearTrajectory") + .def( + "__call__", + [](const IntervalNonlinearTrajectory& self, const double t) { + return self(t); + }, + "Compute the point's position over a time interval t", py::arg("t")) + .def( + "max_distance_from_linear", + &IntervalNonlinearTrajectory::max_distance_from_linear, + R"ipc_Qu8mg5v7( + Compute the maximum distance from the nonlinear trajectory to a linearized trajectory + + Note: + This uses interval arithmetic to compute the maximum distance. If you know a tighter bound on the maximum distance, it is recommended to override this function. + + Parameters: + t0: Start time of the trajectory + t1: End time of the trajectory + )ipc_Qu8mg5v7", + py::arg("t0"), py::arg("t1")); +#endif + + m.def( + "point_point_nonlinear_ccd", + [](const NonlinearTrajectory& p0, const NonlinearTrajectory& p1, + const double tmax = 1.0, const double min_distance = 0, + const double tolerance = DEFAULT_CCD_TOLERANCE, + const long max_iterations = DEFAULT_CCD_MAX_ITERATIONS, + const double conservative_rescaling = + DEFAULT_CCD_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", + py::arg("p0"), py::arg("p1"), py::arg("tmax") = 1.0, + py::arg("min_distance") = 0, + py::arg("tolerance") = DEFAULT_CCD_TOLERANCE, + py::arg("max_iterations") = DEFAULT_CCD_MAX_ITERATIONS, + py::arg("conservative_rescaling") = DEFAULT_CCD_CONSERVATIVE_RESCALING); + + m.def( + "point_edge_nonlinear_ccd", + [](const NonlinearTrajectory& p, const NonlinearTrajectory& e0, + const NonlinearTrajectory& e1, const double tmax = 1.0, + const double min_distance = 0, + const double tolerance = DEFAULT_CCD_TOLERANCE, + const long max_iterations = DEFAULT_CCD_MAX_ITERATIONS, + const double conservative_rescaling = + DEFAULT_CCD_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", + py::arg("p"), py::arg("e0"), py::arg("e1"), py::arg("tmax") = 1.0, + py::arg("min_distance") = 0, + py::arg("tolerance") = DEFAULT_CCD_TOLERANCE, + py::arg("max_iterations") = DEFAULT_CCD_MAX_ITERATIONS, + py::arg("conservative_rescaling") = DEFAULT_CCD_CONSERVATIVE_RESCALING); + + m.def( + "edge_edge_nonlinear_ccd", + [](const NonlinearTrajectory& ea0, const NonlinearTrajectory& ea1, + const NonlinearTrajectory& eb0, const NonlinearTrajectory& eb1, + const double tmax = 1.0, const double min_distance = 0, + const double tolerance = DEFAULT_CCD_TOLERANCE, + const long max_iterations = DEFAULT_CCD_MAX_ITERATIONS, + const double conservative_rescaling = + DEFAULT_CCD_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", + py::arg("ea0"), py::arg("ea1"), py::arg("eb0"), py::arg("eb1"), + py::arg("tmax") = 1.0, py::arg("min_distance") = 0, + py::arg("tolerance") = DEFAULT_CCD_TOLERANCE, + py::arg("max_iterations") = DEFAULT_CCD_MAX_ITERATIONS, + py::arg("conservative_rescaling") = DEFAULT_CCD_CONSERVATIVE_RESCALING); + + m.def( + "point_triangle_nonlinear_ccd", + [](const NonlinearTrajectory& p, const NonlinearTrajectory& t0, + const NonlinearTrajectory& t1, const NonlinearTrajectory& t2, + const double tmax = 1.0, const double min_distance = 0, + const double tolerance = DEFAULT_CCD_TOLERANCE, + const long max_iterations = DEFAULT_CCD_MAX_ITERATIONS, + const double conservative_rescaling = + DEFAULT_CCD_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: + 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 + + Returns: + Tuple of: + True if the point and triangle collide, false otherwise. + Output time of impact + )ipc_Qu8mg5v7", + py::arg("p"), py::arg("t0"), py::arg("t1"), py::arg("t2"), + py::arg("tmax") = 1.0, py::arg("min_distance") = 0, + py::arg("tolerance") = DEFAULT_CCD_TOLERANCE, + py::arg("max_iterations") = DEFAULT_CCD_MAX_ITERATIONS, + py::arg("conservative_rescaling") = DEFAULT_CCD_CONSERVATIVE_RESCALING); + + 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 = 1.0, const double min_distance = 0, + const double conservative_rescaling = + DEFAULT_CCD_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: + 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: + + Output time of impact. + )ipc_Qu8mg5v7", + py::arg("distance"), py::arg("max_distance_from_linear"), + py::arg("linear_ccd"), py::arg("tmax") = 1.0, + py::arg("min_distance") = 0, + py::arg("conservative_rescaling") = DEFAULT_CCD_CONSERVATIVE_RESCALING); +} diff --git a/python/src/ccd/point_static_plane.cpp b/python/src/ccd/point_static_plane.cpp index 1b914cb71..d108cc524 100644 --- a/python/src/ccd/point_static_plane.cpp +++ b/python/src/ccd/point_static_plane.cpp @@ -19,7 +19,7 @@ void define_point_static_plane(py::module_& m) conservative_rescaling); return std::make_tuple(r, toi); }, - "", py::arg("p_t0"), py::arg("p_t1"), py::arg("plane_origin"), + py::arg("p_t0"), py::arg("p_t1"), py::arg("plane_origin"), py::arg("plane_normal"), py::arg("conservative_rescaling") = DEFAULT_CCD_CONSERVATIVE_RESCALING); } diff --git a/python/src/collision_mesh.cpp b/python/src/collision_mesh.cpp index 36bbd9c4c..a6c797c12 100644 --- a/python/src/collision_mesh.cpp +++ b/python/src/collision_mesh.cpp @@ -47,7 +47,7 @@ void define_collision_mesh(py::module_& m) Helper function that automatically builds include_vertex using construct_is_on_surface. Parameters: - full_rest_positions: The full vertices at rest (#V × dim). + full_rest_positions: The full vertices at rest (#FV × dim). edges: The edge matrix of mesh (#E × 2). faces: The face matrix of mesh (#F × 3). @@ -64,13 +64,17 @@ void define_collision_mesh(py::module_& m) .def_property_readonly( "num_vertices", &CollisionMesh::num_vertices, "Get the number of vertices in the collision mesh.") + .def_property_readonly( + "num_codim_vertices", &CollisionMesh::num_codim_vertices, + "Get the number of codimensional vertices in the collision mesh.") .def_property_readonly( "num_edges", &CollisionMesh::num_edges, "Get the number of edges in the collision mesh.") .def_property_readonly( "num_faces", &CollisionMesh::num_faces, "Get the number of faces in the collision mesh.") - .def("dim", &CollisionMesh::dim, "Get the dimension of the mesh.") + .def_property_readonly( + "dim", &CollisionMesh::dim, "Get the dimension of the mesh.") .def_property_readonly( "ndof", &CollisionMesh::ndof, "Get the number of degrees of freedom in the collision mesh.") @@ -83,9 +87,12 @@ void define_collision_mesh(py::module_& m) .def_property_readonly( "rest_positions", &CollisionMesh::rest_positions, "Get the vertices of the collision mesh at rest (#V × dim).") + .def_property_readonly( + "codim_vertices", &CollisionMesh::codim_vertices, + "Get the indices of codimensional vertices of the collision mesh (#CV x 1).") .def_property_readonly( "edges", &CollisionMesh::edges, - "Get the edges of the collision mesh (#E × 2).") + "Get the edges of the collision mesh (#E × 2).") .def_property_readonly( "faces", &CollisionMesh::faces, "Get the faces of the collision mesh (#F × 3).") @@ -107,13 +114,13 @@ void define_collision_mesh(py::module_& m) .def( "displace_vertices", &CollisionMesh::displace_vertices, R"ipc_Qu8mg5v7( - Compute the vertex positions from vertex displacements on the full mesh (#FV × dim). + Compute the vertex positions from vertex displacements on the full mesh. Parameters: - full_displacements: The vertex displacements on the full mesh (#V × dim). + full_displacements: The vertex displacements on the full mesh (#FV × dim). Returns: - The vertex positions of the collision mesh. + The vertex positions of the collision mesh (#V × dim). )ipc_Qu8mg5v7", py::arg("full_displacements")) .def( @@ -122,10 +129,10 @@ void define_collision_mesh(py::module_& m) Map vertex displacements on the full mesh to vertex displacements on the collision mesh. Parameters: - full_displacements: The vertex displacements on the full mesh. + full_displacements: The vertex displacements on the full mesh (#FV × dim). Returns: - The vertex displacements on the collision mesh. + The vertex displacements on the collision mesh (#V × dim). )ipc_Qu8mg5v7", py::arg("full_displacements")) .def( @@ -176,6 +183,9 @@ void define_collision_mesh(py::module_& m) "vertex_vertex_adjacencies", &CollisionMesh::vertex_vertex_adjacencies, "Get the vertex-vertex adjacency matrix.") + .def_property_readonly( + "vertex_edge_adjacencies", &CollisionMesh::vertex_edge_adjacencies, + "Get the vertex-edge adjacency matrix.") .def_property_readonly( "edge_vertex_adjacencies", &CollisionMesh::edge_vertex_adjacencies, "Get the edge-vertex adjacency matrix.") @@ -217,13 +227,13 @@ void define_collision_mesh(py::module_& m) return self.vertex_area_gradient(vi); }, R"ipc_Qu8mg5v7( - Get the gradient of the barycentric area of a vertex wrt the rest - positions of all points. + Get the gradient of the barycentric area of a vertex wrt the rest positions of all points. + Parameters: vi: Vertex ID. + Returns: - Gradient of the barycentric area of vertex vi wrt the rest - positions of all points. + Gradient of the barycentric area of vertex vi wrt the rest positions of all points. )ipc_Qu8mg5v7", py::arg("vi")) .def( @@ -248,13 +258,13 @@ void define_collision_mesh(py::module_& m) return self.edge_area_gradient(ei); }, R"ipc_Qu8mg5v7( - Get the gradient of the barycentric area of an edge wrt the rest - positions of all points. + Get the gradient of the barycentric area of an edge wrt the rest positions of all points. + Parameters: ei: Edge ID. + Returns: - Gradient of the barycentric area of edge ei wrt the rest - positions of all points. + Gradient of the barycentric area of edge ei wrt the rest positions of all points. )ipc_Qu8mg5v7", py::arg("ei")) .def( @@ -269,6 +279,7 @@ void define_collision_mesh(py::module_& m) Parameters: num_vertices: The number of vertices in the mesh. edges: The surface edges of the mesh (#E × 2). + codim_vertices: The indices of codimensional vertices (#CV x 1). Returns: A vector of bools indicating whether each vertex is on the surface. @@ -293,7 +304,7 @@ void define_collision_mesh(py::module_& m) "can_collide", &CollisionMesh::can_collide, R"ipc_Qu8mg5v7( A function that takes two vertex IDs and returns true if the vertices - (and faces or edges containing the vertices) can collide. By default all - primitives can collide with all other primitives. +(and faces or edges containing the vertices) can collide. By default all +primitives can collide with all other primitives. )ipc_Qu8mg5v7"); } diff --git a/python/src/collisions/collision_constraint.cpp b/python/src/collisions/collision_constraint.cpp index 5155e6dd5..e2d31ff83 100644 --- a/python/src/collisions/collision_constraint.cpp +++ b/python/src/collisions/collision_constraint.cpp @@ -9,21 +9,21 @@ void define_collision_constraint(py::module_& m) { py::class_(m, "CollisionConstraint") .def( - "compute_potential", &CollisionConstraint::compute_potential, "", + "compute_potential", &CollisionConstraint::compute_potential, py::arg("vertices"), py::arg("edges"), py::arg("faces"), py::arg("dhat")) .def( "compute_potential_gradient", - &CollisionConstraint::compute_potential_gradient, "", + &CollisionConstraint::compute_potential_gradient, py::arg("vertices"), py::arg("edges"), py::arg("faces"), py::arg("dhat")) .def( "compute_potential_hessian", - &CollisionConstraint::compute_potential_hessian, "", + &CollisionConstraint::compute_potential_hessian, py::arg("vertices"), py::arg("edges"), py::arg("faces"), py::arg("dhat"), py::arg("project_hessian_to_psd")) - .def_readwrite("dmin", &CollisionConstraint::dmin, "") - .def_readwrite("weight", &CollisionConstraint::weight, "") + .def_readwrite("dmin", &CollisionConstraint::dmin) + .def_readwrite("weight", &CollisionConstraint::weight) .def_property( "weight_gradient", [](const CollisionConstraint& self) -> Eigen::SparseMatrix { @@ -33,6 +33,5 @@ void define_collision_constraint(py::module_& m) const Eigen::SparseMatrix& weight_gradient) { assert_is_sparse_vector(weight_gradient, "weight_gradient"); self.weight_gradient = weight_gradient; - }, - ""); + }); } diff --git a/python/src/collisions/collision_constraints.cpp b/python/src/collisions/collision_constraints.cpp index e8850ffb0..97e0646fd 100644 --- a/python/src/collisions/collision_constraints.cpp +++ b/python/src/collisions/collision_constraints.cpp @@ -8,7 +8,7 @@ using namespace ipc; void define_collision_constraints(py::module_& m) { py::class_(m, "CollisionConstraints") - .def(py::init(), "") + .def(py::init()) .def( "build", py::overload_cast< @@ -27,7 +27,7 @@ void define_collision_constraints(py::module_& m) )ipc_Qu8mg5v7", py::arg("mesh"), py::arg("vertices"), py::arg("dhat"), py::arg("dmin") = 0, - py::arg("broad_phase_method") = BroadPhaseMethod::HASH_GRID) + py::arg("broad_phase_method") = DEFAULT_BROAD_PHASE_METHOD) .def( "build", py::overload_cast< @@ -157,6 +157,9 @@ void define_collision_constraints(py::module_& m) &CollisionConstraints::are_shape_derivatives_enabled, &CollisionConstraints::set_are_shape_derivatives_enabled, "If the collision constraints are using the convergent formulation.") + .def( + "to_string", &CollisionConstraints::to_string, py::arg("mesh"), + py::arg("vertices")) .def_readwrite("vv_constraints", &CollisionConstraints::vv_constraints) .def_readwrite("ev_constraints", &CollisionConstraints::ev_constraints) .def_readwrite("ee_constraints", &CollisionConstraints::ee_constraints) diff --git a/python/src/collisions/edge_edge.cpp b/python/src/collisions/edge_edge.cpp index 2c8830dea..b138b281b 100644 --- a/python/src/collisions/edge_edge.cpp +++ b/python/src/collisions/edge_edge.cpp @@ -10,27 +10,50 @@ void define_edge_edge_constraint(py::module_& m) py::class_( m, "EdgeEdgeConstraint") .def( - py::init(), "", + py::init< + const long, const long, const double, + const EdgeEdgeDistanceType>(), py::arg("edge0_id"), py::arg("edge1_id"), py::arg("eps_x"), - py::arg("dtype") = ipc::EdgeEdgeDistanceType::AUTO) + py::arg("dtype") = EdgeEdgeDistanceType::AUTO) .def( py::init< - const EdgeEdgeCandidate&, double, ipc::EdgeEdgeDistanceType>(), - "", py::arg("candidate"), py::arg("eps_x"), - py::arg("dtype") = ipc::EdgeEdgeDistanceType::AUTO) + const EdgeEdgeCandidate&, const double, + const EdgeEdgeDistanceType>(), + py::arg("candidate"), py::arg("eps_x"), + py::arg("dtype") = EdgeEdgeDistanceType::AUTO) + // .def( + // py::init< + // const long, const long, const double, const double, + // const Eigen::SparseVector&, + // const EdgeEdgeDistanceType>(), + // py::arg("edge0_id"), py::arg("edge1_id"), py::arg("eps_x"), + // py::arg("weight"), py::arg("weight_gradient"), + // py::arg("dtype") = EdgeEdgeDistanceType::AUTO) .def( - "compute_potential", &EdgeEdgeConstraint::compute_potential, "", + "compute_potential", &EdgeEdgeConstraint::compute_potential, py::arg("vertices"), py::arg("edges"), py::arg("faces"), py::arg("dhat")) .def( "compute_potential_gradient", - &EdgeEdgeConstraint::compute_potential_gradient, "", + &EdgeEdgeConstraint::compute_potential_gradient, py::arg("vertices"), py::arg("edges"), py::arg("faces"), py::arg("dhat")) .def( "compute_potential_hessian", - &EdgeEdgeConstraint::compute_potential_hessian, "", - py::arg("vertices"), py::arg("edges"), py::arg("faces"), - py::arg("dhat"), py::arg("project_hessian_to_psd")) - .def_readwrite("eps_x", &EdgeEdgeConstraint::eps_x, ""); + &EdgeEdgeConstraint::compute_potential_hessian, py::arg("vertices"), + py::arg("edges"), py::arg("faces"), py::arg("dhat"), + py::arg("project_hessian_to_psd")) + .def("__eq__", &EdgeEdgeConstraint::operator==, py::arg("other")) + .def("__ne__", &EdgeEdgeConstraint::operator!=, py::arg("other")) + .def("__lt__", &EdgeEdgeConstraint::operator<, py::arg("other")) + .def_readwrite( + "eps_x", &EdgeEdgeConstraint::eps_x, + "Mollifier activation threshold.") + .def_readwrite( + "dtype", &EdgeEdgeConstraint::dtype, + R"ipc_Qu8mg5v7( + Cached distance type. + + Some EE constraints are mollified EV or VV constraints. + )ipc_Qu8mg5v7"); } diff --git a/python/src/collisions/edge_vertex.cpp b/python/src/collisions/edge_vertex.cpp index e635b0989..321f5498f 100644 --- a/python/src/collisions/edge_vertex.cpp +++ b/python/src/collisions/edge_vertex.cpp @@ -9,8 +9,12 @@ void define_edge_vertex_constraint(py::module_& m) { py::class_( m, "EdgeVertexConstraint") - .def( - py::init(), "", py::arg("edge_id"), - py::arg("vertex_id")) - .def(py::init(), "", py::arg("ev_candidate")); + .def(py::init(), py::arg("edge_id"), py::arg("vertex_id")) + .def(py::init(), py::arg("candidate")); + // .def( + // py::init< + // const long, const long, const double, + // const Eigen::SparseVector&>(), + // py::arg("edge_id"), py::arg("vertex_id"), py::arg("weight"), + // py::arg("weight_gradient")); } diff --git a/python/src/collisions/face_vertex.cpp b/python/src/collisions/face_vertex.cpp index 94028268b..29663530c 100644 --- a/python/src/collisions/face_vertex.cpp +++ b/python/src/collisions/face_vertex.cpp @@ -12,5 +12,11 @@ void define_face_vertex_constraint(py::module_& m) .def( py::init(), "", py::arg("face_id"), py::arg("vertex_id")) - .def(py::init(), "", py::arg("fv_candidate")); + .def(py::init(), py::arg("candidate")); + // .def( + // py::init< + // const long, const long, const double, + // const Eigen::SparseVector&>(), + // py::arg("face_id"), py::arg("vertex_id"), py::arg("weight"), + // py::arg("weight_gradient")); } diff --git a/python/src/collisions/plane_vertex.cpp b/python/src/collisions/plane_vertex.cpp index 5334ea4fb..2c4dc932b 100644 --- a/python/src/collisions/plane_vertex.cpp +++ b/python/src/collisions/plane_vertex.cpp @@ -10,14 +10,14 @@ void define_plane_vertex_constraint(py::module_& m) py::class_( m, "PlaneVertexConstraint") .def( - py::init(), "", + py::init(), py::arg("plane_origin"), py::arg("plane_normal"), py::arg("vertex_id")) - .def("num_vertices", &PlaneVertexConstraint::num_vertices, "") + .def("num_vertices", &PlaneVertexConstraint::num_vertices) .def( - "vertex_ids", &PlaneVertexConstraint::vertex_ids, "", - py::arg("edges"), py::arg("faces")) - .def_readwrite("plane_origin", &PlaneVertexConstraint::plane_origin, "") - .def_readwrite("plane_normal", &PlaneVertexConstraint::plane_normal, "") - .def_readwrite("vertex_id", &PlaneVertexConstraint::vertex_id, ""); + "vertex_ids", &PlaneVertexConstraint::vertex_ids, py::arg("edges"), + py::arg("faces")) + .def_readwrite("plane_origin", &PlaneVertexConstraint::plane_origin) + .def_readwrite("plane_normal", &PlaneVertexConstraint::plane_normal) + .def_readwrite("vertex_id", &PlaneVertexConstraint::vertex_id); } diff --git a/python/src/collisions/vertex_vertex.cpp b/python/src/collisions/vertex_vertex.cpp index d294e4967..7dccd0481 100644 --- a/python/src/collisions/vertex_vertex.cpp +++ b/python/src/collisions/vertex_vertex.cpp @@ -13,5 +13,11 @@ void define_vertex_vertex_constraint(py::module_& m) .def( py::init(), "", py::arg("vertex0_id"), py::arg("vertex1_id")) - .def(py::init(), "", py::arg("vv_candidate")); + .def(py::init(), py::arg("vv_candidate")); + // .def( + // py::init< + // const long, const long, const double, + // const Eigen::SparseVector&>(), + // py::arg("vertex0_id"), py::arg("vertex1_id"), py::arg("weight"), + // py::arg("weight_gradient")); } diff --git a/python/src/distance/distance_type.cpp b/python/src/distance/distance_type.cpp index b708dc2cf..ebd099870 100644 --- a/python/src/distance/distance_type.cpp +++ b/python/src/distance/distance_type.cpp @@ -92,9 +92,9 @@ void define_distance_type(py::module_& m) Determine the closest pair between a point and edge. Parameters: - p: point - e0: first vertex of the edge - e1: second vertex of the edge + p: The point. + e0: The first vertex of the edge. + e1: The second vertex of the edge. Returns: The distance type of the point-edge pair. @@ -107,10 +107,10 @@ void define_distance_type(py::module_& m) Determine the closest pair between a point and triangle. Parameters: - p: point - t0: first vertex of the triangle - t1: second vertex of the triangle - t2: third vertex of the triangle + p: The point. + t0: The first vertex of the triangle. + t1: The second vertex of the triangle. + t2: The third vertex of the triangle. Returns: The distance type of the point-triangle pair. @@ -123,10 +123,26 @@ void define_distance_type(py::module_& m) Determine the closest pair between two edges. Parameters: - ea0: first vertex of the first edge - ea1: second vertex of the first edge - eb0: first vertex of the second edge - eb1: second vertex of the second edge + ea0: The first vertex of the first edge. + ea1: The second vertex of the first edge. + eb0: The first vertex of the second edge. + eb1: The second vertex of the second edge. + + Returns: + The distance type of the edge-edge pair. + )ipc_Qu8mg5v7", + py::arg("ea0"), py::arg("ea1"), py::arg("eb0"), py::arg("eb1")); + + m.def( + "edge_edge_parallel_distance_type", &edge_edge_parallel_distance_type, + R"ipc_Qu8mg5v7( + Determine the closest pair between two parallel edges. + + Parameters: + ea0: The first vertex of the first edge. + ea1: The second vertex of the first edge. + eb0: The first vertex of the second edge. + eb1: The second vertex of the second edge. Returns: The distance type of the edge-edge pair. diff --git a/python/src/distance/edge_edge.cpp b/python/src/distance/edge_edge.cpp index 358396b24..eae03a89f 100644 --- a/python/src/distance/edge_edge.cpp +++ b/python/src/distance/edge_edge.cpp @@ -14,11 +14,11 @@ void define_edge_edge_distance(py::module_& m) Compute the distance between a two lines segments in 3D. Parameters: - ea0: first vertex of the first edge - ea1: second vertex of the first edge - eb0: first vertex of the second edge - eb1: second vertex of the second edge - dtype: (optional) edge-edge distance type to compute + ea0: The first vertex of the first edge. + ea1: The second vertex of the first edge. + eb0: The first vertex of the second edge. + eb1: The second vertex of the second edge. + dtype: The point edge distance type to compute. Returns: The distance between the two edges. @@ -35,11 +35,11 @@ void define_edge_edge_distance(py::module_& m) Compute the gradient of the distance between a two lines segments. Parameters: - ea0: first vertex of the first edge - ea1: second vertex of the first edge - eb0: first vertex of the second edge - eb1: second vertex of the second edge - dtype: (optional) point edge distance type to compute + ea0: The first vertex of the first edge. + ea1: The second vertex of the first edge. + eb0: The first vertex of the second edge. + eb1: The second vertex of the second edge. + dtype: The point edge distance type to compute. Returns: The gradient of the distance wrt ea0, ea1, eb0, and eb1. @@ -56,11 +56,11 @@ void define_edge_edge_distance(py::module_& m) Compute the hessian of the distance between a two lines segments. Parameters: - ea0: first vertex of the first edge - ea1: second vertex of the first edge - eb0: first vertex of the second edge - eb1: second vertex of the second edge - dtype: (optional) point edge distance type to compute + ea0: The first vertex of the first edge. + ea1: The second vertex of the first edge. + eb0: The first vertex of the second edge. + eb1: The second vertex of the second edge. + dtype: The point edge distance type to compute. Returns: The hessian of the distance wrt ea0, ea1, eb0, and eb1. diff --git a/python/src/distance/edge_edge_mollifier.cpp b/python/src/distance/edge_edge_mollifier.cpp index 315474d45..74029e54d 100644 --- a/python/src/distance/edge_edge_mollifier.cpp +++ b/python/src/distance/edge_edge_mollifier.cpp @@ -13,10 +13,10 @@ void define_edge_edge_mollifier(py::module_& m) Compute the squared norm of the edge-edge cross product. Parameters: - ea0: first vertex of the first edge - ea1: second vertex of the first edge - eb0: first vertex of the second edge - eb1: second vertex of the second edge + ea0: The first vertex of the first edge. + ea1: The second vertex of the first edge. + eb0: The first vertex of the second edge. + eb1: The second vertex of the second edge. Returns: The squared norm of the edge-edge cross product. @@ -35,10 +35,10 @@ void define_edge_edge_mollifier(py::module_& m) Compute the gradient of the squared norm of the edge cross product. Parameters: - ea0: first vertex of the first edge - ea1: second vertex of the first edge - eb0: first vertex of the second edge - eb1: second vertex of the second edge + ea0: The first vertex of the first edge. + ea1: The second vertex of the first edge. + eb0: The first vertex of the second edge. + eb1: The second vertex of the second edge. Returns: The gradient of the squared norm of the edge cross product wrt ea0, ea1, eb0, and eb1. @@ -57,10 +57,10 @@ void define_edge_edge_mollifier(py::module_& m) Compute the hessian of the squared norm of the edge cross product. Parameters: - ea0: first vertex of the first edge - ea1: second vertex of the first edge - eb0: first vertex of the second edge - eb1: second vertex of the second edge + ea0: The first vertex of the first edge. + ea1: The second vertex of the first edge. + eb0: The first vertex of the second edge. + eb1: The second vertex of the second edge. Returns: The hessian of the squared norm of the edge cross product wrt ea0, ea1, eb0, and eb1. @@ -74,8 +74,8 @@ void define_edge_edge_mollifier(py::module_& m) Mollifier function for edge-edge distance. Parameters: - x: squared norm of the edge-edge cross product - eps_x: mollifier activation threshold + x: Squared norm of the edge-edge cross product. + eps_x: Mollifier activation threshold. Returns: The mollifier coefficient to premultiply the edge-edge distance. @@ -90,8 +90,8 @@ void define_edge_edge_mollifier(py::module_& m) The gradient of the mollifier function for edge-edge distance. Parameters: - x: squared norm of the edge-edge cross product - eps_x: mollifier activation threshold + x: Squared norm of the edge-edge cross product. + eps_x: Mollifier activation threshold. Returns: The gradient of the mollifier function for edge-edge distance wrt x. @@ -106,8 +106,8 @@ void define_edge_edge_mollifier(py::module_& m) The hessian of the mollifier function for edge-edge distance. Parameters: - x: squared norm of the edge-edge cross product - eps_x: mollifier activation threshold + x: Squared norm of the edge-edge cross product. + eps_x: Mollifier activation threshold. Returns: The hessian of the mollifier function for edge-edge distance wrt x. @@ -128,11 +128,11 @@ void define_edge_edge_mollifier(py::module_& m) This helps smooth the non-smoothness at close to parallel edges. Parameters: - ea0: first vertex of the first edge - ea1: second vertex of the first edge - eb0: first vertex of the second edge - eb1: second vertex of the second edge - eps_x: mollifier activation threshold + ea0: The first vertex of the first edge. + ea1: The second vertex of the first edge. + eb0: The first vertex of the second edge. + eb1: The second vertex of the second edge. + eps_x: Mollifier activation threshold. Returns: The mollifier coefficient to premultiply the edge-edge distance. @@ -152,11 +152,11 @@ void define_edge_edge_mollifier(py::module_& m) Compute the gradient of the mollifier for the edge-edge distance. Parameters: - ea0: first vertex of the first edge - ea1: second vertex of the first edge - eb0: first vertex of the second edge - eb1: second vertex of the second edge - eps_x: mollifier activation threshold + ea0: The first vertex of the first edge. + ea1: The second vertex of the first edge. + eb0: The first vertex of the second edge. + eb1: The second vertex of the second edge. + eps_x: Mollifier activation threshold. Returns: The gradient of the mollifier. @@ -176,11 +176,11 @@ void define_edge_edge_mollifier(py::module_& m) Compute the hessian of the mollifier for the edge-edge distance. Parameters: - ea0: first vertex of the first edge - ea1: second vertex of the first edge - eb0: first vertex of the second edge - eb1: second vertex of the second edge - eps_x: mollifier activation threshold + ea0: The first vertex of the first edge. + ea1: The second vertex of the first edge. + eb0: The first vertex of the second edge. + eb1: The second vertex of the second edge. + eps_x: Mollifier activation threshold. Returns: The hessian of the mollifier. @@ -196,10 +196,10 @@ void define_edge_edge_mollifier(py::module_& m) This values is computed based on the edges at rest length. Parameters: - ea0_rest: rest position of the first vertex of the first edge - ea1_rest: rest position of the second vertex of the first edge - eb0_rest: rest position of the first vertex of the second edge - eb1_rest: rest position of the second vertex of the second edge + ea0_rest: The rest position of the first vertex of the first edge. + ea1_rest: The rest position of the second vertex of the first edge. + eb0_rest: The rest position of the first vertex of the second edge. + eb1_rest: The rest position of the second vertex of the second edge. Returns: Threshold for edge-edge mollification. diff --git a/python/src/distance/line_line.cpp b/python/src/distance/line_line.cpp index 1fe18e01d..2d8e51bcf 100644 --- a/python/src/distance/line_line.cpp +++ b/python/src/distance/line_line.cpp @@ -13,10 +13,10 @@ void define_line_line_distance(py::module_& m) Compute the distance between a two infinite lines in 3D. Parameters: - ea0: first vertex of the edge defining the first line - ea1: second vertex of the edge defining the first line - eb0: first vertex of the edge defining the second line - eb1: second vertex of the edge defining the second line + ea0: The first vertex of the edge defining the first line. + ea1: The second vertex of the edge defining the first line. + ea0: The first vertex of the edge defining the second line. + ea1: The second vertex of the edge defining the second line. Returns: The distance between the two lines. @@ -35,10 +35,10 @@ void define_line_line_distance(py::module_& m) Compute the gradient of the distance between a two lines in 3D. Parameters: - ea0: first vertex of the edge defining the first line - ea1: second vertex of the edge defining the first line - eb0: first vertex of the edge defining the second line - eb1: second vertex of the edge defining the second line + ea0: The first vertex of the edge defining the first line. + ea1: The second vertex of the edge defining the first line. + ea0: The first vertex of the edge defining the second line. + ea1: The second vertex of the edge defining the second line. Returns: The gradient of the distance wrt ea0, ea1, eb0, and eb1. @@ -57,10 +57,10 @@ void define_line_line_distance(py::module_& m) Compute the hessian of the distance between a two lines in 3D. Parameters: - ea0: first vertex of the edge defining the first line - ea1: second vertex of the edge defining the first line - eb0: first vertex of the edge defining the second line - eb1: second vertex of the edge defining the second line + ea0: The first vertex of the edge defining the first line. + ea1: The second vertex of the edge defining the first line. + ea0: The first vertex of the edge defining the second line. + ea1: The second vertex of the edge defining the second line. Returns: The hessian of the distance wrt ea0, ea1, eb0, and eb1. diff --git a/python/src/distance/point_edge.cpp b/python/src/distance/point_edge.cpp index cfae048bc..3f9eecb42 100644 --- a/python/src/distance/point_edge.cpp +++ b/python/src/distance/point_edge.cpp @@ -14,13 +14,13 @@ void define_point_edge_distance(py::module_& m) Compute the distance between a point and edge in 2D or 3D. Parameters: - p: point - e0: first vertex of the edge - e1: second vertex of the edge - dtype: (optional) point edge distance type to compute + p: The point. + e0: The first vertex of the edge. + e1: The second vertex of the edge. + dtype: The point edge distance type to compute. Returns: - The distance between the point and edge + The distance between the point and edge. Note: The distance is actually squared distance. @@ -34,13 +34,13 @@ void define_point_edge_distance(py::module_& m) Compute the gradient of the distance between a point and edge. Parameters: - p: point - e0: first vertex of the edge - e1: second vertex of the edge - dtype: (optional) point edge distance type to compute + p: The point. + e0: The first vertex of the edge. + e1: The second vertex of the edge. + dtype: The point edge distance type to compute. Returns: - The gradient of the distance wrt p, e0, and e1. + grad The gradient of the distance wrt p, e0, and e1. Note: The distance is actually squared distance. @@ -54,13 +54,13 @@ void define_point_edge_distance(py::module_& m) Compute the hessian of the distance between a point and edge. Parameters: - p: point - e0: first vertex of the edge - e1: second vertex of the edge - dtype: (optional) point edge distance type to compute + p: The point. + e0: The first vertex of the edge. + e1: The second vertex of the edge. + dtype: The point edge distance type to compute. Returns: - The hessian of the distance wrt p, e0, and e1. + hess The hessian of the distance wrt p, e0, and e1. Note: The distance is actually squared distance. diff --git a/python/src/distance/point_line.cpp b/python/src/distance/point_line.cpp index b530d6e93..c82cb932e 100644 --- a/python/src/distance/point_line.cpp +++ b/python/src/distance/point_line.cpp @@ -13,9 +13,9 @@ void define_point_line_distance(py::module_& m) Compute the distance between a point and line in 2D or 3D. Parameters: - p: point - e0: first vertex of the edge defining the line - e1: second vertex of the edge defining the line + p: The point. + e0: The first vertex of the edge defining the line. + e1: The second vertex of the edge defining the line. Returns: The distance between the point and line. @@ -31,9 +31,9 @@ void define_point_line_distance(py::module_& m) Compute the gradient of the distance between a point and line. Parameters: - p: point - e0: first vertex of the edge defining the line. - e1: second vertex of the edge defining the line. + p: The point. + e0: The first vertex of the edge defining the line. + e1: The second vertex of the edge defining the line. Returns: The gradient of the distance wrt p, e0, and e1. @@ -49,9 +49,9 @@ void define_point_line_distance(py::module_& m) Compute the hessian of the distance between a point and line. Parameters: - p: point - e0: first vertex of the edge defining the line - e1: second vertex of the edge defining the line + p: The point. + e0: The first vertex of the edge defining the line. + e1: The second vertex of the edge defining the line. Returns: The hessian of the distance wrt p, e0, and e1. diff --git a/python/src/distance/point_plane.cpp b/python/src/distance/point_plane.cpp index 23d6ae36b..dbe331efa 100644 --- a/python/src/distance/point_plane.cpp +++ b/python/src/distance/point_plane.cpp @@ -20,9 +20,9 @@ void define_point_plane_distance(py::module_& m) The distance is actually squared distance. Parameters: - p: point - origin: origin of the plane - normal: normal of the plane + p: The point. + origin: The origin of the plane. + normal: The normal of the plane. Returns: The distance between the point and plane. @@ -43,10 +43,10 @@ void define_point_plane_distance(py::module_& m) The distance is actually squared distance. Parameters: - p: point - t0: first vertex of the triangle - t1: second vertex of the triangle - t2: third vertex of the triangle + p: The point. + t0: The first vertex of the triangle. + t1: The second vertex of the triangle. + t2: The third vertex of the triangle. Returns: The distance between the point and plane. @@ -67,9 +67,9 @@ void define_point_plane_distance(py::module_& m) The distance is actually squared distance. Parameters: - p: point - origin: origin of the plane - normal: normal of the plane + p: The point. + origin: The origin of the plane. + normal: The normal of the plane. Returns: The gradient of the distance wrt p. @@ -91,10 +91,10 @@ void define_point_plane_distance(py::module_& m) The distance is actually squared distance. Parameters: - p: point - t0: first vertex of the triangle - t1: second vertex of the triangle - t2: third vertex of the triangle + p: The point. + t0: The first vertex of the triangle. + t1: The second vertex of the triangle. + t2: The third vertex of the triangle. Returns: The gradient of the distance wrt p, t0, t1, and t2. @@ -115,9 +115,9 @@ void define_point_plane_distance(py::module_& m) The distance is actually squared distance. Parameters: - p: point - origin: origin of the plane - normal: normal of the plane + p: The point. + origin: The origin of the plane. + normal: The normal of the plane. Returns: The hessian of the distance wrt p. @@ -139,10 +139,10 @@ void define_point_plane_distance(py::module_& m) The distance is actually squared distance. Parameters: - p: point - t0: first vertex of the triangle - t1: second vertex of the triangle - t2: third vertex of the triangle + p: The point. + t0: The first vertex of the triangle. + t1: The second vertex of the triangle. + t2: The third vertex of the triangle. Returns: The hessian of the distance wrt p, t0, t1, and t2. diff --git a/python/src/distance/point_point.cpp b/python/src/distance/point_point.cpp index 2672be153..e310466ec 100644 --- a/python/src/distance/point_point.cpp +++ b/python/src/distance/point_point.cpp @@ -14,11 +14,11 @@ void define_point_point_distance(py::module_& m) Compute the distance between two points. Parameters: - p0: first point - p1: second point + p0: The first point. + p1: The second point. Returns: - The distance between p0 and p1 + The distance between p0 and p1. Note: The distance is actually squared distance. @@ -31,8 +31,8 @@ void define_point_point_distance(py::module_& m) Compute the gradient of the distance between two points. Parameters: - p0: first point - p1: second point + p0: The first point. + p1: The second point. Returns: The gradient of the distance wrt p0 and p1. @@ -45,11 +45,11 @@ void define_point_point_distance(py::module_& m) m.def( "point_point_distance_hessian", &point_point_distance_hessian, R"ipc_Qu8mg5v7( - Compute the hessian of the distance between a point and point. + Compute the hessian of the distance between two points. Parameters: - p0: first point - p1: second point + p0: The first point. + p1: The second point. Returns: The hessian of the distance wrt p0 and p1. diff --git a/python/src/distance/point_triangle.cpp b/python/src/distance/point_triangle.cpp index eb9ccd20e..664851b1d 100644 --- a/python/src/distance/point_triangle.cpp +++ b/python/src/distance/point_triangle.cpp @@ -11,14 +11,14 @@ void define_point_triangle_distance(py::module_& m) m.def( "point_triangle_distance", &point_triangle_distance, R"ipc_Qu8mg5v7( - Compute the distance between a two lines segments in 3D. + Compute the distance between a points and a triangle. Parameters: - p : point. - t0: first vertex of the triangle. - t1: second vertex of the triangle. - t2: third vertex of the triangle. - dtype: (Optional) point-triangle distance type to compute + p: The point. + t0: The first vertex of the triangle. + t1: The second vertex of the triangle. + t2: The third vertex of the triangle. + dtype: The point-triangle distance type to compute. Returns: The distance between the point and triangle. @@ -32,17 +32,17 @@ void define_point_triangle_distance(py::module_& m) m.def( "point_triangle_distance_gradient", &point_triangle_distance_gradient, R"ipc_Qu8mg5v7( - Compute the gradient of the distance between a two lines segments. + Compute the gradient of the distance between a points and a triangle. Parameters: - p : point - t0: first vertex of the triangle - t1: second vertex of the triangle - t2: third vertex of the triangle - dtype: (optional) point-triangle distance type to compute + p: The point. + t0: The first vertex of the triangle. + t1: The second vertex of the triangle. + t2: The third vertex of the triangle. + dtype: The point-triangle distance type to compute. Returns: - The gradient of the distance wrt ea0, ea1, eb0, and eb1. + The gradient of the distance wrt p, t0, t1, and t2. Note: The distance is actually squared distance. @@ -53,17 +53,17 @@ void define_point_triangle_distance(py::module_& m) m.def( "point_triangle_distance_hessian", &point_triangle_distance_hessian, R"ipc_Qu8mg5v7( - Compute the hessian of the distance between a two lines segments. + Compute the hessian of the distance between a points and a triangle. Parameters: - p : point - t0: first vertex of the triangle - t1: second vertex of the triangle - t2: third vertex of the triangle - dtype: (optional) point-triangle distance type to compute + p: The point. + t0: The first vertex of the triangle. + t1: The second vertex of the triangle. + t2: The third vertex of the triangle. + dtype: The point-triangle distance type to compute. Returns: - The hessian of the distance wrt ea0, ea1, eb0, and eb1. + The hessian of the distance wrt p, t0, t1, and t2. Note: The distance is actually squared distance. diff --git a/python/src/friction/closest_point.cpp b/python/src/friction/closest_point.cpp index 71afda741..6f5a744da 100644 --- a/python/src/friction/closest_point.cpp +++ b/python/src/friction/closest_point.cpp @@ -15,7 +15,17 @@ void define_closest_point(py::module_& m) assert_2D_or_3D_vector(e1, "e1"); return point_edge_closest_point(p, e0, e1); }, - "", py::arg("p"), py::arg("e0"), py::arg("e1")); + py::arg("p"), py::arg("e0"), py::arg("e1")); + + m.def( + "point_edge_closest_point_jacobian", + [](const VectorMax3d& p, const VectorMax3d& e0, const VectorMax3d& e1) { + assert_2D_or_3D_vector(p, "p"); + assert_2D_or_3D_vector(e0, "e0"); + assert_2D_or_3D_vector(e1, "e1"); + return point_edge_closest_point_jacobian(p, e0, e1); + }, + py::arg("p"), py::arg("e0"), py::arg("e1")); m.def( "edge_edge_closest_point", @@ -26,6 +36,14 @@ void define_closest_point(py::module_& m) "Compute the barycentric coordinates of the closest points", py::arg("ea0"), py::arg("ea1"), py::arg("eb0"), py::arg("eb1")); + m.def( + "edge_edge_closest_point_jacobian", + [](const Eigen::Vector3d& ea0, const Eigen::Vector3d& ea1, + const Eigen::Vector3d& eb0, const Eigen::Vector3d& eb1) { + return edge_edge_closest_point_jacobian(ea0, ea1, eb0, eb1); + }, + py::arg("ea0"), py::arg("ea1"), py::arg("eb0"), py::arg("eb1")); + m.def( "point_triangle_closest_point", [](const Eigen::Vector3d& p, const Eigen::Vector3d& t0, @@ -35,29 +53,11 @@ void define_closest_point(py::module_& m) "Compute the barycentric coordinates of the closest point on the triangle.", py::arg("p"), py::arg("t0"), py::arg("t1"), py::arg("t2")); - m.def( - "point_edge_closest_point_jacobian", - [](const VectorMax3d& p, const VectorMax3d& e0, const VectorMax3d& e1) { - assert_2D_or_3D_vector(p, "p"); - assert_2D_or_3D_vector(e0, "e0"); - assert_2D_or_3D_vector(e1, "e1"); - return point_edge_closest_point_jacobian(p, e0, e1); - }, - "", py::arg("p"), py::arg("e0"), py::arg("e1")); - - m.def( - "edge_edge_closest_point_jacobian", - [](const Eigen::Vector3d& ea0, const Eigen::Vector3d& ea1, - const Eigen::Vector3d& eb0, const Eigen::Vector3d& eb1) { - return edge_edge_closest_point_jacobian(ea0, ea1, eb0, eb1); - }, - "", py::arg("ea0"), py::arg("ea1"), py::arg("eb0"), py::arg("eb1")); - m.def( "point_triangle_closest_point_jacobian", [](const Eigen::Vector3d& p, const Eigen::Vector3d& t0, const Eigen::Vector3d& t1, const Eigen::Vector3d& t2) { return point_triangle_closest_point_jacobian(p, t0, t1, t2); }, - "", py::arg("p"), py::arg("t0"), py::arg("t1"), py::arg("t2")); + py::arg("p"), py::arg("t0"), py::arg("t1"), py::arg("t2")); } diff --git a/python/src/friction/constraints/edge_edge.cpp b/python/src/friction/constraints/edge_edge.cpp index 54cce8307..667d73b90 100644 --- a/python/src/friction/constraints/edge_edge.cpp +++ b/python/src/friction/constraints/edge_edge.cpp @@ -10,12 +10,12 @@ void define_edge_edge_friction_constraint(py::module_& m) py::class_< EdgeEdgeFrictionConstraint, EdgeEdgeCandidate, FrictionConstraint>( m, "EdgeEdgeFrictionConstraint") - .def(py::init(), "", py::arg("constraint")) + .def(py::init(), py::arg("constraint")) .def( py::init< const EdgeEdgeConstraint&, const Eigen::MatrixXd&, const Eigen::MatrixXi&, const Eigen::MatrixXi&, const double, const double>(), - "", py::arg("constraint"), py::arg("vertices"), py::arg("edges"), + py::arg("constraint"), py::arg("vertices"), py::arg("edges"), py::arg("faces"), py::arg("dhat"), py::arg("barrier_stiffness")); } diff --git a/python/src/friction/constraints/edge_vertex.cpp b/python/src/friction/constraints/edge_vertex.cpp index c91d2c564..b26b22558 100644 --- a/python/src/friction/constraints/edge_vertex.cpp +++ b/python/src/friction/constraints/edge_vertex.cpp @@ -10,12 +10,12 @@ void define_edge_vertex_friction_constraint(py::module_& m) py::class_< EdgeVertexFrictionConstraint, EdgeVertexCandidate, FrictionConstraint>( m, "EdgeVertexFrictionConstraint") - .def(py::init(), "", py::arg("constraint")) + .def(py::init(), py::arg("constraint")) .def( py::init< const EdgeVertexConstraint&, const Eigen::MatrixXd&, const Eigen::MatrixXi&, const Eigen::MatrixXi&, const double, const double>(), - "", py::arg("constraint"), py::arg("vertices"), py::arg("edges"), + py::arg("constraint"), py::arg("vertices"), py::arg("edges"), py::arg("faces"), py::arg("dhat"), py::arg("barrier_stiffness")); } diff --git a/python/src/friction/constraints/face_vertex.cpp b/python/src/friction/constraints/face_vertex.cpp index 7abcddba7..9bbe47f87 100644 --- a/python/src/friction/constraints/face_vertex.cpp +++ b/python/src/friction/constraints/face_vertex.cpp @@ -10,12 +10,12 @@ void define_face_vertex_friction_constraint(py::module_& m) py::class_< FaceVertexFrictionConstraint, FaceVertexCandidate, FrictionConstraint>( m, "FaceVertexFrictionConstraint") - .def(py::init(), "", py::arg("constraint")) + .def(py::init(), py::arg("constraint")) .def( py::init< const FaceVertexConstraint&, const Eigen::MatrixXd&, const Eigen::MatrixXi&, const Eigen::MatrixXi&, const double, const double>(), - "", py::arg("constraint"), py::arg("vertices"), py::arg("edges"), + py::arg("constraint"), py::arg("vertices"), py::arg("edges"), py::arg("faces"), py::arg("dhat"), py::arg("barrier_stiffness")); } diff --git a/python/src/friction/constraints/friction_constraint.cpp b/python/src/friction/constraints/friction_constraint.cpp index 3dda11ef5..58e5d4b1a 100644 --- a/python/src/friction/constraints/friction_constraint.cpp +++ b/python/src/friction/constraints/friction_constraint.cpp @@ -76,9 +76,9 @@ void define_friction_constraint(py::module_& m) Compute the friction force. Parameters: - rest_positions: Rest positions of the vertices (rowwise). - lagged_displacements: Previous displacements of the vertices (rowwise). - velocities: Current displacements of the vertices (rowwise). + rest_positions: Rest positions of the vertices (rowwise) + lagged_displacements: Previous displacements of the vertices (rowwise) + velocities: Current displacements of the vertices (rowwise) edges: Collision mesh edges faces: Collision mesh faces dhat: Barrier activation distance @@ -101,9 +101,9 @@ void define_friction_constraint(py::module_& m) Compute the friction force Jacobian. Parameters: - rest_positions: Rest positions of the vertices (rowwise). - lagged_displacements: Previous displacements of the vertices (rowwise). - velocities: Current displacements of the vertices (rowwise). + rest_positions: Rest positions of the vertices (rowwise) + lagged_displacements: Previous displacements of the vertices (rowwise) + velocities: Current displacements of the vertices (rowwise) edges: Collision mesh edges faces: Collision mesh faces dhat: Barrier activation distance diff --git a/python/src/friction/constraints/vertex_vertex.cpp b/python/src/friction/constraints/vertex_vertex.cpp index 53874c2b2..e2d1ab812 100644 --- a/python/src/friction/constraints/vertex_vertex.cpp +++ b/python/src/friction/constraints/vertex_vertex.cpp @@ -10,14 +10,12 @@ void define_vertex_vertex_friction_constraint(py::module_& m) py::class_< VertexVertexFrictionConstraint, VertexVertexCandidate, FrictionConstraint>(m, "VertexVertexFrictionConstraint") - .def( - py::init(), "", - py::arg("constraint")) + .def(py::init(), py::arg("constraint")) .def( py::init< const VertexVertexConstraint&, const Eigen::MatrixXd&, const Eigen::MatrixXi&, const Eigen::MatrixXi&, const double, const double>(), - "", py::arg("constraint"), py::arg("vertices"), py::arg("edges"), + py::arg("constraint"), py::arg("vertices"), py::arg("edges"), py::arg("faces"), py::arg("dhat"), py::arg("barrier_stiffness")); } diff --git a/python/src/friction/friction_constraints.cpp b/python/src/friction/friction_constraints.cpp index 4dbbc2d1f..df3cbaf09 100644 --- a/python/src/friction/friction_constraints.cpp +++ b/python/src/friction/friction_constraints.cpp @@ -8,14 +8,14 @@ using namespace ipc; void define_friction_constraints(py::module_& m) { py::class_(m, "FrictionConstraints") - .def(py::init(), "") + .def(py::init()) .def( "build", py::overload_cast< const CollisionMesh&, const Eigen::MatrixXd&, const CollisionConstraints&, double, double, double>( &FrictionConstraints::build), - "", py::arg("mesh"), py::arg("vertices"), + py::arg("mesh"), py::arg("vertices"), py::arg("contact_constraints"), py::arg("dhat"), py::arg("barrier_stiffness"), py::arg("mu")) .def( @@ -40,7 +40,7 @@ void define_friction_constraints(py::module_& m) const Eigen::VectorXd&, const std::function&>( &FrictionConstraints::build), - "", py::arg("mesh"), py::arg("vertices"), + py::arg("mesh"), py::arg("vertices"), py::arg("contact_constraints"), py::arg("dhat"), py::arg("barrier_stiffness"), py::arg("mus"), py::arg("blend_mu")) .def( @@ -96,9 +96,9 @@ void define_friction_constraints(py::module_& m) Parameters: mesh: The collision mesh. - rest_positions: Rest positions of the vertices (rowwise). - lagged_displacements: Previous displacements of the vertices (rowwise). - velocities: Current displacements of the vertices (rowwise). + rest_positions: Rest positions of the vertices (rowwise) + lagged_displacements: Previous displacements of the vertices (rowwise) + velocities: Current displacements of the vertices (rowwise) dhat: Barrier activation distance. barrier_stiffness: Barrier stiffness. epsv: Mollifier parameter :math:`\epsilon_v`. @@ -120,9 +120,9 @@ void define_friction_constraints(py::module_& m) Parameters: mesh: The collision mesh. - rest_positions: Rest positions of the vertices (rowwise). - lagged_displacements: Previous displacements of the vertices (rowwise). - velocities: Current displacements of the vertices (rowwise). + rest_positions: Rest positions of the vertices (rowwise) + lagged_displacements: Previous displacements of the vertices (rowwise) + velocities: Current displacements of the vertices (rowwise) dhat: Barrier activation distance. barrier_stiffness: Barrier stiffness. epsv: Mollifier parameter :math:`\epsilon_v`. @@ -162,14 +162,10 @@ void define_friction_constraints(py::module_& m) )ipc_Qu8mg5v7", py::arg("idx")) .def_static( - "default_blend_mu", &FrictionConstraints::default_blend_mu, "", + "default_blend_mu", &FrictionConstraints::default_blend_mu, py::arg("mu0"), py::arg("mu1")) - .def_readwrite( - "vv_constraints", &FrictionConstraints::vv_constraints, "") - .def_readwrite( - "ev_constraints", &FrictionConstraints::ev_constraints, "") - .def_readwrite( - "ee_constraints", &FrictionConstraints::ee_constraints, "") - .def_readwrite( - "fv_constraints", &FrictionConstraints::fv_constraints, ""); + .def_readwrite("vv_constraints", &FrictionConstraints::vv_constraints) + .def_readwrite("ev_constraints", &FrictionConstraints::ev_constraints) + .def_readwrite("ee_constraints", &FrictionConstraints::ee_constraints) + .def_readwrite("fv_constraints", &FrictionConstraints::fv_constraints); } diff --git a/python/src/friction/normal_force_magnitude.cpp b/python/src/friction/normal_force_magnitude.cpp index f79dc029e..11de33ccc 100644 --- a/python/src/friction/normal_force_magnitude.cpp +++ b/python/src/friction/normal_force_magnitude.cpp @@ -8,13 +8,13 @@ using namespace ipc; void define_normal_force_magnitude(py::module_& m) { m.def( - "compute_normal_force_magnitude", &compute_normal_force_magnitude, "", + "compute_normal_force_magnitude", &compute_normal_force_magnitude, py::arg("distance_squared"), py::arg("dhat"), py::arg("barrier_stiffness"), py::arg("dmin") = 0); m.def( "compute_normal_force_magnitude_gradient", - &compute_normal_force_magnitude_gradient, "", - py::arg("distance_squared"), py::arg("distance_squared_gradient"), - py::arg("dhat"), py::arg("barrier_stiffness"), py::arg("dmin") = 0); + &compute_normal_force_magnitude_gradient, py::arg("distance_squared"), + py::arg("distance_squared_gradient"), py::arg("dhat"), + py::arg("barrier_stiffness"), py::arg("dmin") = 0); } diff --git a/python/src/friction/relative_velocity.cpp b/python/src/friction/relative_velocity.cpp index d23237507..22dea702e 100644 --- a/python/src/friction/relative_velocity.cpp +++ b/python/src/friction/relative_velocity.cpp @@ -67,12 +67,11 @@ void define_relative_velocity(py::module_& m) m.def( "point_edge_relative_velocity_matrix", - &point_edge_relative_velocity_matrix, "", py::arg("dim"), - py::arg("alpha")); + &point_edge_relative_velocity_matrix, py::arg("dim"), py::arg("alpha")); m.def( "point_edge_relative_velocity_matrix_jacobian", - &point_edge_relative_velocity_matrix_jacobian, "", py::arg("dim"), + &point_edge_relative_velocity_matrix_jacobian, py::arg("dim"), py::arg("alpha")); m.def( @@ -95,12 +94,11 @@ void define_relative_velocity(py::module_& m) m.def( "edge_edge_relative_velocity_matrix", - &edge_edge_relative_velocity_matrix, "", py::arg("dim"), - py::arg("coords")); + &edge_edge_relative_velocity_matrix, py::arg("dim"), py::arg("coords")); m.def( "edge_edge_relative_velocity_matrix_jacobian", - &edge_edge_relative_velocity_matrix_jacobian, "", py::arg("dim"), + &edge_edge_relative_velocity_matrix_jacobian, py::arg("dim"), py::arg("coords")); m.def( @@ -123,11 +121,11 @@ void define_relative_velocity(py::module_& m) m.def( "point_triangle_relative_velocity_matrix", - &point_triangle_relative_velocity_matrix, "", py::arg("dim"), + &point_triangle_relative_velocity_matrix, py::arg("dim"), py::arg("coords")); m.def( "point_triangle_relative_velocity_matrix_jacobian", - &point_triangle_relative_velocity_matrix_jacobian, "", py::arg("dim"), + &point_triangle_relative_velocity_matrix_jacobian, py::arg("dim"), py::arg("coords")); } diff --git a/python/src/friction/smooth_friction_mollifier.cpp b/python/src/friction/smooth_friction_mollifier.cpp index b36f051ce..ad2959382 100644 --- a/python/src/friction/smooth_friction_mollifier.cpp +++ b/python/src/friction/smooth_friction_mollifier.cpp @@ -36,12 +36,14 @@ void define_smooth_friction_mollifier(py::module_& m) Compute the derivative of f0_SF divided by s (:math:`\frac{f_0'(s)}{s}`). .. math:: + f_1(s) = f_0'(s) = \begin{cases} -\frac{s^2}{\epsilon_v^2}+\frac{2 s}{\epsilon_v}, & |s| < \epsilon_v \newline 1, & |s| \geq \epsilon_v \end{cases} .. math:: + \frac{f_1(s)}{s} = \begin{cases} -\frac{s}{\epsilon_v^2}+\frac{2}{\epsilon_v}, & |s| < \epsilon_v \newline \frac{1}{s}, & |s| \geq \epsilon_v diff --git a/python/src/friction/tangent_basis.cpp b/python/src/friction/tangent_basis.cpp index 896ec3ef3..e2b48be8f 100644 --- a/python/src/friction/tangent_basis.cpp +++ b/python/src/friction/tangent_basis.cpp @@ -26,6 +26,15 @@ void define_tangent_basis(py::module_& m) )ipc_Qu8mg5v7", py::arg("p0"), py::arg("p1")); + m.def( + "point_point_tangent_basis_jacobian", + [](const VectorMax3d& p0, const VectorMax3d& p1) { + assert_2D_or_3D_vector(p0, "p0"); + assert_2D_or_3D_vector(p1, "p1"); + return point_point_tangent_basis_jacobian(p0, p1); + }, + py::arg("p0"), py::arg("p1")); + m.def( "point_edge_tangent_basis", [](const VectorMax3d& p, const VectorMax3d& e0, const VectorMax3d& e1) { @@ -34,7 +43,17 @@ void define_tangent_basis(py::module_& m) assert_2D_or_3D_vector(e1, "e1"); return point_edge_tangent_basis(p, e0, e1); }, - "", py::arg("p"), py::arg("e0"), py::arg("e1")); + py::arg("p"), py::arg("e0"), py::arg("e1")); + + m.def( + "point_edge_tangent_basis_jacobian", + [](const VectorMax3d& p, const VectorMax3d& e0, const VectorMax3d& e1) { + assert_2D_or_3D_vector(p, "p"); + assert_2D_or_3D_vector(e0, "e0"); + assert_2D_or_3D_vector(e1, "e1"); + return point_edge_tangent_basis_jacobian(p, e0, e1); + }, + py::arg("p"), py::arg("e0"), py::arg("e1")); m.def( "edge_edge_tangent_basis", @@ -45,6 +64,14 @@ void define_tangent_basis(py::module_& m) "Compute a basis for the space tangent to the edge-edge pair.", py::arg("ea0"), py::arg("ea1"), py::arg("eb0"), py::arg("eb1")); + m.def( + "edge_edge_tangent_basis_jacobian", + [](const Eigen::Vector3d& ea0, const Eigen::Vector3d& ea1, + const Eigen::Vector3d& eb0, const Eigen::Vector3d& eb1) { + return edge_edge_tangent_basis_jacobian(ea0, ea1, eb0, eb1); + }, + py::arg("ea0"), py::arg("ea1"), py::arg("eb0"), py::arg("eb1")); + m.def( "point_triangle_tangent_basis", [](const Eigen::Vector3d& p, const Eigen::Vector3d& t0, @@ -72,38 +99,11 @@ void define_tangent_basis(py::module_& m) )ipc_Qu8mg5v7", py::arg("p"), py::arg("t0"), py::arg("t1"), py::arg("t2")); - m.def( - "point_point_tangent_basis_jacobian", - [](const VectorMax3d& p0, const VectorMax3d& p1) { - assert_2D_or_3D_vector(p0, "p0"); - assert_2D_or_3D_vector(p1, "p1"); - return point_point_tangent_basis_jacobian(p0, p1); - }, - "", py::arg("p0"), py::arg("p1")); - - m.def( - "point_edge_tangent_basis_jacobian", - [](const VectorMax3d& p, const VectorMax3d& e0, const VectorMax3d& e1) { - assert_2D_or_3D_vector(p, "p"); - assert_2D_or_3D_vector(e0, "e0"); - assert_2D_or_3D_vector(e1, "e1"); - return point_edge_tangent_basis_jacobian(p, e0, e1); - }, - "", py::arg("p"), py::arg("e0"), py::arg("e1")); - - m.def( - "edge_edge_tangent_basis_jacobian", - [](const Eigen::Vector3d& ea0, const Eigen::Vector3d& ea1, - const Eigen::Vector3d& eb0, const Eigen::Vector3d& eb1) { - return edge_edge_tangent_basis_jacobian(ea0, ea1, eb0, eb1); - }, - "", py::arg("ea0"), py::arg("ea1"), py::arg("eb0"), py::arg("eb1")); - m.def( "point_triangle_tangent_basis_jacobian", [](const Eigen::Vector3d& p, const Eigen::Vector3d& t0, const Eigen::Vector3d& t1, const Eigen::Vector3d& t2) { return point_triangle_tangent_basis_jacobian(p, t0, t1, t2); }, - "", py::arg("p"), py::arg("t0"), py::arg("t1"), py::arg("t2")); + py::arg("p"), py::arg("t0"), py::arg("t1"), py::arg("t2")); } diff --git a/python/src/ipc.cpp b/python/src/ipc.cpp index 368d1affd..d275e764b 100644 --- a/python/src/ipc.cpp +++ b/python/src/ipc.cpp @@ -9,11 +9,7 @@ using namespace ipc; void define_ipc(py::module_& m) { m.def( - "is_step_collision_free", - py::overload_cast< - const CollisionMesh&, const Eigen::MatrixXd&, - const Eigen::MatrixXd&, const BroadPhaseMethod, const double, - const double, const long>(&is_step_collision_free), + "is_step_collision_free", &is_step_collision_free, R"ipc_Qu8mg5v7( Determine if the step is collision free. @@ -39,11 +35,7 @@ void define_ipc(py::module_& m) py::arg("max_iterations") = DEFAULT_CCD_MAX_ITERATIONS); m.def( - "compute_collision_free_stepsize", - py::overload_cast< - const CollisionMesh&, const Eigen::MatrixXd&, - const Eigen::MatrixXd&, const BroadPhaseMethod, const double, - const double, const long>(&compute_collision_free_stepsize), + "compute_collision_free_stepsize", &compute_collision_free_stepsize, R"ipc_Qu8mg5v7( Computes a maximal step size that is collision free. @@ -60,7 +52,7 @@ void define_ipc(py::module_& m) max_iterations: The maximum number of iterations for the CCD algorithm. Returns: - A step-size $\in [0, 1]$ that is collision free. A value of 1.0 if a full step and 0.0 is no step. + A step-size :math:`\in [0, 1]` that is collision free. A value of 1.0 if a full step and 0.0 is no step. )ipc_Qu8mg5v7", py::arg("mesh"), py::arg("vertices_t0"), py::arg("vertices_t1"), py::arg("broad_phase_method") = DEFAULT_BROAD_PHASE_METHOD, diff --git a/python/src/utils/eigen_ext.cpp b/python/src/utils/eigen_ext.cpp index d11983ba8..22fc0ae69 100644 --- a/python/src/utils/eigen_ext.cpp +++ b/python/src/utils/eigen_ext.cpp @@ -12,13 +12,30 @@ void define_eigen_ext(py::module_& m) &project_to_pd< double, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor | Eigen::AutoAlign, Eigen::Dynamic, Eigen::Dynamic>, - "Matrix Projection onto Positive Definite Cone", py::arg("A"), - py::arg("eps") = 1e-8); + R"ipc_Qu8mg5v7( + Matrix projection onto positive definite cone + + Parameters: + A: Symmetric matrix to project + + Returns: + Projected matrix + )ipc_Qu8mg5v7", + py::arg("A"), py::arg("eps") = 1e-8); m.def( "project_to_psd", &project_to_psd< double, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor | Eigen::AutoAlign, Eigen::Dynamic, Eigen::Dynamic>, - "Matrix Projection onto Positive Semi-Definite Cone", py::arg("A")); + R"ipc_Qu8mg5v7( + Matrix projection onto positive semi-definite cone + + Parameters: + A: Symmetric matrix to project + + Returns: + Projected matrix + )ipc_Qu8mg5v7", + py::arg("A")); } diff --git a/python/src/utils/intersection.cpp b/python/src/utils/intersection.cpp index 24ca30549..5b75dc5f2 100644 --- a/python/src/utils/intersection.cpp +++ b/python/src/utils/intersection.cpp @@ -10,7 +10,7 @@ using namespace ipc; void define_intersection(py::module_& m) { m.def( - "is_edge_intersecting_triangle", &is_edge_intersecting_triangle, "", + "is_edge_intersecting_triangle", &is_edge_intersecting_triangle, py::arg("e0"), py::arg("e1"), py::arg("t0"), py::arg("t1"), py::arg("t2")); diff --git a/python/src/utils/vertex_to_min_edge.cpp b/python/src/utils/vertex_to_min_edge.cpp index 7e3480435..df4e121ec 100644 --- a/python/src/utils/vertex_to_min_edge.cpp +++ b/python/src/utils/vertex_to_min_edge.cpp @@ -8,6 +8,6 @@ using namespace ipc; void define_vertex_to_min_edge(py::module_& m) { m.def( - "vertex_to_min_edge", &vertex_to_min_edge, "", py::arg("num_vertices"), + "vertex_to_min_edge", &vertex_to_min_edge, py::arg("num_vertices"), py::arg("edges")); } diff --git a/src/ipc/barrier/barrier.hpp b/src/ipc/barrier/barrier.hpp index c27d369af..836c0d06e 100644 --- a/src/ipc/barrier/barrier.hpp +++ b/src/ipc/barrier/barrier.hpp @@ -10,7 +10,7 @@ namespace ipc { // Barrier functions from [Li et al. 2020] // ============================================================================ -/// @brief Function that grows to infinity as x approaches 0 from the right. +/// @brief Function that grows to infinity as d approaches 0 from the right. /// /// \f\[ /// b(d) = -(d-\hat{d})^2\ln\left(\frac{d}{\hat{d}}\right) diff --git a/src/ipc/broad_phase/aabb.hpp b/src/ipc/broad_phase/aabb.hpp index b206fcabd..39b144c49 100644 --- a/src/ipc/broad_phase/aabb.hpp +++ b/src/ipc/broad_phase/aabb.hpp @@ -25,11 +25,18 @@ class AABB { { } - /// @brief Compute a AABB for a static point. + /// @brief Construct a AABB for a static point. + /// @param p The point's position. + /// @param inflation_radius Radius of a sphere around the point which the AABB encloses. + /// @return The constructed AABB. static AABB from_point(const VectorMax3d& p, const double inflation_radius = 0); - /// @brief Compute a AABB for a moving point (i.e. temporal edge). + /// @brief Construct a AABB for a moving point (i.e. temporal edge). + /// @param p_t0 The point's position at time t=0. + /// @param p_t1 The point's position at time t=1. + /// @param inflation_radius Radius of a capsule around the temporal edge which the AABB encloses. + /// @return The constructed AABB. static AABB from_point( const VectorMax3d& p_t0, const VectorMax3d& p_t1, @@ -40,6 +47,9 @@ class AABB { from_point(p_t1, inflation_radius)); } + /// @brief Check if another AABB intersects with this one. + /// @param other The other AABB. + /// @return If the two AABBs intersect. bool intersects(const AABB& other) const; /// @brief Compute a conservative inflation of the AABB. @@ -47,11 +57,18 @@ class AABB { ArrayMax3d& min, ArrayMax3d& max, const double inflation_radius); public: + /// @brief Minimum corner of the AABB. ArrayMax3d min; + /// @brief Maximum corner of the AABB. ArrayMax3d max; + /// @brief Vertex IDs attached to the AABB. std::array vertex_ids; }; +/// @brief Build one AABB per vertex position (row of V). +/// @param[in] vertices Vertex positions (rowwise). +/// @param[out] vertex_boxes Vertex AABBs. +/// @param[in] inflation_radius Radius of a sphere around the points which the AABBs enclose. void build_vertex_boxes( const Eigen::MatrixXd& vertices, std::vector& vertex_boxes, diff --git a/src/ipc/broad_phase/hash_grid.hpp b/src/ipc/broad_phase/hash_grid.hpp index 6e479846a..24df9a5f0 100644 --- a/src/ipc/broad_phase/hash_grid.hpp +++ b/src/ipc/broad_phase/hash_grid.hpp @@ -6,8 +6,10 @@ namespace ipc { /// @brief An entry into the hash grid as a (key, value) pair. struct HashItem { - long key; /// @brief The key of the item. - long id; /// @brief The value of the item. + /// @brief The key of the item. + long key; + /// @brief The value of the item. + long id; /// @brief Construct a hash item as a (key, value) pair. HashItem(int _key, int _id) : key(_key), id(_id) { } diff --git a/src/ipc/candidates/edge_edge.hpp b/src/ipc/candidates/edge_edge.hpp index 0f6c1b4d0..084a97cfc 100644 --- a/src/ipc/candidates/edge_edge.hpp +++ b/src/ipc/candidates/edge_edge.hpp @@ -49,8 +49,10 @@ class EdgeEdgeCandidate : public ContinuousCollisionCandidate { // ------------------------------------------------------------------------ - long edge0_id; ///< @brief ID of the first edge. - long edge1_id; ///< @brief ID of the second edge. + /// @brief ID of the first edge. + long edge0_id; + /// @brief ID of the second edge. + long edge1_id; using CollisionStencil::compute_distance; using CollisionStencil::compute_distance_gradient; diff --git a/src/ipc/candidates/edge_face.hpp b/src/ipc/candidates/edge_face.hpp index 3e5f584a7..69c0eaef4 100644 --- a/src/ipc/candidates/edge_face.hpp +++ b/src/ipc/candidates/edge_face.hpp @@ -26,8 +26,10 @@ class EdgeFaceCandidate { return H::combine(std::move(h), fv.edge_id, fv.face_id); } - long edge_id; ///< @brief ID of the edge - long face_id; ///< @brief ID of the face + /// @brief ID of the edge + long edge_id; + /// @brief ID of the face + long face_id; }; } // namespace ipc diff --git a/src/ipc/candidates/edge_vertex.hpp b/src/ipc/candidates/edge_vertex.hpp index ca56c8d5c..642af5c3a 100644 --- a/src/ipc/candidates/edge_vertex.hpp +++ b/src/ipc/candidates/edge_vertex.hpp @@ -46,8 +46,10 @@ class EdgeVertexCandidate : public ContinuousCollisionCandidate { // ------------------------------------------------------------------------ - long edge_id; ///< @brief ID of the edge - long vertex_id; ///< @brief ID of the vertex + /// @brief ID of the edge + long edge_id; + /// @brief ID of the vertex + long vertex_id; using CollisionStencil::compute_distance; using CollisionStencil::compute_distance_gradient; diff --git a/src/ipc/candidates/face_vertex.hpp b/src/ipc/candidates/face_vertex.hpp index a7e73fdc8..a5fcf7646 100644 --- a/src/ipc/candidates/face_vertex.hpp +++ b/src/ipc/candidates/face_vertex.hpp @@ -47,8 +47,10 @@ class FaceVertexCandidate : public ContinuousCollisionCandidate { // ------------------------------------------------------------------------ - long face_id; ///< @brief ID of the face - long vertex_id; ///< @brief ID of the vertex + /// @brief ID of the face + long face_id; + /// @brief ID of the vertex + long vertex_id; using CollisionStencil::compute_distance; using CollisionStencil::compute_distance_gradient; diff --git a/src/ipc/candidates/vertex_vertex.hpp b/src/ipc/candidates/vertex_vertex.hpp index df6c21c27..338b93209 100644 --- a/src/ipc/candidates/vertex_vertex.hpp +++ b/src/ipc/candidates/vertex_vertex.hpp @@ -52,8 +52,10 @@ class VertexVertexCandidate : public ContinuousCollisionCandidate { // ------------------------------------------------------------------------ - long vertex0_id; ///< @brief ID of the first vertex - long vertex1_id; ///< @brief ID of the second vertex + /// @brief ID of the first vertex + long vertex0_id; + /// @brief ID of the second vertex + long vertex1_id; using CollisionStencil::compute_distance; using CollisionStencil::compute_distance_gradient; diff --git a/src/ipc/distance/distance_type.hpp b/src/ipc/distance/distance_type.hpp index c5d7a95ac..11f9122ce 100644 --- a/src/ipc/distance/distance_type.hpp +++ b/src/ipc/distance/distance_type.hpp @@ -14,22 +14,26 @@ enum class PointEdgeDistanceType { /// @brief Closest pair between a point and triangle. enum class PointTriangleDistanceType { - P_T0, ///< The point is closest to triangle vertex zero. - P_T1, ///< The point is closest to triangle vertex one. - P_T2, ///< The point is closest to triangle vertex two. - P_E0, ///< The point is closest to triangle edge zero (vertex zero to one). - P_E1, ///< The point is closest to triangle edge one (vertex one to two). - P_E2, ///< The point is closest to triangle edge two (vertex two to zero). - P_T, ///< The point is closest to the interior of the triangle. - AUTO ///< Automatically determine the closest pair. + P_T0, /// The point is closest to triangle vertex zero. + P_T1, /// The point is closest to triangle vertex one. + P_T2, /// The point is closest to triangle vertex two. + P_E0, /// The point is closest to triangle edge zero (vertex zero to one). + P_E1, /// The point is closest to triangle edge one (vertex one to two). + P_E2, /// The point is closest to triangle edge two (vertex two to zero). + P_T, /// The point is closest to the interior of the triangle. + AUTO /// Automatically determine the closest pair. }; /// @brief Closest pair between two edges. enum class EdgeEdgeDistanceType { - EA0_EB0, ///< The edges are closest at vertex 0 of edge A and 0 of edge B. - EA0_EB1, ///< The edges are closest at vertex 0 of edge A and 1 of edge B. - EA1_EB0, ///< The edges are closest at vertex 1 of edge A and 0 of edge B. - EA1_EB1, ///< The edges are closest at vertex 1 of edge A and 1 of edge B. + /// The edges are closest at vertex 0 of edge A and 0 of edge B. + EA0_EB0, + /// The edges are closest at vertex 0 of edge A and 1 of edge B. + EA0_EB1, + /// The edges are closest at vertex 1 of edge A and 0 of edge B. + EA1_EB0, + /// The edges are closest at vertex 1 of edge A and 1 of edge B. + EA1_EB1, /// The edges are closest at the interior of edge A and vertex 0 of edge B. EA_EB0, /// The edges are closest at the interior of edge A and vertex 1 of edge B. @@ -38,8 +42,10 @@ enum class EdgeEdgeDistanceType { EA0_EB, /// The edges are closest at vertex 1 of edge A and the interior of edge B. EA1_EB, - EA_EB, ///< The edges are closest at an interior point of edge A and B. - AUTO ///< Automatically determine the closest pair. + /// The edges are closest at an interior point of edge A and B. + EA_EB, + /// Automatically determine the closest pair. + AUTO }; /// @brief Determine the closest pair between a point and edge. diff --git a/src/ipc/implicits/plane.hpp b/src/ipc/implicits/plane.hpp index 2e8142cfd..fcecec719 100644 --- a/src/ipc/implicits/plane.hpp +++ b/src/ipc/implicits/plane.hpp @@ -15,12 +15,12 @@ inline bool default_can_point_plane_collide(size_t, size_t) { return true; } /// /// @note The given pv_constraints will be cleared. /// -/// @param[in] points Points as rows of a matrix. -/// @param[in] plane_origins Plane origins as rows of a matrix. -/// @param[in] plane_normals Plane normals as rows of a matrix. -/// @param[in] dhat The activation distance of the barrier. +/// @param[in] points Points as rows of a matrix. +/// @param[in] plane_origins Plane origins as rows of a matrix. +/// @param[in] plane_normals Plane normals as rows of a matrix. +/// @param[in] dhat The activation distance of the barrier. /// @param[out] pv_constraints The constructed set of constraints. -/// @param[in] dmin Minimum distance. +/// @param[in] dmin Minimum distance. /// @param[in] can_collide A function that takes a vertex ID (row numbers in points) and a plane ID (row number in plane_origins) then returns true if the vertex can collide with the plane. By default all points can collide with all planes. void construct_point_plane_constraint_set( const Eigen::MatrixXd& points, @@ -41,8 +41,8 @@ void construct_point_plane_constraint_set( /// /// @param[in] points_t0 Points at start as rows of a matrix. /// @param[in] points_t1 Points at end as rows of a matrix. -/// @param[in] plane_origins Plane origins as rows of a matrix. -/// @param[in] plane_normals Plane normals as rows of a matrix. +/// @param[in] plane_origins Plane origins as rows of a matrix. +/// @param[in] plane_normals Plane normals as rows of a matrix. /// @param[in] can_collide A function that takes a vertex ID (row numbers in points) and a plane ID (row number in plane_origins) then returns true if the vertex can collide with the plane. By default all points can collide with all planes. /// @returns True if any collisions occur. bool is_step_point_plane_collision_free( @@ -61,8 +61,8 @@ bool is_step_point_plane_collision_free( /// /// @param points_t0 Points at start as rows of a matrix. /// @param points_t1 Points at end as rows of a matrix. -/// @param plane_origins Plane origins as rows of a matrix. -/// @param plane_normals Plane normals as rows of a matrix. +/// @param plane_origins Plane origins as rows of a matrix. +/// @param plane_normals Plane normals as rows of a matrix. /// @param can_collide A function that takes a vertex ID (row numbers in points) and a plane ID (row number in plane_origins) then returns true if the vertex can collide with the plane. By default all points can collide with all planes. /// @returns A step-size \f$\in [0, 1]\f$ that is collision free. double compute_point_plane_collision_free_stepsize( From 0dada1c21bb4dd67fc37f41ffbe85185c05e8326 Mon Sep 17 00:00:00 2001 From: Zachary Ferguson Date: Mon, 30 Oct 2023 19:00:09 -0400 Subject: [PATCH 02/10] Update Python bindings --- .../src/collisions/collision_constraint.cpp | 16 +++ python/src/distance/edge_edge.cpp | 18 ++-- python/src/distance/edge_edge_mollifier.cpp | 99 +++++++++++++++++++ python/src/distance/line_line.cpp | 36 +++---- python/src/distance/point_edge.cpp | 18 ++-- python/src/distance/point_line.cpp | 18 ++-- python/src/distance/point_point.cpp | 22 ++--- python/src/distance/point_triangle.cpp | 18 ++-- src/ipc/distance/line_line.hpp | 4 +- 9 files changed, 182 insertions(+), 67 deletions(-) diff --git a/python/src/collisions/collision_constraint.cpp b/python/src/collisions/collision_constraint.cpp index e2d31ff83..bee897b63 100644 --- a/python/src/collisions/collision_constraint.cpp +++ b/python/src/collisions/collision_constraint.cpp @@ -8,6 +8,9 @@ using namespace ipc; void define_collision_constraint(py::module_& m) { py::class_(m, "CollisionConstraint") + // .def( + // py::init&>(), + // py::arg("weight"), py::arg("weight_gradient")) .def( "compute_potential", &CollisionConstraint::compute_potential, py::arg("vertices"), py::arg("edges"), py::arg("faces"), @@ -22,6 +25,19 @@ void define_collision_constraint(py::module_& m) &CollisionConstraint::compute_potential_hessian, py::arg("vertices"), py::arg("edges"), py::arg("faces"), py::arg("dhat"), py::arg("project_hessian_to_psd")) + .def( + "compute_shape_derivative", + [](CollisionConstraint& self, const Eigen::MatrixXd& rest_positions, + const Eigen::MatrixXd& vertices, const Eigen::MatrixXi& edges, + const Eigen::MatrixXi& faces, const double dhat) { + std::vector> triplets; + self.compute_shape_derivative( + rest_positions, vertices, edges, faces, dhat, triplets); + return triplets; + }, + "Compute the derivative of the potential gradient wrt the shape.", + py::arg("rest_positions"), py::arg("vertices"), py::arg("edges"), + py::arg("faces"), py::arg("dhat")) .def_readwrite("dmin", &CollisionConstraint::dmin) .def_readwrite("weight", &CollisionConstraint::weight) .def_property( diff --git a/python/src/distance/edge_edge.cpp b/python/src/distance/edge_edge.cpp index eae03a89f..f7bc1c620 100644 --- a/python/src/distance/edge_edge.cpp +++ b/python/src/distance/edge_edge.cpp @@ -13,6 +13,9 @@ void define_edge_edge_distance(py::module_& m) R"ipc_Qu8mg5v7( Compute the distance between a two lines segments in 3D. + Note: + The distance is actually squared distance. + Parameters: ea0: The first vertex of the first edge. ea1: The second vertex of the first edge. @@ -22,9 +25,6 @@ void define_edge_edge_distance(py::module_& m) Returns: The distance between the two edges. - - Note: - The distance is actually squared distance. )ipc_Qu8mg5v7", py::arg("ea0"), py::arg("ea1"), py::arg("eb0"), py::arg("eb1"), py::arg("dtype") = EdgeEdgeDistanceType::AUTO); @@ -34,6 +34,9 @@ void define_edge_edge_distance(py::module_& m) R"ipc_Qu8mg5v7( Compute the gradient of the distance between a two lines segments. + Note: + The distance is actually squared distance. + Parameters: ea0: The first vertex of the first edge. ea1: The second vertex of the first edge. @@ -43,9 +46,6 @@ void define_edge_edge_distance(py::module_& m) Returns: The gradient of the distance wrt ea0, ea1, eb0, and eb1. - - Note: - The distance is actually squared distance. )ipc_Qu8mg5v7", py::arg("ea0"), py::arg("ea1"), py::arg("eb0"), py::arg("eb1"), py::arg("dtype") = EdgeEdgeDistanceType::AUTO); @@ -55,6 +55,9 @@ void define_edge_edge_distance(py::module_& m) R"ipc_Qu8mg5v7( Compute the hessian of the distance between a two lines segments. + Note: + The distance is actually squared distance. + Parameters: ea0: The first vertex of the first edge. ea1: The second vertex of the first edge. @@ -64,9 +67,6 @@ void define_edge_edge_distance(py::module_& m) Returns: The hessian of the distance wrt ea0, ea1, eb0, and eb1. - - Note: - The distance is actually squared distance. )ipc_Qu8mg5v7", py::arg("ea0"), py::arg("ea1"), py::arg("eb0"), py::arg("eb1"), py::arg("dtype") = EdgeEdgeDistanceType::AUTO); diff --git a/python/src/distance/edge_edge_mollifier.cpp b/python/src/distance/edge_edge_mollifier.cpp index 74029e54d..b1498d18b 100644 --- a/python/src/distance/edge_edge_mollifier.cpp +++ b/python/src/distance/edge_edge_mollifier.cpp @@ -98,6 +98,21 @@ void define_edge_edge_mollifier(py::module_& m) )ipc_Qu8mg5v7", py::arg("x"), py::arg("eps_x")); + m.def( + "edge_edge_mollifier_derivative_wrt_eps_x", + &edge_edge_mollifier_derivative_wrt_eps_x, + R"ipc_Qu8mg5v7( + The derivative of the mollifier function for edge-edge distance wrt eps_x. + + Parameters: + x: Squared norm of the edge-edge cross product. + eps_x: Mollifier activation threshold. + + Returns: + The derivative of the mollifier function for edge-edge distance wrt eps_x. + )ipc_Qu8mg5v7", + py::arg("x"), py::arg("eps_x")); + m.def( "edge_edge_mollifier_hessian", py::overload_cast( @@ -114,6 +129,21 @@ void define_edge_edge_mollifier(py::module_& m) )ipc_Qu8mg5v7", py::arg("x"), py::arg("eps_x")); + m.def( + "edge_edge_mollifier_gradient_derivative_wrt_eps_x", + &edge_edge_mollifier_gradient_derivative_wrt_eps_x, + R"ipc_Qu8mg5v7( + The derivative of the gradient of the mollifier function for edge-edge distance wrt eps_x. + + Parameters: + x: Squared norm of the edge-edge cross product. + eps_x: Mollifier activation threshold. + + Returns: + The derivative of the gradient of the mollifier function for edge-edge distance wrt eps_x. + )ipc_Qu8mg5v7", + py::arg("x"), py::arg("eps_x")); + m.def( "edge_edge_mollifier", py::overload_cast< @@ -188,6 +218,55 @@ void define_edge_edge_mollifier(py::module_& m) py::arg("ea0"), py::arg("ea1"), py::arg("eb0"), py::arg("eb1"), py::arg("eps_x")); + m.def( + "edge_edge_mollifier_gradient_wrt_x", + &edge_edge_mollifier_gradient_wrt_x, + R"ipc_Qu8mg5v7( + Compute the gradient of the mollifier for the edge-edge distance wrt rest positions. + + Parameters: + ea0_rest: The rest position of the first vertex of the first edge. + ea1_rest: The rest position of the second vertex of the first edge. + eb0_rest: The rest position of the first vertex of the second edge. + eb1_rest: The rest position of the second vertex of the second edge. + ea0: The first vertex of the first edge. + ea1: The second vertex of the first edge. + eb0: The first vertex of the second edge. + eb1: The second vertex of the second edge. + + Returns: + The derivative of the mollifier wrt rest positions. + )ipc_Qu8mg5v7", + py::arg("ea0_rest"), py::arg("ea1_rest"), py::arg("eb0_rest"), + py::arg("eb1_rest"), py::arg("ea0"), py::arg("ea1"), py::arg("eb0"), + py::arg("eb1")); + + m.def( + "edge_edge_mollifier_gradient_jacobian_wrt_x", + &edge_edge_mollifier_gradient_jacobian_wrt_x, + R"ipc_Qu8mg5v7( + Compute the jacobian of the edge-edge distance mollifier's gradient wrt rest positions. + + Note: + This is not the hessian of the mollifier wrt rest positions, but the jacobian wrt rest positions of the mollifier's gradient wrt positions. + + Parameters: + ea0_rest: The rest position of the first vertex of the first edge. + ea1_rest: The rest position of the second vertex of the first edge. + eb0_rest: The rest position of the first vertex of the second edge. + eb1_rest: The rest position of the second vertex of the second edge. + ea0: The first vertex of the first edge. + ea1: The second vertex of the first edge. + eb0: The first vertex of the second edge. + eb1: The second vertex of the second edge. + + Returns: + The jacobian of the mollifier's gradient wrt rest positions. + )ipc_Qu8mg5v7", + py::arg("ea0_rest"), py::arg("ea1_rest"), py::arg("eb0_rest"), + py::arg("eb1_rest"), py::arg("ea0"), py::arg("ea1"), py::arg("eb0"), + py::arg("eb1")); + m.def( "edge_edge_mollifier_threshold", &edge_edge_mollifier_threshold, R"ipc_Qu8mg5v7( @@ -206,4 +285,24 @@ void define_edge_edge_mollifier(py::module_& m) )ipc_Qu8mg5v7", py::arg("ea0_rest"), py::arg("ea1_rest"), py::arg("eb0_rest"), py::arg("eb1_rest")); + + m.def( + "edge_edge_mollifier_threshold_gradient", + &edge_edge_mollifier_threshold_gradient, + R"ipc_Qu8mg5v7( + Compute the gradient of the threshold of the mollifier edge-edge distance. + + This values is computed based on the edges at rest length. + + Parameters: + ea0_rest: The rest position of the first vertex of the first edge. + ea1_rest: The rest position of the second vertex of the first edge. + eb0_rest: The rest position of the first vertex of the second edge. + eb1_rest: The rest position of the second vertex of the second edge. + + Returns: + Gradient of the threshold for edge-edge mollification. + )ipc_Qu8mg5v7", + py::arg("ea0_rest"), py::arg("ea1_rest"), py::arg("eb0_rest"), + py::arg("eb1_rest")); } diff --git a/python/src/distance/line_line.cpp b/python/src/distance/line_line.cpp index 2d8e51bcf..7dfbca8fb 100644 --- a/python/src/distance/line_line.cpp +++ b/python/src/distance/line_line.cpp @@ -12,6 +12,12 @@ void define_line_line_distance(py::module_& m) R"ipc_Qu8mg5v7( Compute the distance between a two infinite lines in 3D. + Note: + The distance is actually squared distance. + + Warning: + If the lines are parallel this function returns a distance of zero. + Parameters: ea0: The first vertex of the edge defining the first line. ea1: The second vertex of the edge defining the first line. @@ -20,12 +26,6 @@ void define_line_line_distance(py::module_& m) Returns: The distance between the two lines. - - Note: - The distance is actually squared distance. - - Warning: - If the lines are parallel this function returns a distance of zero. )ipc_Qu8mg5v7", py::arg("ea0"), py::arg("ea1"), py::arg("eb0"), py::arg("eb1")); @@ -34,6 +34,12 @@ void define_line_line_distance(py::module_& m) R"ipc_Qu8mg5v7( Compute the gradient of the distance between a two lines in 3D. + Note: + The distance is actually squared distance. + + Warning: + If the lines are parallel this function returns a distance of zero. + Parameters: ea0: The first vertex of the edge defining the first line. ea1: The second vertex of the edge defining the first line. @@ -42,12 +48,6 @@ void define_line_line_distance(py::module_& m) Returns: The gradient of the distance wrt ea0, ea1, eb0, and eb1. - - Note: - The distance is actually squared distance. - - Warning: - If the lines are parallel this function returns a distance of zero. )ipc_Qu8mg5v7", py::arg("ea0"), py::arg("ea1"), py::arg("eb0"), py::arg("eb1")); @@ -56,6 +56,12 @@ void define_line_line_distance(py::module_& m) R"ipc_Qu8mg5v7( Compute the hessian of the distance between a two lines in 3D. + Note: + The distance is actually squared distance. + + Warning: + If the lines are parallel this function returns a distance of zero. + Parameters: ea0: The first vertex of the edge defining the first line. ea1: The second vertex of the edge defining the first line. @@ -64,12 +70,6 @@ void define_line_line_distance(py::module_& m) Returns: The hessian of the distance wrt ea0, ea1, eb0, and eb1. - - Note: - The distance is actually squared distance. - - Warning: - If the lines are parallel this function returns a distance of zero. )ipc_Qu8mg5v7", py::arg("ea0"), py::arg("ea1"), py::arg("eb0"), py::arg("eb1")); } diff --git a/python/src/distance/point_edge.cpp b/python/src/distance/point_edge.cpp index 3f9eecb42..79b655eca 100644 --- a/python/src/distance/point_edge.cpp +++ b/python/src/distance/point_edge.cpp @@ -13,6 +13,9 @@ void define_point_edge_distance(py::module_& m) R"ipc_Qu8mg5v7( Compute the distance between a point and edge in 2D or 3D. + Note: + The distance is actually squared distance. + Parameters: p: The point. e0: The first vertex of the edge. @@ -21,9 +24,6 @@ void define_point_edge_distance(py::module_& m) Returns: The distance between the point and edge. - - Note: - The distance is actually squared distance. )ipc_Qu8mg5v7", py::arg("p"), py::arg("e0"), py::arg("e1"), py::arg("dtype") = PointEdgeDistanceType::AUTO); @@ -33,6 +33,9 @@ void define_point_edge_distance(py::module_& m) R"ipc_Qu8mg5v7( Compute the gradient of the distance between a point and edge. + Note: + The distance is actually squared distance. + Parameters: p: The point. e0: The first vertex of the edge. @@ -41,9 +44,6 @@ void define_point_edge_distance(py::module_& m) Returns: grad The gradient of the distance wrt p, e0, and e1. - - Note: - The distance is actually squared distance. )ipc_Qu8mg5v7", py::arg("p"), py::arg("e0"), py::arg("e1"), py::arg("dtype") = PointEdgeDistanceType::AUTO); @@ -53,6 +53,9 @@ void define_point_edge_distance(py::module_& m) R"ipc_Qu8mg5v7( Compute the hessian of the distance between a point and edge. + Note: + The distance is actually squared distance. + Parameters: p: The point. e0: The first vertex of the edge. @@ -61,9 +64,6 @@ void define_point_edge_distance(py::module_& m) Returns: hess The hessian of the distance wrt p, e0, and e1. - - Note: - The distance is actually squared distance. )ipc_Qu8mg5v7", py::arg("p"), py::arg("e0"), py::arg("e1"), py::arg("dtype") = PointEdgeDistanceType::AUTO); diff --git a/python/src/distance/point_line.cpp b/python/src/distance/point_line.cpp index c82cb932e..bb7b23973 100644 --- a/python/src/distance/point_line.cpp +++ b/python/src/distance/point_line.cpp @@ -12,6 +12,9 @@ void define_point_line_distance(py::module_& m) R"ipc_Qu8mg5v7( Compute the distance between a point and line in 2D or 3D. + Note: + The distance is actually squared distance. + Parameters: p: The point. e0: The first vertex of the edge defining the line. @@ -19,9 +22,6 @@ void define_point_line_distance(py::module_& m) Returns: The distance between the point and line. - - Note: - The distance is actually squared distance. )ipc_Qu8mg5v7", py::arg("p"), py::arg("e0"), py::arg("e1")); @@ -30,6 +30,9 @@ void define_point_line_distance(py::module_& m) R"ipc_Qu8mg5v7( Compute the gradient of the distance between a point and line. + Note: + The distance is actually squared distance. + Parameters: p: The point. e0: The first vertex of the edge defining the line. @@ -37,9 +40,6 @@ void define_point_line_distance(py::module_& m) Returns: The gradient of the distance wrt p, e0, and e1. - - Note: - The distance is actually squared distance. )ipc_Qu8mg5v7", py::arg("p"), py::arg("e0"), py::arg("e1")); @@ -48,6 +48,9 @@ void define_point_line_distance(py::module_& m) R"ipc_Qu8mg5v7( Compute the hessian of the distance between a point and line. + Note: + The distance is actually squared distance. + Parameters: p: The point. e0: The first vertex of the edge defining the line. @@ -55,9 +58,6 @@ void define_point_line_distance(py::module_& m) Returns: The hessian of the distance wrt p, e0, and e1. - - Note: - The distance is actually squared distance. )ipc_Qu8mg5v7", py::arg("p"), py::arg("e0"), py::arg("e1")); } diff --git a/python/src/distance/point_point.cpp b/python/src/distance/point_point.cpp index e310466ec..61e242312 100644 --- a/python/src/distance/point_point.cpp +++ b/python/src/distance/point_point.cpp @@ -13,15 +13,15 @@ void define_point_point_distance(py::module_& m) R"ipc_Qu8mg5v7( Compute the distance between two points. + Note: + The distance is actually squared distance. + Parameters: p0: The first point. p1: The second point. Returns: The distance between p0 and p1. - - Note: - The distance is actually squared distance. )ipc_Qu8mg5v7", py::arg("p0"), py::arg("p1")); @@ -30,15 +30,15 @@ void define_point_point_distance(py::module_& m) R"ipc_Qu8mg5v7( Compute the gradient of the distance between two points. + Note: + The distance is actually squared distance. + Parameters: p0: The first point. p1: The second point. Returns: - The gradient of the distance wrt p0 and p1. - - Note: - The distance is actually squared distance. + The computed gradient. )ipc_Qu8mg5v7", py::arg("p0"), py::arg("p1")); @@ -47,15 +47,15 @@ void define_point_point_distance(py::module_& m) R"ipc_Qu8mg5v7( Compute the hessian of the distance between two points. + Note: + The distance is actually squared distance. + Parameters: p0: The first point. p1: The second point. Returns: - The hessian of the distance wrt p0 and p1. - - Note: - The distance is actually squared distance. + The computed hessian. )ipc_Qu8mg5v7", py::arg("p0"), py::arg("p1")); } diff --git a/python/src/distance/point_triangle.cpp b/python/src/distance/point_triangle.cpp index 664851b1d..2ac91f825 100644 --- a/python/src/distance/point_triangle.cpp +++ b/python/src/distance/point_triangle.cpp @@ -13,6 +13,9 @@ void define_point_triangle_distance(py::module_& m) R"ipc_Qu8mg5v7( Compute the distance between a points and a triangle. + Note: + The distance is actually squared distance. + Parameters: p: The point. t0: The first vertex of the triangle. @@ -22,9 +25,6 @@ void define_point_triangle_distance(py::module_& m) Returns: The distance between the point and triangle. - - Note: - The distance is actually squared distance. )ipc_Qu8mg5v7", py::arg("p"), py::arg("t0"), py::arg("t1"), py::arg("t2"), py::arg("dtype") = PointTriangleDistanceType::AUTO); @@ -34,6 +34,9 @@ void define_point_triangle_distance(py::module_& m) R"ipc_Qu8mg5v7( Compute the gradient of the distance between a points and a triangle. + Note: + The distance is actually squared distance. + Parameters: p: The point. t0: The first vertex of the triangle. @@ -43,9 +46,6 @@ void define_point_triangle_distance(py::module_& m) Returns: The gradient of the distance wrt p, t0, t1, and t2. - - Note: - The distance is actually squared distance. )ipc_Qu8mg5v7", py::arg("p"), py::arg("t0"), py::arg("t1"), py::arg("t2"), py::arg("dtype") = PointTriangleDistanceType::AUTO); @@ -55,6 +55,9 @@ void define_point_triangle_distance(py::module_& m) R"ipc_Qu8mg5v7( Compute the hessian of the distance between a points and a triangle. + Note: + The distance is actually squared distance. + Parameters: p: The point. t0: The first vertex of the triangle. @@ -64,9 +67,6 @@ void define_point_triangle_distance(py::module_& m) Returns: The hessian of the distance wrt p, t0, t1, and t2. - - Note: - The distance is actually squared distance. )ipc_Qu8mg5v7", py::arg("p"), py::arg("t0"), py::arg("t1"), py::arg("t2"), py::arg("dtype") = PointTriangleDistanceType::AUTO); diff --git a/src/ipc/distance/line_line.hpp b/src/ipc/distance/line_line.hpp index 313c317c8..86a3556d6 100644 --- a/src/ipc/distance/line_line.hpp +++ b/src/ipc/distance/line_line.hpp @@ -25,7 +25,7 @@ double line_line_distance( /// @param ea1 The second vertex of the edge defining the first line. /// @param ea0 The first vertex of the edge defining the second line. /// @param ea1 The second vertex of the edge defining the second line. -/// @return grad The gradient of the distance wrt ea0, ea1, eb0, and eb1. +/// @return The gradient of the distance wrt ea0, ea1, eb0, and eb1. Vector12d line_line_distance_gradient( const Eigen::Ref& ea0, const Eigen::Ref& ea1, @@ -39,7 +39,7 @@ Vector12d line_line_distance_gradient( /// @param ea1 The second vertex of the edge defining the first line. /// @param ea0 The first vertex of the edge defining the second line. /// @param ea1 The second vertex of the edge defining the second line. -/// @return hess The hessian of the distance wrt ea0, ea1, eb0, and eb1. +/// @return The hessian of the distance wrt ea0, ea1, eb0, and eb1. Matrix12d line_line_distance_hessian( const Eigen::Ref& ea0, const Eigen::Ref& ea1, From f1ec243e17b37ef7d012a734e342bc8f88da265d Mon Sep 17 00:00:00 2001 From: Zachary Ferguson Date: Tue, 31 Oct 2023 11:34:07 -0400 Subject: [PATCH 03/10] Remove overridden functions --- python/src/broad_phase/broad_phase.cpp | 12 +- python/src/broad_phase/brute_force.cpp | 42 +--- python/src/broad_phase/bvh.cpp | 105 +-------- python/src/broad_phase/hash_grid.cpp | 96 -------- python/src/broad_phase/spatial_hash.cpp | 40 ---- .../broad_phase/sweep_and_tiniest_queue.cpp | 210 +----------------- 6 files changed, 10 insertions(+), 495 deletions(-) diff --git a/python/src/broad_phase/broad_phase.cpp b/python/src/broad_phase/broad_phase.cpp index bb1c995ee..9ab0fd025 100644 --- a/python/src/broad_phase/broad_phase.cpp +++ b/python/src/broad_phase/broad_phase.cpp @@ -72,7 +72,7 @@ void define_broad_phase(py::module_& m) .def("clear", &BroadPhase::clear, "Clear any built data.") .def( "detect_vertex_vertex_candidates", - [](BroadPhase& self) { + [](const BroadPhase& self) { std::vector candidates; self.detect_vertex_vertex_candidates(candidates); return candidates; @@ -85,7 +85,7 @@ void define_broad_phase(py::module_& m) )ipc_Qu8mg5v7") .def( "detect_edge_vertex_candidates", - [](BroadPhase& self) { + [](const BroadPhase& self) { std::vector candidates; self.detect_edge_vertex_candidates(candidates); return candidates; @@ -98,7 +98,7 @@ void define_broad_phase(py::module_& m) )ipc_Qu8mg5v7") .def( "detect_edge_edge_candidates", - [](BroadPhase& self) { + [](const BroadPhase& self) { std::vector candidates; self.detect_edge_edge_candidates(candidates); return candidates; @@ -111,7 +111,7 @@ void define_broad_phase(py::module_& m) )ipc_Qu8mg5v7") .def( "detect_face_vertex_candidates", - [](BroadPhase& self) { + [](const BroadPhase& self) { std::vector candidates; self.detect_face_vertex_candidates(candidates); return candidates; @@ -124,7 +124,7 @@ void define_broad_phase(py::module_& m) )ipc_Qu8mg5v7") .def( "detect_edge_face_candidates", - [](BroadPhase& self) { + [](const BroadPhase& self) { std::vector candidates; self.detect_edge_face_candidates(candidates); return candidates; @@ -137,7 +137,7 @@ void define_broad_phase(py::module_& m) )ipc_Qu8mg5v7") .def( "detect_collision_candidates", - [](BroadPhase& self, int dim) { + [](const BroadPhase& self, int dim) { Candidates candidates; self.detect_collision_candidates(dim, candidates); return candidates; diff --git a/python/src/broad_phase/brute_force.cpp b/python/src/broad_phase/brute_force.cpp index 8f957f4ef..045123fc7 100644 --- a/python/src/broad_phase/brute_force.cpp +++ b/python/src/broad_phase/brute_force.cpp @@ -7,45 +7,5 @@ using namespace ipc; void define_brute_force(py::module_& m) { - py::class_(m, "BruteForce") - .def( - "detect_vertex_vertex_candidates", - [](BruteForce& self) { - std::vector candidates; - self.detect_vertex_vertex_candidates(candidates); - return candidates; - }, - "Find the candidate vertex-vertex collisions.") - .def( - "detect_edge_vertex_candidates", - [](BruteForce& self) { - std::vector candidates; - self.detect_edge_vertex_candidates(candidates); - return candidates; - }, - "Find the candidate edge-vertex collisions.") - .def( - "detect_edge_edge_candidates", - [](BruteForce& self) { - std::vector candidates; - self.detect_edge_edge_candidates(candidates); - return candidates; - }, - "Find the candidate edge-edge collisions.") - .def( - "detect_face_vertex_candidates", - [](BruteForce& self) { - std::vector candidates; - self.detect_face_vertex_candidates(candidates); - return candidates; - }, - "Find the candidate face-vertex collisions.") - .def( - "detect_edge_face_candidates", - [](BruteForce& self) { - std::vector candidates; - self.detect_edge_face_candidates(candidates); - return candidates; - }, - "Find the candidate edge-face intersections."); + py::class_(m, "BruteForce"); } diff --git a/python/src/broad_phase/bvh.cpp b/python/src/broad_phase/bvh.cpp index 91a5665f2..5d9f78d65 100644 --- a/python/src/broad_phase/bvh.cpp +++ b/python/src/broad_phase/bvh.cpp @@ -5,107 +5,4 @@ namespace py = pybind11; using namespace ipc; -void define_bvh(py::module_& m) -{ - py::class_(m, "BVH") - .def( - "build", - py::overload_cast< - const Eigen::MatrixXd&, const Eigen::MatrixXi&, - const Eigen::MatrixXi&, const double>(&BVH::build), - R"ipc_Qu8mg5v7( - Build the broad phase for static collision detection. - - Parameters: - V0: Positions of the vertices. - E: Edges of the mesh. - F: Faces of the mesh. - inflation_radius: Radius of inflation around all elements. - )ipc_Qu8mg5v7", - py::arg("V"), py::arg("E"), py::arg("F"), - py::arg("inflation_radius") = 0) - .def( - "build", - py::overload_cast< - const Eigen::MatrixXd&, const Eigen::MatrixXd&, - const Eigen::MatrixXi&, const Eigen::MatrixXi&, const double>( - &BVH::build), - R"ipc_Qu8mg5v7( - Build the broad phase for continuous collision detection. - - Parameters: - V0: Starting positions of the vertices. - V1: Ending positions of the vertices. - E: Edges of the mesh. - F: Faces of the mesh. - inflation_radius: Radius of inflation around all elements. - )ipc_Qu8mg5v7", - py::arg("V0"), py::arg("V1"), py::arg("E"), py::arg("F"), - py::arg("inflation_radius") = 0) - .def("clear", &BVH::clear, "Clear any built data.") - .def( - "detect_vertex_vertex_candidates", - [](BVH& self) { - std::vector candidates; - self.detect_vertex_vertex_candidates(candidates); - return candidates; - }, - R"ipc_Qu8mg5v7( - Find the candidate vertex-vertex collisions. - - Returns: - The candidate vertex-vertex collisions. - )ipc_Qu8mg5v7") - .def( - "detect_edge_vertex_candidates", - [](BVH& self) { - std::vector candidates; - self.detect_edge_vertex_candidates(candidates); - return candidates; - }, - R"ipc_Qu8mg5v7( - Find the candidate edge-vertex collisions. - - Returns: - The candidate edge-vertex collisions. - )ipc_Qu8mg5v7") - .def( - "detect_edge_edge_candidates", - [](BVH& self) { - std::vector candidates; - self.detect_edge_edge_candidates(candidates); - return candidates; - }, - R"ipc_Qu8mg5v7( - Find the candidate edge-edge collisions. - - Returns: - The candidate edge-edge collisions. - )ipc_Qu8mg5v7") - .def( - "detect_face_vertex_candidates", - [](BVH& self) { - std::vector candidates; - self.detect_face_vertex_candidates(candidates); - return candidates; - }, - R"ipc_Qu8mg5v7( - Find the candidate face-vertex collisions. - - Returns: - The candidate face-vertex collisions. - )ipc_Qu8mg5v7") - .def( - "detect_edge_face_candidates", - [](BVH& self) { - std::vector candidates; - self.detect_edge_face_candidates(candidates); - return candidates; - }, - R"ipc_Qu8mg5v7( - Find the candidate edge-face intersections. - - Returns: - The candidate edge-face intersections. - )ipc_Qu8mg5v7"); -} +void define_bvh(py::module_& m) { py::class_(m, "BVH"); } diff --git a/python/src/broad_phase/hash_grid.cpp b/python/src/broad_phase/hash_grid.cpp index 1d76df276..ca46aaf7a 100644 --- a/python/src/broad_phase/hash_grid.cpp +++ b/python/src/broad_phase/hash_grid.cpp @@ -19,102 +19,6 @@ void define_hash_grid(py::module_& m) .def_readwrite("id", &HashItem::id, "The value of the item."); py::class_(m, "HashGrid") - .def(py::init()) - .def( - "build", - py::overload_cast< - const Eigen::MatrixXd&, const Eigen::MatrixXi&, - const Eigen::MatrixXi&, double>(&HashGrid::build), - R"ipc_Qu8mg5v7( - Build the broad phase for static collision detection. - - Parameters: - vertices: Vertex positions - edges: Collision mesh edges - faces: Collision mesh faces - inflation_radius: Radius of inflation around all elements. - )ipc_Qu8mg5v7", - py::arg("vertices"), py::arg("edges"), py::arg("faces"), - py::arg("inflation_radius") = 0) - .def( - "build", - py::overload_cast< - const Eigen::MatrixXd&, const Eigen::MatrixXd&, - const Eigen::MatrixXi&, const Eigen::MatrixXi&, double>( - &HashGrid::build), - R"ipc_Qu8mg5v7( - Build the broad phase for continuous collision detection. - - Parameters: - vertices_t0: Starting vertices of the vertices. - vertices_t1: Ending vertices of the vertices. - edges: Collision mesh edges - faces: Collision mesh faces - inflation_radius: Radius of inflation around all elements. - )ipc_Qu8mg5v7", - py::arg("vertices_t0"), py::arg("vertices_t1"), py::arg("edges"), - py::arg("faces"), py::arg("inflation_radius") = 0) - .def("clear", &HashGrid::clear, "Clear the hash grid.") - .def( - "detect_vertex_vertex_candidates", - [](HashGrid& self) { - std::vector candidates; - self.detect_vertex_vertex_candidates(candidates); - return candidates; - }, - "Find the candidate vertex-vertex collisions.") - .def( - "detect_edge_vertex_candidates", - [](HashGrid& self) { - std::vector candidates; - self.detect_edge_vertex_candidates(candidates); - return candidates; - }, - R"ipc_Qu8mg5v7( - Find the candidate edge-vertex collisions. - - Returns: - The candidate edge-vertex collisions. - )ipc_Qu8mg5v7") - .def( - "detect_edge_edge_candidates", - [](HashGrid& self) { - std::vector candidates; - self.detect_edge_edge_candidates(candidates); - return candidates; - }, - R"ipc_Qu8mg5v7( - Find the candidate edge-edge collisions. - - Returns: - The candidate edge-edge collisions. - )ipc_Qu8mg5v7") - .def( - "detect_face_vertex_candidates", - [](HashGrid& self) { - std::vector candidates; - self.detect_face_vertex_candidates(candidates); - return candidates; - }, - R"ipc_Qu8mg5v7( - Find the candidate face-vertex collisions. - - Returns: - The candidate face-vertex collisions. - )ipc_Qu8mg5v7") - .def( - "detect_edge_face_candidates", - [](HashGrid& self) { - std::vector candidates; - self.detect_edge_face_candidates(candidates); - return candidates; - }, - R"ipc_Qu8mg5v7( - Find the candidate edge-face intersections. - - Returns: - The candidate edge-face intersections. - )ipc_Qu8mg5v7") .def("cellSize", &HashGrid::cellSize) .def( "gridSize", &HashGrid::gridSize, py::return_value_policy::reference) diff --git a/python/src/broad_phase/spatial_hash.cpp b/python/src/broad_phase/spatial_hash.cpp index 2d0af8b7c..9001bbcb5 100644 --- a/python/src/broad_phase/spatial_hash.cpp +++ b/python/src/broad_phase/spatial_hash.cpp @@ -55,46 +55,6 @@ void define_spatial_hash(py::module_& m) .def( "to_triangle_index", &SpatialHash::to_triangle_index, "Convert a primitive index to a triangle index.", py::arg("idx")) - .def( - "detect_vertex_vertex_candidates", - [](SpatialHash& self) { - std::vector candidates; - self.detect_vertex_vertex_candidates(candidates); - return candidates; - }, - "Find the candidate vertex-vertex collisions.") - .def( - "detect_edge_vertex_candidates", - [](SpatialHash& self) { - std::vector candidates; - self.detect_edge_vertex_candidates(candidates); - return candidates; - }, - "Find the candidate edge-vertex collisions.") - .def( - "detect_edge_edge_candidates", - [](SpatialHash& self) { - std::vector candidates; - self.detect_edge_edge_candidates(candidates); - return candidates; - }, - "Find the candidate edge-edge collisions.") - .def( - "detect_face_vertex_candidates", - [](SpatialHash& self) { - std::vector candidates; - self.detect_face_vertex_candidates(candidates); - return candidates; - }, - "Find the candidate face-vertex collisions.") - .def( - "detect_edge_face_candidates", - [](SpatialHash& self) { - std::vector candidates; - self.detect_edge_face_candidates(candidates); - return candidates; - }, - "Find the candidate edge-face intersections.") .def_readwrite("left_bottom_corner", &SpatialHash::left_bottom_corner) .def_readwrite("right_top_corner", &SpatialHash::right_top_corner) .def_readwrite("voxel_count", &SpatialHash::voxel_count) diff --git a/python/src/broad_phase/sweep_and_tiniest_queue.cpp b/python/src/broad_phase/sweep_and_tiniest_queue.cpp index 757f70fb7..39ba6b72b 100644 --- a/python/src/broad_phase/sweep_and_tiniest_queue.cpp +++ b/python/src/broad_phase/sweep_and_tiniest_queue.cpp @@ -9,214 +9,8 @@ void define_sweep_and_tiniest_queue(py::module_& m) { py::class_(m, "CopyMeshBroadPhase"); - py::class_( - m, "SweepAndTiniestQueue") - .def(py::init()) - .def( - "build", - py::overload_cast< - const Eigen::MatrixXd&, const Eigen::MatrixXi&, - const Eigen::MatrixXi&, double>(&SweepAndTiniestQueue::build), - R"ipc_Qu8mg5v7( - Build the broad phase for static collision detection. - - Parameters: - vertices: Vertex positions - edges: Collision mesh edges - faces: Collision mesh faces - inflation_radius: Radius of inflation around all elements. - )ipc_Qu8mg5v7", - py::arg("vertices"), py::arg("edges"), py::arg("faces"), - py::arg("inflation_radius") = 0) - .def( - "build", - py::overload_cast< - const Eigen::MatrixXd&, const Eigen::MatrixXd&, - const Eigen::MatrixXi&, const Eigen::MatrixXi&, double>( - &SweepAndTiniestQueue::build), - R"ipc_Qu8mg5v7( - Build the broad phase for continuous collision detection. - - Parameters: - vertices_t0: Starting vertex positions - vertices_t1: Ending vertex positions - edges: Collision mesh edges - faces: Collision mesh faces - inflation_radius: Radius of inflation around all elements. - )ipc_Qu8mg5v7", - py::arg("vertices_t0"), py::arg("vertices_t1"), py::arg("edges"), - py::arg("faces"), py::arg("inflation_radius") = 0) - .def("clear", &SweepAndTiniestQueue::clear, "Clear any built data.") - .def( - "detect_vertex_vertex_candidates", - [](SweepAndTiniestQueue& self) { - std::vector candidates; - self.detect_vertex_vertex_candidates(candidates); - return candidates; - }, - R"ipc_Qu8mg5v7( - Find the candidate vertex-vertex collisions. - - Returns: - The candidate vertex-vertex collisions. - )ipc_Qu8mg5v7") - .def( - "detect_edge_vertex_candidates", - [](SweepAndTiniestQueue& self) { - std::vector candidates; - self.detect_edge_vertex_candidates(candidates); - return candidates; - }, - R"ipc_Qu8mg5v7( - Find the candidate edge-vertex collisions. - - Returns: - The candidate edge-vertex collisions. - )ipc_Qu8mg5v7") - .def( - "detect_edge_edge_candidates", - [](SweepAndTiniestQueue& self) { - std::vector candidates; - self.detect_edge_edge_candidates(candidates); - return candidates; - }, - R"ipc_Qu8mg5v7( - Find the candidate edge-edge collisions. - - Returns: - The candidate edge-edge collisions. - )ipc_Qu8mg5v7") - .def( - "detect_face_vertex_candidates", - [](SweepAndTiniestQueue& self) { - std::vector candidates; - self.detect_face_vertex_candidates(candidates); - return candidates; - }, - R"ipc_Qu8mg5v7( - Find the candidate face-vertex collisions. - - Returns: - The candidate face-vertex collisions. - )ipc_Qu8mg5v7") - .def( - "detect_edge_face_candidates", - [](SweepAndTiniestQueue& self) { - std::vector candidates; - self.detect_edge_face_candidates(candidates); - return candidates; - }, - R"ipc_Qu8mg5v7( - Find the candidate edge-face intersections. - - Returns: - The candidate edge-face intersections. - )ipc_Qu8mg5v7"); - #ifdef IPC_TOOLKIT_WITH_CUDA - py::class_( - m, "SweepAndTiniestQueueGPU") - .def(py::init()) - .def( - "build", - py::overload_cast< - const Eigen::MatrixXd&, const Eigen::MatrixXi&, - const Eigen::MatrixXi&, double>( - &SweepAndTiniestQueueGPU::build), - R"ipc_Qu8mg5v7( - Build the broad phase for static collision detection. - - Parameters: - vertices: Vertex positions - edges: Collision mesh edges - faces: Collision mesh faces - inflation_radius: Radius of inflation around all elements. - )ipc_Qu8mg5v7", - py::arg("vertices"), py::arg("edges"), py::arg("faces"), - py::arg("inflation_radius") = 0) - .def( - "build", - py::overload_cast< - const Eigen::MatrixXd&, const Eigen::MatrixXd&, - const Eigen::MatrixXi&, const Eigen::MatrixXi&, double>( - &SweepAndTiniestQueueGPU::build), - R"ipc_Qu8mg5v7( - Build the broad phase for continuous collision detection. - - Parameters: - vertices_t0: Starting vertex positions - vertices_t1: Ending vertex positions - edges: Collision mesh edges - faces: Collision mesh faces - inflation_radius: Radius of inflation around all elements. - )ipc_Qu8mg5v7", - py::arg("vertices_t0"), py::arg("vertices_t1"), py::arg("edges"), - py::arg("faces"), py::arg("inflation_radius") = 0) - .def("clear", &SweepAndTiniestQueueGPU::clear, "Clear any built data.") - .def( - "detect_vertex_vertex_candidates", - [](SweepAndTiniestQueueGPU& self) { - std::vector candidates; - self.detect_vertex_vertex_candidates(candidates); - return candidates; - }, - R"ipc_Qu8mg5v7( - Find the candidate vertex-vertex collisions. - - Returns: - The candidate vertex-vertex collisions. - )ipc_Qu8mg5v7") - .def( - "detect_edge_vertex_candidates", - [](SweepAndTiniestQueueGPU& self) { - std::vector candidates; - self.detect_edge_vertex_candidates(candidates); - return candidates; - }, - R"ipc_Qu8mg5v7( - Find the candidate edge-vertex collisions. - - Returns: - The candidate edge-vertex collisions. - )ipc_Qu8mg5v7") - .def( - "detect_edge_edge_candidates", - [](SweepAndTiniestQueueGPU& self) { - std::vector candidates; - self.detect_edge_edge_candidates(candidates); - return candidates; - }, - R"ipc_Qu8mg5v7( - Find the candidate edge-edge collisions. - - Returns: - The candidate edge-edge collisions. - )ipc_Qu8mg5v7") - .def( - "detect_face_vertex_candidates", - [](SweepAndTiniestQueueGPU& self) { - std::vector candidates; - self.detect_face_vertex_candidates(candidates); - return candidates; - }, - R"ipc_Qu8mg5v7( - Find the candidate face-vertex collisions. - - Returns: - The candidate face-vertex collisions. - )ipc_Qu8mg5v7") - .def( - "detect_edge_face_candidates", - [](SweepAndTiniestQueueGPU& self) { - std::vector candidates; - self.detect_edge_face_candidates(candidates); - return candidates; - }, - R"ipc_Qu8mg5v7( - Find the candidate edge-face intersections. - - Returns: - The candidate edge-face intersections. - )ipc_Qu8mg5v7"); + py::class_( + m, "SweepAndTiniestQueue"); #endif } From 9d970f8a885c84509ee17e387395481a3f5b2336 Mon Sep 17 00:00:00 2001 From: Zachary Ferguson Date: Tue, 31 Oct 2023 13:38:09 -0400 Subject: [PATCH 04/10] Remove overridden bindings --- .gitignore | 1 + python/src/candidates/edge_edge.cpp | 4 ---- python/src/candidates/edge_vertex.cpp | 14 ----------- python/src/candidates/face_vertex.cpp | 14 ----------- python/src/candidates/vertex_vertex.cpp | 24 ------------------- .../src/collisions/collision_constraint.cpp | 3 ++- python/src/collisions/edge_edge.cpp | 14 ----------- python/src/collisions/plane_vertex.cpp | 4 ---- 8 files changed, 3 insertions(+), 75 deletions(-) diff --git a/.gitignore b/.gitignore index 818fdfccb..a4231f67e 100644 --- a/.gitignore +++ b/.gitignore @@ -266,3 +266,4 @@ docs/_doxygen notebooks/*.[ch]pp tests/data/cloth_ball_bf_ccd_candidated.json +python/update_bindings.py diff --git a/python/src/candidates/edge_edge.cpp b/python/src/candidates/edge_edge.cpp index dd191dea4..786ed4986 100644 --- a/python/src/candidates/edge_edge.cpp +++ b/python/src/candidates/edge_edge.cpp @@ -22,10 +22,6 @@ void define_edge_edge_candidate(py::module_& m) return fmt::format( "EdgeEdgeCandidate({:d}, {:d})", ev.edge0_id, ev.edge1_id); }) - .def("num_vertices", &EdgeEdgeCandidate::num_vertices) - .def( - "vertex_ids", &EdgeEdgeCandidate::vertex_ids, py::arg("edges"), - py::arg("faces")) .def("__eq__", &EdgeEdgeCandidate::operator==, py::arg("other")) .def("__ne__", &EdgeEdgeCandidate::operator!=, py::arg("other")) .def( diff --git a/python/src/candidates/edge_vertex.cpp b/python/src/candidates/edge_vertex.cpp index 82e64b9f1..1dddbf541 100644 --- a/python/src/candidates/edge_vertex.cpp +++ b/python/src/candidates/edge_vertex.cpp @@ -23,20 +23,6 @@ void define_edge_vertex_candidate(py::module_& m) "EdgeVertexCandidate({:d}, {:d})", ev.edge_id, ev.vertex_id); }) - .def("num_vertices", &EdgeVertexCandidate::num_vertices) - .def( - "vertex_ids", &EdgeVertexCandidate::vertex_ids, py::arg("edges"), - py::arg("faces")) - .def( - "print_ccd_query", - [](EdgeVertexCandidate& self, const Eigen::MatrixXd& vertices_t0, - const Eigen::MatrixXd& vertices_t1, const Eigen::MatrixXi& edges, - const Eigen::MatrixXi& faces) -> void { - self.write_ccd_query( - std::cout, vertices_t0, vertices_t1, edges, faces); - }, - py::arg("vertices_t0"), py::arg("vertices_t1"), py::arg("edges"), - py::arg("faces")) .def("__eq__", &EdgeVertexCandidate::operator==, py::arg("other")) .def("__ne__", &EdgeVertexCandidate::operator!=, py::arg("other")) .def( diff --git a/python/src/candidates/face_vertex.cpp b/python/src/candidates/face_vertex.cpp index 2b6fd6ec7..c5572d94a 100644 --- a/python/src/candidates/face_vertex.cpp +++ b/python/src/candidates/face_vertex.cpp @@ -23,20 +23,6 @@ void define_face_vertex_candidate(py::module_& m) "FaceVertexCandidate({:d}, {:d})", ev.face_id, ev.vertex_id); }) - .def("num_vertices", &FaceVertexCandidate::num_vertices) - .def( - "vertex_ids", &FaceVertexCandidate::vertex_ids, py::arg("edges"), - py::arg("faces")) - .def( - "print_ccd_query", - [](FaceVertexCandidate& self, const Eigen::MatrixXd& vertices_t0, - const Eigen::MatrixXd& vertices_t1, const Eigen::MatrixXi& edges, - const Eigen::MatrixXi& faces) -> void { - self.write_ccd_query( - std::cout, vertices_t0, vertices_t1, edges, faces); - }, - py::arg("vertices_t0"), py::arg("vertices_t1"), py::arg("edges"), - py::arg("faces")) .def("__eq__", &FaceVertexCandidate::operator==, py::arg("other")) .def("__ne__", &FaceVertexCandidate::operator!=, py::arg("other")) .def( diff --git a/python/src/candidates/vertex_vertex.cpp b/python/src/candidates/vertex_vertex.cpp index dcd59da47..f27ba9541 100644 --- a/python/src/candidates/vertex_vertex.cpp +++ b/python/src/candidates/vertex_vertex.cpp @@ -26,30 +26,6 @@ void define_vertex_vertex_candidate(py::module_& m) "VertexVertexCandidate({:d}, {:d})", ev.vertex0_id, ev.vertex1_id); }) - .def("num_vertices", &VertexVertexCandidate::num_vertices) - .def( - "vertex_ids", &VertexVertexCandidate::vertex_ids, - R"ipc_Qu8mg5v7( - Get the indices of the vertices - - Parameters: - edges: edge matrix of mesh - faces: face matrix of mesh - - Returns: - List of vertex indices - )ipc_Qu8mg5v7", - py::arg("edges"), py::arg("faces")) - .def( - "print_ccd_query", - [](VertexVertexCandidate& self, const Eigen::MatrixXd& vertices_t0, - const Eigen::MatrixXd& vertices_t1, const Eigen::MatrixXi& edges, - const Eigen::MatrixXi& faces) { - self.write_ccd_query( - std::cout, vertices_t0, vertices_t1, edges, faces); - }, - py::arg("vertices_t0"), py::arg("vertices_t1"), py::arg("edges"), - py::arg("faces")) .def("__eq__", &VertexVertexCandidate::operator==, py::arg("other")) .def("__ne__", &VertexVertexCandidate::operator!=, py::arg("other")) .def( diff --git a/python/src/collisions/collision_constraint.cpp b/python/src/collisions/collision_constraint.cpp index bee897b63..eeb21cefb 100644 --- a/python/src/collisions/collision_constraint.cpp +++ b/python/src/collisions/collision_constraint.cpp @@ -27,7 +27,8 @@ void define_collision_constraint(py::module_& m) py::arg("dhat"), py::arg("project_hessian_to_psd")) .def( "compute_shape_derivative", - [](CollisionConstraint& self, const Eigen::MatrixXd& rest_positions, + [](const CollisionConstraint& self, + const Eigen::MatrixXd& rest_positions, const Eigen::MatrixXd& vertices, const Eigen::MatrixXi& edges, const Eigen::MatrixXi& faces, const double dhat) { std::vector> triplets; diff --git a/python/src/collisions/edge_edge.cpp b/python/src/collisions/edge_edge.cpp index b138b281b..c9d677d9e 100644 --- a/python/src/collisions/edge_edge.cpp +++ b/python/src/collisions/edge_edge.cpp @@ -29,20 +29,6 @@ void define_edge_edge_constraint(py::module_& m) // py::arg("edge0_id"), py::arg("edge1_id"), py::arg("eps_x"), // py::arg("weight"), py::arg("weight_gradient"), // py::arg("dtype") = EdgeEdgeDistanceType::AUTO) - .def( - "compute_potential", &EdgeEdgeConstraint::compute_potential, - py::arg("vertices"), py::arg("edges"), py::arg("faces"), - py::arg("dhat")) - .def( - "compute_potential_gradient", - &EdgeEdgeConstraint::compute_potential_gradient, - py::arg("vertices"), py::arg("edges"), py::arg("faces"), - py::arg("dhat")) - .def( - "compute_potential_hessian", - &EdgeEdgeConstraint::compute_potential_hessian, py::arg("vertices"), - py::arg("edges"), py::arg("faces"), py::arg("dhat"), - py::arg("project_hessian_to_psd")) .def("__eq__", &EdgeEdgeConstraint::operator==, py::arg("other")) .def("__ne__", &EdgeEdgeConstraint::operator!=, py::arg("other")) .def("__lt__", &EdgeEdgeConstraint::operator<, py::arg("other")) diff --git a/python/src/collisions/plane_vertex.cpp b/python/src/collisions/plane_vertex.cpp index 2c4dc932b..ff72f8519 100644 --- a/python/src/collisions/plane_vertex.cpp +++ b/python/src/collisions/plane_vertex.cpp @@ -13,10 +13,6 @@ void define_plane_vertex_constraint(py::module_& m) py::init(), py::arg("plane_origin"), py::arg("plane_normal"), py::arg("vertex_id")) - .def("num_vertices", &PlaneVertexConstraint::num_vertices) - .def( - "vertex_ids", &PlaneVertexConstraint::vertex_ids, py::arg("edges"), - py::arg("faces")) .def_readwrite("plane_origin", &PlaneVertexConstraint::plane_origin) .def_readwrite("plane_normal", &PlaneVertexConstraint::plane_normal) .def_readwrite("vertex_id", &PlaneVertexConstraint::vertex_id); From cf2804e8ea2b60344841809dabd62ce11e255561 Mon Sep 17 00:00:00 2001 From: Zachary Ferguson Date: Tue, 31 Oct 2023 13:58:23 -0400 Subject: [PATCH 05/10] Resolve comments --- python/src/broad_phase/aabb.cpp | 4 ++-- src/ipc/broad_phase/aabb.hpp | 4 ++-- src/ipc/distance/distance_type.hpp | 16 ++++++++-------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/python/src/broad_phase/aabb.cpp b/python/src/broad_phase/aabb.cpp index 8c7bc6685..895e72efe 100644 --- a/python/src/broad_phase/aabb.cpp +++ b/python/src/broad_phase/aabb.cpp @@ -23,7 +23,7 @@ void define_aabb(py::module_& m) py::overload_cast( &AABB::from_point), R"ipc_Qu8mg5v7( - Construct a AABB for a static point. + Construct an AABB for a static point. Parameters: p: The point's position. @@ -39,7 +39,7 @@ void define_aabb(py::module_& m) const VectorMax3d&, const VectorMax3d&, const double>( &AABB::from_point), R"ipc_Qu8mg5v7( - Construct a AABB for a moving point (i.e. temporal edge). + Construct an AABB for a moving point (i.e. temporal edge). Parameters: p_t0: The point's position at time t=0. diff --git a/src/ipc/broad_phase/aabb.hpp b/src/ipc/broad_phase/aabb.hpp index 39b144c49..9f4dfdd97 100644 --- a/src/ipc/broad_phase/aabb.hpp +++ b/src/ipc/broad_phase/aabb.hpp @@ -25,14 +25,14 @@ class AABB { { } - /// @brief Construct a AABB for a static point. + /// @brief Construct an AABB for a static point. /// @param p The point's position. /// @param inflation_radius Radius of a sphere around the point which the AABB encloses. /// @return The constructed AABB. static AABB from_point(const VectorMax3d& p, const double inflation_radius = 0); - /// @brief Construct a AABB for a moving point (i.e. temporal edge). + /// @brief Construct an AABB for a moving point (i.e. temporal edge). /// @param p_t0 The point's position at time t=0. /// @param p_t1 The point's position at time t=1. /// @param inflation_radius Radius of a capsule around the temporal edge which the AABB encloses. diff --git a/src/ipc/distance/distance_type.hpp b/src/ipc/distance/distance_type.hpp index 11f9122ce..5fddda16c 100644 --- a/src/ipc/distance/distance_type.hpp +++ b/src/ipc/distance/distance_type.hpp @@ -14,14 +14,14 @@ enum class PointEdgeDistanceType { /// @brief Closest pair between a point and triangle. enum class PointTriangleDistanceType { - P_T0, /// The point is closest to triangle vertex zero. - P_T1, /// The point is closest to triangle vertex one. - P_T2, /// The point is closest to triangle vertex two. - P_E0, /// The point is closest to triangle edge zero (vertex zero to one). - P_E1, /// The point is closest to triangle edge one (vertex one to two). - P_E2, /// The point is closest to triangle edge two (vertex two to zero). - P_T, /// The point is closest to the interior of the triangle. - AUTO /// Automatically determine the closest pair. + P_T0, ///< The point is closest to triangle vertex zero. + P_T1, ///< The point is closest to triangle vertex one. + P_T2, ///< The point is closest to triangle vertex two. + P_E0, ///< The point is closest to triangle edge zero (vertex zero to one). + P_E1, ///< The point is closest to triangle edge one (vertex one to two). + P_E2, ///< The point is closest to triangle edge two (vertex two to zero). + P_T, ///< The point is closest to the interior of the triangle. + AUTO ///< Automatically determine the closest pair. }; /// @brief Closest pair between two edges. From 9ebf6724344fa2bdab86c63e96ac2e42adbc8452 Mon Sep 17 00:00:00 2001 From: Zachary Ferguson Date: Tue, 31 Oct 2023 14:11:06 -0400 Subject: [PATCH 06/10] Fix STQ bindings --- python/src/broad_phase/sweep_and_tiniest_queue.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python/src/broad_phase/sweep_and_tiniest_queue.cpp b/python/src/broad_phase/sweep_and_tiniest_queue.cpp index 39ba6b72b..c8ca1f07f 100644 --- a/python/src/broad_phase/sweep_and_tiniest_queue.cpp +++ b/python/src/broad_phase/sweep_and_tiniest_queue.cpp @@ -9,8 +9,11 @@ void define_sweep_and_tiniest_queue(py::module_& m) { py::class_(m, "CopyMeshBroadPhase"); -#ifdef IPC_TOOLKIT_WITH_CUDA py::class_( m, "SweepAndTiniestQueue"); + +#ifdef IPC_TOOLKIT_WITH_CUDA + py::class_( + m, "SweepAndTiniestQueueGPU"); #endif } From be820bd2d7ce09015cfd37bd3db2525efdcb70ea Mon Sep 17 00:00:00 2001 From: Zachary Ferguson Date: Wed, 1 Nov 2023 02:42:46 -0400 Subject: [PATCH 07/10] Bind NonlinearTrajectory and Interval --- cmake/recipes/filib.cmake | 2 +- cmake/recipes/pybind11.cmake | 2 +- docs/source/Doxyfile | 2 +- docs/source/cpp-api/ccd.rst | 39 +++- docs/source/cpp-api/intersections.rst | 5 + docs/source/cpp-api/utils.rst | 13 +- docs/source/index.rst | 2 + docs/source/python-api/ccd.rst | 44 ++++- docs/source/python-api/intersections.rst | 6 + docs/source/python-api/utils.rst | 6 + python/CMakeLists.txt | 1 + python/src/bindings.cpp | 1 + python/src/ccd/nonlinear_ccd.cpp | 39 +++- python/src/utils/bindings.hpp | 1 + python/src/utils/interval.cpp | 234 +++++++++++++++++++++++ python/tests/test_ccd.py | 56 ++++++ python/tests/test_interval.py | 144 ++++++++++++++ src/ipc/ccd/nonlinear_ccd.cpp | 32 ++-- src/ipc/ccd/nonlinear_ccd.hpp | 1 - src/ipc/utils/interval.cpp | 4 +- src/ipc/utils/interval.hpp | 4 +- 21 files changed, 604 insertions(+), 34 deletions(-) create mode 100644 docs/source/cpp-api/intersections.rst create mode 100644 docs/source/python-api/intersections.rst create mode 100644 python/src/utils/interval.cpp create mode 100644 python/tests/test_interval.py diff --git a/cmake/recipes/filib.cmake b/cmake/recipes/filib.cmake index b4f912688..dcbcc522e 100644 --- a/cmake/recipes/filib.cmake +++ b/cmake/recipes/filib.cmake @@ -7,4 +7,4 @@ endif() message(STATUS "Third-party: creating target 'filib::filib'") include(CPM) -CPMAddPackage("gh:zfergus/filib#63acb1f78dcdf7667ca2d214f7a3fa3505fdf339") \ No newline at end of file +CPMAddPackage("gh:zfergus/filib#1cd377a7c833a68dc47217829e333f4886c5c46d") \ No newline at end of file diff --git a/cmake/recipes/pybind11.cmake b/cmake/recipes/pybind11.cmake index d25797a13..747696283 100644 --- a/cmake/recipes/pybind11.cmake +++ b/cmake/recipes/pybind11.cmake @@ -26,4 +26,4 @@ find_package(Python COMPONENTS Interpreter Development.Module REQUIRED) set(PYTHON_EXECUTABLE ${Python_EXECUTABLE}) include(CPM) -CPMAddPackage("gh:pybind/pybind11@2.10.3") +CPMAddPackage("gh:pybind/pybind11@2.11.1") diff --git a/docs/source/Doxyfile b/docs/source/Doxyfile index ca30f3033..e11032475 100644 --- a/docs/source/Doxyfile +++ b/docs/source/Doxyfile @@ -2332,7 +2332,7 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = +PREDEFINED = IPC_TOOLKIT_WITH_CORRECT_CCD IPC_TOOLKIT_WITH_ROBIN_MAP IPC_TOOLKIT_WITH_ABSEIL IPC_TOOLKIT_WITH_FILIB # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The diff --git a/docs/source/cpp-api/ccd.rst b/docs/source/cpp-api/ccd.rst index 66c552684..4eaf92723 100644 --- a/docs/source/cpp-api/ccd.rst +++ b/docs/source/cpp-api/ccd.rst @@ -9,7 +9,44 @@ Continuous Collision Detection .. doxygenvariable:: ipc::DEFAULT_CCD_MAX_ITERATIONS .. doxygenvariable:: ipc::DEFAULT_CCD_CONSERVATIVE_RESCALING +Individual CCD Functions +------------------------ + .. doxygenfunction:: ipc::point_point_ccd .. doxygenfunction:: ipc::point_edge_ccd .. doxygenfunction:: ipc::edge_edge_ccd -.. doxygenfunction:: ipc::point_triangle_ccd \ No newline at end of file +.. doxygenfunction:: ipc::point_triangle_ccd + +Generic Interface +^^^^^^^^^^^^^^^^^ + +.. doxygenfunction:: ipc::ccd_strategy + +Additive CCD +------------ + +.. doxygenfunction:: ipc::additive_ccd::point_point_ccd +.. doxygenfunction:: ipc::additive_ccd::point_edge_ccd +.. doxygenfunction:: ipc::additive_ccd::edge_edge_ccd +.. doxygenfunction:: ipc::additive_ccd::point_triangle_ccd + +Generic Interface +^^^^^^^^^^^^^^^^^ + +.. doxygenfunction:: ipc::additive_ccd::additive_ccd + +Nonlinear CCD +------------- + +.. doxygenclass:: ipc::NonlinearTrajectory +.. doxygenclass:: ipc::IntervalNonlinearTrajectory + +.. doxygenfunction:: ipc::point_point_nonlinear_ccd +.. doxygenfunction:: ipc::point_edge_nonlinear_ccd +.. doxygenfunction:: ipc::edge_edge_nonlinear_ccd +.. doxygenfunction:: ipc::point_triangle_nonlinear_ccd + +Generic Interface +^^^^^^^^^^^^^^^^^ + +.. doxygenfunction:: ipc::conservative_piecewise_linear_ccd \ No newline at end of file diff --git a/docs/source/cpp-api/intersections.rst b/docs/source/cpp-api/intersections.rst new file mode 100644 index 000000000..ea300814e --- /dev/null +++ b/docs/source/cpp-api/intersections.rst @@ -0,0 +1,5 @@ +Intersections +============= + +.. doxygenfunction:: ipc::has_intersections +.. doxygenfunction:: ipc::is_edge_intersecting_triangle \ No newline at end of file diff --git a/docs/source/cpp-api/utils.rst b/docs/source/cpp-api/utils.rst index 8e45f8f91..818d0631f 100644 --- a/docs/source/cpp-api/utils.rst +++ b/docs/source/cpp-api/utils.rst @@ -1,5 +1,14 @@ Utils ===== -.. doxygenfunction:: compute_minimum_distance -.. doxygenfunction:: has_intersections \ No newline at end of file +Logger +------ + +.. doxygenfunction:: ipc::logger +.. doxygenfunction:: ipc::set_logger + +Positive Semi-Definite Projection +--------------------------------- + +.. doxygenfunction:: ipc::project_to_psd +.. doxygenfunction:: ipc::project_to_pd \ No newline at end of file diff --git a/docs/source/index.rst b/docs/source/index.rst index 12c7c1b3f..185d7850d 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -28,6 +28,7 @@ cpp-api/ccd.rst cpp-api/distance.rst cpp-api/barrier.rst + cpp-api/intersections.rst cpp-api/utils.rst .. toctree:: @@ -43,6 +44,7 @@ python-api/ccd.rst python-api/distance.rst python-api/barrier.rst + python-api/intersections.rst python-api/utils.rst .. toctree:: diff --git a/docs/source/python-api/ccd.rst b/docs/source/python-api/ccd.rst index 4c3733fd1..99fa320da 100644 --- a/docs/source/python-api/ccd.rst +++ b/docs/source/python-api/ccd.rst @@ -5,6 +5,9 @@ Continuous Collision Detection .. autofunction:: ipctk.compute_collision_free_stepsize +Individual CCD Functions +------------------------ + .. .. autovariable:: ipctk.DEFAULT_CCD_TOLERANCE .. .. autovariable:: ipctk.DEFAULT_CCD_MAX_ITERATIONS .. .. autovariable:: ipctk.DEFAULT_CCD_CONSERVATIVE_RESCALING @@ -12,4 +15,43 @@ Continuous Collision Detection .. autofunction:: ipctk.point_point_ccd .. autofunction:: ipctk.point_edge_ccd .. autofunction:: ipctk.edge_edge_ccd -.. autofunction:: ipctk.point_triangle_ccd \ No newline at end of file +.. autofunction:: ipctk.point_triangle_ccd + +Generic Interface +^^^^^^^^^^^^^^^^^ + +.. autofunction:: ipctk.ccd_strategy + +Additive CCD +------------ + +.. autofunction:: ipctk.additive_ccd.point_point_ccd +.. autofunction:: ipctk.additive_ccd.point_edge_ccd +.. autofunction:: ipctk.additive_ccd.edge_edge_ccd +.. autofunction:: ipctk.additive_ccd.point_triangle_ccd + +Generic Interface +^^^^^^^^^^^^^^^^^ + +.. autofunction:: ipctk.additive_ccd.additive_ccd + +Nonlinear CCD +------------- + +.. autoclass:: ipctk.NonlinearTrajectory + + .. autoclasstoc:: + +.. autoclass:: ipctk.IntervalNonlinearTrajectory + + .. autoclasstoc:: + +.. autofunction:: ipctk.point_point_nonlinear_ccd +.. autofunction:: ipctk.point_edge_nonlinear_ccd +.. autofunction:: ipctk.edge_edge_nonlinear_ccd +.. autofunction:: ipctk.point_triangle_nonlinear_ccd + +Generic Interface +^^^^^^^^^^^^^^^^^ + +.. autofunction:: ipctk.conservative_piecewise_linear_ccd \ No newline at end of file diff --git a/docs/source/python-api/intersections.rst b/docs/source/python-api/intersections.rst new file mode 100644 index 000000000..8bec6e42d --- /dev/null +++ b/docs/source/python-api/intersections.rst @@ -0,0 +1,6 @@ +Intersections +============= + +.. autofunction:: ipctk.has_intersections +.. autofunction:: ipctk.is_edge_intersecting_triangle +.. autofunction:: ipctk.segment_segment_intersect \ No newline at end of file diff --git a/docs/source/python-api/utils.rst b/docs/source/python-api/utils.rst index 702ab5d0a..3299ccadd 100644 --- a/docs/source/python-api/utils.rst +++ b/docs/source/python-api/utils.rst @@ -12,3 +12,9 @@ Multi-Threading .. autofunction:: ipctk.get_num_threads .. autofunction:: ipctk.set_num_threads + +Positive Semi-Definite Projection +--------------------------------- + +.. autofunction:: ipctk.project_to_psd +.. autofunction:: ipctk.project_to_pd \ No newline at end of file diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 5c009ad53..3e98911a4 100755 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -68,6 +68,7 @@ pybind11_add_module(ipctk src/utils/area_gradient.cpp src/utils/eigen_ext.cpp + src/utils/interval.cpp src/utils/intersection.cpp src/utils/logger.cpp src/utils/thread_limiter.cpp diff --git a/python/src/bindings.cpp b/python/src/bindings.cpp index 254dc9515..78e8b3195 100644 --- a/python/src/bindings.cpp +++ b/python/src/bindings.cpp @@ -84,6 +84,7 @@ PYBIND11_MODULE(ipctk, m) // utils define_area_gradient(m); define_eigen_ext(m); + define_interval(m); define_intersection(m); define_logger(m); define_thread_limiter(m); diff --git a/python/src/ccd/nonlinear_ccd.cpp b/python/src/ccd/nonlinear_ccd.cpp index db3ebcda0..2d17012d5 100644 --- a/python/src/ccd/nonlinear_ccd.cpp +++ b/python/src/ccd/nonlinear_ccd.cpp @@ -5,9 +5,32 @@ namespace py = pybind11; using namespace ipc; +class PyNonlinearTrajectory : public NonlinearTrajectory { +public: + // clang-format off + using NonlinearTrajectory::NonlinearTrajectory; // Inherit constructors + VectorMax3d operator()(const double t) const override { PYBIND11_OVERRIDE_PURE_NAME(VectorMax3d, NonlinearTrajectory, "__call__", operator(), t); } + double max_distance_from_linear(const double t0, const double t1) const override { PYBIND11_OVERRIDE_PURE(double, NonlinearTrajectory, max_distance_from_linear, t0, t1); } + // clang-format on +}; + +#ifdef IPC_TOOLKIT_WITH_FILIB +class PyIntervalNonlinearTrajectory : public IntervalNonlinearTrajectory { +public: + // clang-format off + using IntervalNonlinearTrajectory::IntervalNonlinearTrajectory; // Inherit constructors + VectorMax3d operator()(const double t) const override { PYBIND11_OVERRIDE_PURE_NAME(VectorMax3d, IntervalNonlinearTrajectory, "__call__", operator(), t); } + VectorMax3I operator()(const filib::Interval& t) const override { PYBIND11_OVERRIDE_PURE_NAME(VectorMax3I, IntervalNonlinearTrajectory, "__call__", operator(), t); } + double max_distance_from_linear(const double t0, const double t1) const override { PYBIND11_OVERRIDE(double, IntervalNonlinearTrajectory, max_distance_from_linear, t0, t1); } + // clang-format on +}; +#endif + void define_nonlinear_ccd(py::module_& m) { - py::class_(m, "NonlinearTrajectory") + py::class_( + m, "NonlinearTrajectory") + .def(py::init<>()) .def( "__call__", &NonlinearTrajectory::operator(), "Compute the point's position at time t", py::arg("t")) @@ -17,9 +40,6 @@ void define_nonlinear_ccd(py::module_& m) R"ipc_Qu8mg5v7( Compute the maximum distance from the nonlinear trajectory to a linearized trajectory - Note: - This uses interval arithmetic to compute the maximum distance. If you know a tighter bound on the maximum distance, it is recommended to override this function. - Parameters: t0: Start time of the trajectory t1: End time of the trajectory @@ -27,13 +47,20 @@ void define_nonlinear_ccd(py::module_& m) py::arg("t0"), py::arg("t1")); #ifdef IPC_TOOLKIT_WITH_FILIB - py::class_( - m, "IntervalNonlinearTrajectory") + py::class_< + IntervalNonlinearTrajectory, NonlinearTrajectory, + PyIntervalNonlinearTrajectory>(m, "IntervalNonlinearTrajectory") + .def(py::init<>()) .def( "__call__", [](const IntervalNonlinearTrajectory& self, const double t) { return self(t); }, + "Compute the point's position at time t", py::arg("t")) + .def( + "__call__", + py::overload_cast( + &IntervalNonlinearTrajectory::operator(), py::const_), "Compute the point's position over a time interval t", py::arg("t")) .def( "max_distance_from_linear", diff --git a/python/src/utils/bindings.hpp b/python/src/utils/bindings.hpp index d447c29ad..648fbdb46 100644 --- a/python/src/utils/bindings.hpp +++ b/python/src/utils/bindings.hpp @@ -5,6 +5,7 @@ namespace py = pybind11; void define_area_gradient(py::module_& m); void define_eigen_ext(py::module_& m); +void define_interval(py::module_& m); void define_intersection(py::module_& m); void define_logger(py::module_& m); void define_thread_limiter(py::module_& m); diff --git a/python/src/utils/interval.cpp b/python/src/utils/interval.cpp new file mode 100644 index 000000000..488bd24d1 --- /dev/null +++ b/python/src/utils/interval.cpp @@ -0,0 +1,234 @@ +#include +#include + +#include + +namespace py = pybind11; +using namespace filib; + +// ============================================================================ + +#define RETURN_INTERVAL(func) \ + [](const Interval& i) -> Interval { return func(i); } + +#define OP_II(op) \ + [](const Interval& a, const Interval& b) -> Interval { return op; } +#define OP_ID(op) [](const Interval& a, double b) -> Interval { return op; } +#define OP_DI(op) [](const Interval& b, double a) -> Interval { return op; } + +#define DEF_OP(name, op) def("__" name "__", op, py::is_operator()) +#define DEF_BIN_OP(name, op) \ + DEF_OP(name, OP_II(op)).DEF_OP(name, OP_ID(op)).DEF_OP("r" name, OP_DI(op)) +#define DEF_UN_OP(name, op) \ + DEF_OP(name, [](const Interval& i) -> Interval { return op; }) + +#define DEF_IOP(name, RHSType, op) \ + def( \ + "__i" name "__", \ + [](Interval& self, RHSType rhs) -> Interval& { \ + op; \ + return self; \ + }, \ + py::is_operator()) + +// ============================================================================ + +void define_interval(py::module_& m) +{ +#ifdef IPC_TOOLKIT_WITH_FILIB + auto m_filib = m.def_submodule("filib", "Fast Interval Library"); + + py::class_(m_filib, "Interval") + .def(py::init()) + .def(py::init(), py::arg("x")) + .def(py::init(), py::arg("x"), py::arg("y")) + .def( + "__str__", + [](const Interval& self) { + return (std::stringstream() << self).str(); + }) + .def( + "__repr__", + [](const Interval& self) { + return (std::stringstream() + << "Interval(" << self.INF << ", " << self.SUP << ")") + .str(); + }) + .DEF_BIN_OP("add", a + b) + .DEF_UN_OP("pos", +i) + .DEF_IOP("add", const Interval&, self += rhs) + .DEF_IOP("add", double, self += rhs) + .DEF_BIN_OP("sub", a - b) + .DEF_UN_OP("neg", -i) + .DEF_IOP("sub", const Interval&, self -= rhs) + .DEF_IOP("sub", double, self -= rhs) + // .DEF_BIN_OP("mul", a * b) + .DEF_OP( + "mul", + [](const Interval& a, const Interval& b) -> Interval { + if (a == b) { + return sqr(a); // More accurate + } + return a * b; + }) + .DEF_OP("mul", OP_ID(a * b)) + .DEF_OP("rmul", OP_DI(a * b)) + .DEF_IOP("mul", const Interval&, self *= rhs) + .DEF_IOP("mul", double, self *= rhs) + .DEF_BIN_OP("truediv", a / b) + .DEF_IOP("truediv", const Interval&, self /= rhs) + .DEF_IOP("truediv", double, self /= rhs) + .def(py::self == py::self) + .def(py::self == double()) + .def(double() == py::self) + .def(py::self != py::self) + .def(py::self != double()) + .def(double() != py::self) + .def(py::self < py::self) + .def(py::self < double()) + .def(double() < py::self) + .def(py::self <= py::self) + .def(py::self <= double()) + .def(double() <= py::self) + .def(py::self > py::self) + .def(py::self > double()) + .def(double() > py::self) + .def(py::self >= py::self) + .def(py::self >= double()) + .def(double() >= py::self) + .def( + "__contains__", + [](const Interval& self, double x) { return in(x, self); }, + py::is_operator()) + .def( + "__contains__", + [](const Interval& self, const Interval& i) { return in(i, self); }, + py::is_operator()) + .def("empty", [](const Interval& self) { return empty(self); }) + .DEF_OP("or", OP_II(a | b)) + .DEF_OP("and", OP_II(a & b)) + .def("mid", [](const Interval& self) { return mid(self); }) + .def("diam", [](const Interval& self) { return diam(self); }) + .def("drel", [](const Interval& self) { return drel(self); }) + .def( + "blow", + [](const Interval& self, double eps) -> Interval { + return blow(self, eps); + }) + .def("sqr", RETURN_INTERVAL(sqr)) + .def( + "__pow__", + [](const Interval& self, double x) -> Interval { + if (x != 2.0) { + throw std::invalid_argument( + "Only x == 2.0 is supported for Interval**double"); + } + return sqr(self); + }, + py::is_operator()) + .def("sqrt", RETURN_INTERVAL(sqrt)) + .def("exp", RETURN_INTERVAL(exp)) + .def("exp2", RETURN_INTERVAL(exp2)) + .def("exp10", RETURN_INTERVAL(exp10)) + .def( + "__rpow__", + [](const Interval& self, double b) -> Interval { + if (b == 2.0) { + return sqr(self); + } else if (b == exp(1.0)) { + return exp(self); + } else if (b == 10.0) { + return exp10(self); + } else { + throw std::invalid_argument( + "Only b in [2.0, e, 10.0] are supported for double**Interval"); + } + }, + py::is_operator()) + .def("expm1", RETURN_INTERVAL(expm1)) + .def("log", RETURN_INTERVAL(log)) + .def("log2", RETURN_INTERVAL(log2)) + .def("log10", RETURN_INTERVAL(log10)) + .def("log1p", RETURN_INTERVAL(log1p)) + .def("sin", RETURN_INTERVAL(sin)) + .def("cos", RETURN_INTERVAL(cos)) + .def("cot", RETURN_INTERVAL(cot)) + .def("tan", RETURN_INTERVAL(tan)) + .def("asin", RETURN_INTERVAL(asin)) + .def("acos", RETURN_INTERVAL(acos)) + .def("atan", RETURN_INTERVAL(atan)) + .def("acot", RETURN_INTERVAL(acot)) + .def("arcsin", RETURN_INTERVAL(asin)) + .def("arccos", RETURN_INTERVAL(acos)) + .def("arctan", RETURN_INTERVAL(atan)) + .def("arccot", RETURN_INTERVAL(acot)) + .def("sinh", RETURN_INTERVAL(sinh)) + .def("cosh", RETURN_INTERVAL(cosh)) + .def("tanh", RETURN_INTERVAL(tanh)) + .def("coth", RETURN_INTERVAL(coth)) + .def("asinh", RETURN_INTERVAL(asinh)) + .def("acosh", RETURN_INTERVAL(acosh)) + .def("atanh", RETURN_INTERVAL(atanh)) + .def("acoth", RETURN_INTERVAL(acoth)) + .def("arcsinh", RETURN_INTERVAL(asinh)) + .def("arccosh", RETURN_INTERVAL(acosh)) + .def("arctanh", RETURN_INTERVAL(atanh)) + .def("arccoth", RETURN_INTERVAL(acoth)) + .def("erf", RETURN_INTERVAL(erf)) + .def("erfc", RETURN_INTERVAL(erfc)) + .def_readwrite("INF", &interval::INF) + .def_readwrite("SUP", &interval::SUP); + + m_filib.def("disjoint", [](const Interval& i, const Interval& j) { + return disjoint(i, j); + }); + m_filib.def("max", [](const Interval& i, const Interval& j) -> Interval { + return max(i, j); + }); + m_filib.def("max", [](const Interval& i, double j) -> Interval { + return max(i, j); + }); + m_filib.def("max", [](double i, const Interval& j) -> Interval { + return max(i, j); + }); + m_filib.def("min", [](const Interval& i, const Interval& j) -> Interval { + return min(i, j); + }); + m_filib.def("min", [](const Interval& i, double j) -> Interval { + return min(i, j); + }); + m_filib.def("min", [](double i, const Interval& j) -> Interval { + return min(i, j); + }); + m_filib.def("sqr", RETURN_INTERVAL(sqr)); + m_filib.def("sqrt", RETURN_INTERVAL(sqrt)); + m_filib.def("exp", RETURN_INTERVAL(exp)); + m_filib.def("exp2", RETURN_INTERVAL(exp2)); + m_filib.def("exp10", RETURN_INTERVAL(exp10)); + m_filib.def("expm1", RETURN_INTERVAL(expm1)); + m_filib.def("log", RETURN_INTERVAL(log)); + m_filib.def("log2", RETURN_INTERVAL(log2)); + m_filib.def("log10", RETURN_INTERVAL(log10)); + m_filib.def("log1p", RETURN_INTERVAL(log1p)); + m_filib.def("sin", RETURN_INTERVAL(sin)); + m_filib.def("cos", RETURN_INTERVAL(cos)); + m_filib.def("cot", RETURN_INTERVAL(cot)); + m_filib.def("tan", RETURN_INTERVAL(tan)); + m_filib.def("asin", RETURN_INTERVAL(asin)); + m_filib.def("acos", RETURN_INTERVAL(acos)); + m_filib.def("atan", RETURN_INTERVAL(atan)); + m_filib.def("acot", RETURN_INTERVAL(acot)); + m_filib.def("sinh", RETURN_INTERVAL(sinh)); + m_filib.def("cosh", RETURN_INTERVAL(cosh)); + m_filib.def("coth", RETURN_INTERVAL(coth)); + m_filib.def("tanh", RETURN_INTERVAL(tanh)); + m_filib.def("asinh", RETURN_INTERVAL(asinh)); + m_filib.def("acosh", RETURN_INTERVAL(acosh)); + m_filib.def("acoth", RETURN_INTERVAL(acoth)); + m_filib.def("atanh", RETURN_INTERVAL(atanh)); + m_filib.def("erf", RETURN_INTERVAL(erf)); + m_filib.def("erfc", RETURN_INTERVAL(erfc)); + + PYBIND11_NUMPY_DTYPE(Interval, INF, SUP); +#endif +} \ No newline at end of file diff --git a/python/tests/test_ccd.py b/python/tests/test_ccd.py index 78be0b2cd..296526c16 100644 --- a/python/tests/test_ccd.py +++ b/python/tests/test_ccd.py @@ -1,6 +1,7 @@ import numpy as np from utils import * import ipctk +from ipctk.filib import Interval def test_ccd(): @@ -18,3 +19,58 @@ def test_ccd(): assert 0 < toi < 1 assert ipctk.is_step_collision_free(mesh, V0, (V1 - V0) * toi + V0) + + +def test_nonlinear_ccd(): + class LinearTrajectory(ipctk.NonlinearTrajectory): + def __init__(self, p0, p1): + ipctk.NonlinearTrajectory.__init__(self) + self.p0 = p0 + self.p1 = p1 + + def __call__(self, t: float): + return (self.p1 - self.p0) * t + self.p0 + + def max_distance_from_linear(self, t0: float, t1: float): + return 0 + + p0 = LinearTrajectory(np.array([-1, 0, 0]), np.array([1, 0, 0])) + p1 = LinearTrajectory(np.array([0, -1, 0]), np.array([0, 1, 0])) + + assert np.all(p0(0) == np.array([-1, 0, 0])) + assert np.all(p0(1) == np.array([1, 0, 0])) + assert np.all(p1(0) == np.array([0, -1, 0])) + assert np.all(p1(1) == np.array([0, 1, 0])) + + assert np.all(p0(0.5) == np.array([0, 0, 0])) + assert np.all(p1(0.5) == np.array([0, 0, 0])) + + 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) + + assert is_colliding + assert 0 < toi < 1 + assert np.abs(toi - 0.5) < 1e-6 + + class IntervalLinearTrajectory(ipctk.IntervalNonlinearTrajectory): + def __init__(self, p0, p1): + ipctk.IntervalNonlinearTrajectory.__init__(self) + self.p0 = p0 + self.p1 = p1 + + def __call__(self, t): + r = ((self.p1 - self.p0) * t + self.p0) + if isinstance(t, Interval): + r = np.array([(ri.INF, ri.SUP) for ri in r], dtype="f8,f8") + return r + + 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) + + assert is_colliding + assert 0 < toi < 1 + assert np.abs(toi - 0.5) < 1e-2 diff --git a/python/tests/test_interval.py b/python/tests/test_interval.py new file mode 100644 index 000000000..9f7cc80a1 --- /dev/null +++ b/python/tests/test_interval.py @@ -0,0 +1,144 @@ +import math +import numpy as np +from utils import * +from ipctk import filib +from ipctk.filib import Interval + + +def np_sqr(x): return x ** 2 +def np_exp10(x): return 10 ** x +def np_cot(x): return 1 / np.tan(x) +def np_arccot(x): return np.pi / 2 - np.arctan(x) +def np_coth(x): return 1 / np.tanh(x) +def np_arccoth(x): return np.arctanh(1/x) + + +def test_interval(): + x, y = 2, 0.5 + xi, yi = Interval(x), Interval(y) + + assert x + y in xi + yi + assert x + 2 in xi + 2 + assert 2 + x in 2 + xi + + assert x - y in xi - yi + assert x - 2 in xi - 2 + assert 2 - x in 2 - xi + + assert x * y in xi * yi + assert x * 2 in xi * 2 + assert 2 * x in 2 * xi + + assert x / y in xi / yi + assert x / 2 in xi / 2 + assert 2 / x in 2 / xi + + tmp = Interval(xi.INF, xi.SUP) + tmp += Interval(1) + assert x + 1 in tmp + tmp += 1 + assert x + 2 in tmp + tmp -= Interval(1) + assert x + 1 in tmp + tmp -= 1 + assert x in tmp + tmp *= Interval(2) + assert 2 * x in tmp + tmp *= 2 + assert 4 * x in tmp + tmp /= Interval(2) + assert 2 * x in tmp + tmp /= 2 + assert x in tmp + + assert +x == +xi + assert -x == -xi + + assert xi == xi + assert xi == x + assert x == xi + + assert xi != yi + assert xi != y + assert y != xi + + assert yi < xi + assert 0 < xi + assert yi < x + + assert yi <= xi + assert 0 <= xi + assert yi <= x + + assert xi > yi + assert xi > y + assert x > yi + + assert xi >= yi + assert xi >= y + assert x >= yi + + assert Interval(3, 2).empty() + + assert not (xi | yi).empty() + assert (xi & yi).empty() + assert filib.disjoint(xi, yi) + + assert x in xi + assert x not in yi + assert xi in xi.blow(1e-16) + assert xi not in yi + + assert filib.max(xi, yi) == xi + assert filib.max(xi, y) == xi + assert filib.max(y, xi) == xi + + assert filib.min(xi, yi) == yi + assert filib.min(yi, y) == yi + assert filib.min(y, yi) == yi + + assert np_sqr(x) in filib.sqr(xi) + assert np_sqr(x) in np_sqr(xi) + assert np.sqrt(x) in np.sqrt(xi) + + assert np.exp(x) in np.exp(xi) + assert np.e**x in np.e**xi + assert np.exp2(x) in np.exp2(xi) + assert 2**x in 2**xi + assert np_exp10(x) in filib.exp10(xi) + assert np_exp10(x) in np_exp10(xi) + assert np.expm1(x) in np.expm1(xi) + + assert np.log(x) in np.log(xi) + assert np.log2(x) in np.log2(xi) + assert np.log10(x) in np.log10(xi) + assert np.log1p(x) in np.log1p(xi) + + assert np.sin(x) in np.sin(xi) + assert np.cos(x) in np.cos(xi) + assert np.tan(x) in np.tan(xi) + assert np_cot(x) in filib.cot(xi) + assert np_cot(x) in np_cot(xi) + + assert np.arcsin(y) in np.arcsin(yi) + assert np.arccos(y) in np.arccos(yi) + assert np.arctan(y) in np.arctan(yi) + assert np_arccot(y) in filib.acot(yi) + assert np_arccot(y) in np_arccot(yi) + + assert np.sinh(x) in np.sinh(xi) + assert np.cosh(x) in np.cosh(xi) + assert np.tanh(x) in np.tanh(xi) + assert np_coth(x) in filib.coth(xi) + + assert np.arcsinh(y) in np.arcsinh(yi) + assert np.arccosh(x) in np.arccosh(xi) + assert np.arctanh(y) in np.arctanh(yi) + assert np_arccoth(x) in filib.acoth(xi) + assert np_arccoth(x) in np_arccoth(xi) + + assert math.erf(x) in filib.erf(xi) + assert math.erfc(x) in filib.erfc(xi) + + a = np.array([Interval(-1, 1), Interval(-1, 1), Interval(-1, 1)]) + assert np.linalg.norm(a).INF == 0 diff --git a/src/ipc/ccd/nonlinear_ccd.cpp b/src/ipc/ccd/nonlinear_ccd.cpp index 0d42f9ffb..cf2ebe26b 100644 --- a/src/ipc/ccd/nonlinear_ccd.cpp +++ b/src/ipc/ccd/nonlinear_ccd.cpp @@ -255,14 +255,14 @@ bool edge_edge_nonlinear_ccd( return ticcd::edgeEdgeCCD( ea0(ti0), ea1(ti0), eb0(ti0), eb1(ti0), // ea0(ti1), ea1(ti1), eb0(ti1), eb1(ti1), - Eigen::Array3d::Constant(-1), // rounding error (auto) - _min_distance, // minimum separation distance - _toi, // time of impact - tolerance, // delta - 1.0, // maximum time to check - max_iterations, // maximum number of iterations - output_tolerance, // delta_actual - no_zero_toi); // no zero toi + Eigen::Array3d::Constant(-1), // rounding error (auto) + _min_distance, // minimum separation distance + _toi, // time of impact + tolerance, // delta + 1.0, // maximum time to check + max_iterations, // maximum number of iterations + output_tolerance, // delta_actual + no_zero_toi); // no zero toi }, toi, tmax, min_sep_distance, conservative_rescaling); } @@ -295,14 +295,14 @@ bool point_triangle_nonlinear_ccd( return ticcd::vertexFaceCCD( p(ti0), t0(ti0), t1(ti0), t2(ti0), // p(ti1), t0(ti1), t1(ti1), t2(ti1), - Eigen::Array3d::Constant(-1), // rounding error (auto) - _min_distance, // minimum separation distance - _toi, // time of impact - tolerance, // delta - 1.0, // maximum time to check - max_iterations, // maximum number of iterations - output_tolerance, // delta_actual - no_zero_toi); // no zero toi + Eigen::Array3d::Constant(-1), // rounding error (auto) + _min_distance, // minimum separation distance + _toi, // time of impact + tolerance, // delta + 1.0, // maximum time to check + max_iterations, // maximum number of iterations + output_tolerance, // delta_actual + no_zero_toi); // no zero toi }, toi, tmax, min_distance, conservative_rescaling); } diff --git a/src/ipc/ccd/nonlinear_ccd.hpp b/src/ipc/ccd/nonlinear_ccd.hpp index bf201dc1f..63d22abe3 100644 --- a/src/ipc/ccd/nonlinear_ccd.hpp +++ b/src/ipc/ccd/nonlinear_ccd.hpp @@ -20,7 +20,6 @@ class NonlinearTrajectory { virtual VectorMax3d operator()(const double t) const = 0; /// @brief Compute the maximum distance from the nonlinear trajectory to a linearized trajectory - /// @note This uses interval arithmetic to compute the maximum distance. If you know a tighter bound on the maximum distance, it is recommended to override this function. /// @param[in] t0 Start time of the trajectory /// @param[in] t1 End time of the trajectory virtual double diff --git a/src/ipc/utils/interval.cpp b/src/ipc/utils/interval.cpp index 1167abe06..9e965bc2e 100644 --- a/src/ipc/utils/interval.cpp +++ b/src/ipc/utils/interval.cpp @@ -4,7 +4,7 @@ namespace ipc { -filib::Interval squared_norm(const Eigen::Ref& x) +filib::Interval squared_norm(const Eigen::Ref& x) { filib::Interval sqr_norm(0); for (int i = 0; i < x.size(); i++) { @@ -13,7 +13,7 @@ filib::Interval squared_norm(const Eigen::Ref& x) return sqr_norm; } -filib::Interval norm(const Eigen::Ref& x) +filib::Interval norm(const Eigen::Ref& x) { return sqrt(squared_norm(x)); } diff --git a/src/ipc/utils/interval.hpp b/src/ipc/utils/interval.hpp index cafe63eb0..a4bf00ec4 100644 --- a/src/ipc/utils/interval.hpp +++ b/src/ipc/utils/interval.hpp @@ -60,12 +60,12 @@ typedef MatrixX MatrixXI; /// @brief Compute the L2 norm of a 3-dimensional interval /// @param v The 3-dimensional interval /// @return The L2 norm of the interval -filib::Interval squared_norm(const Eigen::Ref& v); // L2 norm +filib::Interval squared_norm(const Eigen::Ref& v); // L2 norm /// @brief Compute the L2 norm of a 3-dimensional interval /// @param v The 3-dimensional interval /// @return The L2 norm of the interval -filib::Interval norm(const Eigen::Ref& v); // L2 norm +filib::Interval norm(const Eigen::Ref& v); // L2 norm } // namespace ipc From 4dc0292e5ea00bb88ceac0878608ccd413494a78 Mon Sep 17 00:00:00 2001 From: Zachary Ferguson Date: Wed, 1 Nov 2023 10:40:45 -0400 Subject: [PATCH 08/10] Comment out interval CCD test --- python/tests/test_ccd.py | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/python/tests/test_ccd.py b/python/tests/test_ccd.py index 296526c16..ce7f49c51 100644 --- a/python/tests/test_ccd.py +++ b/python/tests/test_ccd.py @@ -54,23 +54,23 @@ def max_distance_from_linear(self, t0: float, t1: float): assert 0 < toi < 1 assert np.abs(toi - 0.5) < 1e-6 - class IntervalLinearTrajectory(ipctk.IntervalNonlinearTrajectory): - def __init__(self, p0, p1): - ipctk.IntervalNonlinearTrajectory.__init__(self) - self.p0 = p0 - self.p1 = p1 - - def __call__(self, t): - r = ((self.p1 - self.p0) * t + self.p0) - if isinstance(t, Interval): - r = np.array([(ri.INF, ri.SUP) for ri in r], dtype="f8,f8") - return r - - 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) - - assert is_colliding - assert 0 < toi < 1 - assert np.abs(toi - 0.5) < 1e-2 + # class IntervalLinearTrajectory(ipctk.IntervalNonlinearTrajectory): + # def __init__(self, p0, p1): + # ipctk.IntervalNonlinearTrajectory.__init__(self) + # self.p0 = p0 + # self.p1 = p1 + + # def __call__(self, t): + # r = ((self.p1 - self.p0) * t + self.p0) + # if isinstance(t, Interval): + # r = np.array([(ri.INF, ri.SUP) for ri in r], dtype="f8,f8") + # return r + + # 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) + + # assert is_colliding + # assert 0 < toi < 1 + # assert np.abs(toi - 0.5) < 1e-2 From df8a491359e5bacd6b802d7572ae9b1f15b349ee Mon Sep 17 00:00:00 2001 From: Zachary Ferguson Date: Wed, 1 Nov 2023 10:41:53 -0400 Subject: [PATCH 09/10] Update Python CI --- .github/workflows/python.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 3620770c7..4b74724ac 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -2,12 +2,8 @@ name: Python on: push: - branches: - - main - - python + branches: [main] pull_request: - branches: - - main paths: - '.github/workflows/python.yml' - 'cmake/**' From 4b88825d856eeb3bc81e58e949de74f3d502f413 Mon Sep 17 00:00:00 2001 From: Zachary Ferguson Date: Wed, 1 Nov 2023 12:59:42 -0400 Subject: [PATCH 10/10] Add BOUNDING_VOLUME_HIERARCHY enum to python --- python/src/broad_phase/broad_phase.cpp | 15 ++++++++++----- python/tests/utils.py | 1 + 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/python/src/broad_phase/broad_phase.cpp b/python/src/broad_phase/broad_phase.cpp index 9ab0fd025..c0a4afa4b 100644 --- a/python/src/broad_phase/broad_phase.cpp +++ b/python/src/broad_phase/broad_phase.cpp @@ -11,15 +11,20 @@ void define_broad_phase(py::module_& m) py::enum_( m, "BroadPhaseMethod", "Enumeration of implemented broad phase methods.") - .value("BRUTE_FORCE", BroadPhaseMethod::BRUTE_FORCE, "") - .value("HASH_GRID", BroadPhaseMethod::HASH_GRID, "") - .value("SPATIAL_HASH", BroadPhaseMethod::SPATIAL_HASH, "") + .value("BRUTE_FORCE", BroadPhaseMethod::BRUTE_FORCE, "Brute force.") + .value("HASH_GRID", BroadPhaseMethod::HASH_GRID, "Hash grid.") + .value("SPATIAL_HASH", BroadPhaseMethod::SPATIAL_HASH, "Spatial hash.") + .value( + "BOUNDING_VOLUME_HIERARCHY", BroadPhaseMethod::BVH, + "Bounding volume hierarchy.") .value( "SWEEP_AND_TINIEST_QUEUE", - BroadPhaseMethod::SWEEP_AND_TINIEST_QUEUE, "") + BroadPhaseMethod::SWEEP_AND_TINIEST_QUEUE, + "Sweep and tiniest queue.") .value( "SWEEP_AND_TINIEST_QUEUE_GPU", - BroadPhaseMethod::SWEEP_AND_TINIEST_QUEUE_GPU, "") + BroadPhaseMethod::SWEEP_AND_TINIEST_QUEUE_GPU, + "Sweep and tiniest queue (GPU).") .export_values(); py::class_(m, "BroadPhase") diff --git a/python/tests/utils.py b/python/tests/utils.py index 30c026aea..2e6e4da65 100644 --- a/python/tests/utils.py +++ b/python/tests/utils.py @@ -22,6 +22,7 @@ def broad_phase_methods(): yield ipctk.BroadPhaseMethod.BRUTE_FORCE yield ipctk.BroadPhaseMethod.HASH_GRID yield ipctk.BroadPhaseMethod.SPATIAL_HASH + yield ipctk.BroadPhaseMethod.BOUNDING_VOLUME_HIERARCHY yield ipctk.BroadPhaseMethod.SWEEP_AND_TINIEST_QUEUE