Frequently Asked Questions¶
How do I include IPC Toolkit in my project?¶
If you are using CMake, the public include directory is added to the ipc::toolkit cmake target which means that any lib/bin that includes ipc::toolkit as a dependency also adds those include directories too.
If you are not using CMake, the include path is src.
Files are included with the prefix #include <ipc/...> in C++ and import ipctk in Python.
How do I determine which edges intersect?¶
We do not provide an edge-edge intersection function in 3D, but you can approximate it by computing the distance between the two edges and checking if it is less than a threshold.
Inside any BroadPhase classes, the function detect_edge_edge_candidates determines which edges intersect based on their bounding boxes. You can then use edge_edge_distance to check if they approximatly intersect by computing the distance.
How do I build the edge matrix from the face matrix?¶
To build the edge matrix you can use igl::edges(faces, edges); in C++ or ipctk.edges(faces) in Python.
Is there a way to ignore select collisions?¶
Yes. Both CollisionMesh::can_collide and BroadPhase::can_vertices_collide are CollisionFilter objects — composable predicates of the form bool(size_t vi, size_t vj) that control which vertex pairs enter the collision pipeline.
When building candidates through Candidates::build, the broad phase automatically inherits CollisionMesh::can_collide, so you only need to set it once on the mesh.
How primitive-level checks work
BroadPhase expands vertex-level decisions to primitive pairs. For example, checking whether vertex vi can collide with triangle f = (vj, vk, vl) evaluates:
can_face_vertex_collide(f, vi) :=
can_vertices_collide(vj, vi)
&& can_vertices_collide(vk, vi)
&& can_vertices_collide(vl, vi)
This means the filter acts on the one-ring of a vertex rather than a single primitive pair. For finer control you can subclass BroadPhase and override the virtual methods:
virtual bool can_edge_vertex_collide(size_t ei, size_t vi) const;
virtual bool can_edges_collide(size_t eai, size_t ebi) const;
virtual bool can_face_vertex_collide(size_t fi, size_t vi) const;
virtual bool can_edge_face_collide(size_t ei, size_t fi) const;
virtual bool can_faces_collide(size_t fai, size_t fbi) const;
CollisionFilter wraps any bool(size_t, size_t) callable and supports logical composition via | (union) and & (intersection). Negation uses ! in C++ and ~ in Python.
The available factory functions are:
make_connected_components_filter(faces)— blocks pairs within the same connected component (prevents self-collision).make_static_obstacle_filter(n_dynamic)— blocks static-vs-static pairs; vertices with index>= n_dynamicare considered static.make_vertex_patches_filter(patch_ids)— blocks pairs that share the same integer patch label.make_sparse_filter(explicit_values, default_value)— sparse explicit overrides with a fallback default (Python only).
#include <ipc/collision_filter.hpp>
// Built-in factory functions
CollisionFilter no_self = make_connected_components_filter(mesh.faces());
CollisionFilter no_static = make_static_obstacle_filter(n_dynamic_verts);
CollisionFilter by_patch = make_vertex_patches_filter(patch_ids);
// Combine with | (union), & (intersection), ! (negation)
mesh.can_collide = no_self & no_static;
// Or construct directly from a lambda
mesh.can_collide = CollisionFilter([&](size_t vi, size_t vj) {
return group[vi] != group[vj];
});
import numpy as np
from ipctk import (
CollisionFilter,
make_connected_components_filter,
make_sparse_filter,
make_static_obstacle_filter,
make_vertex_patches_filter,
)
# Built-in factory functions
no_self = make_connected_components_filter(mesh.faces)
no_static = make_static_obstacle_filter(n_dynamic)
by_patch = make_vertex_patches_filter(np.array([0, 0, 1, 1], dtype=np.int32))
# Composition: &, |, ~
mesh.can_collide = no_self & no_static
# Sparse explicit overrides (e.g. always allow pair (2, 5))
mesh.can_collide = make_sparse_filter({(2, 5): True}, default_value=False)
# Arbitrary callable (slower — prefer factory functions for large meshes)
mesh.can_collide = CollisionFilter(lambda i, j: group[i] != group[j])
My question is not answered here. What should I do?¶
Please open an Q&A discussion post on GitHub and we will do our best to help you.