Collision Mesh¶
- class CollisionMesh;¶
A class for encapsulating the transformation/selections needed to go from a volumetric FE mesh to a surface collision mesh.
Public Functions¶
- CollisionMesh() = default;¶
Construct a new Collision Mesh object.
Collision Mesh objects are immutable, so use the other constructors.
-
explicit CollisionMesh(
Eigen::ConstRef<Eigen::MatrixXd> rest_positions,
Eigen::ConstRef<Eigen::MatrixXi> edges = Eigen::MatrixXi(),
Eigen::ConstRef<Eigen::MatrixXi> faces = Eigen::MatrixXi(),
const Eigen::SparseMatrix<double>& displacement_map
= Eigen::SparseMatrix<double>());¶ Construct a new Collision Mesh object directly from the collision mesh vertices.
- Parameters:¶
- Eigen::ConstRef<Eigen::MatrixXd> rest_positions¶
The vertices of the collision mesh at rest (|V| × dim).
- Eigen::ConstRef<Eigen::MatrixXi> edges = Eigen::MatrixXi()¶
The edges of the collision mesh (|E| × 2).
- Eigen::ConstRef<Eigen::MatrixXi> faces = Eigen::MatrixXi()¶
The faces of the collision mesh (|F| × 3).
- const Eigen::SparseMatrix<double> &displacement_map = Eigen::SparseMatrix<double>()¶
The displacement mapping from displacements on the full mesh to the collision mesh.
-
inline CollisionMesh(const std::vector<bool>& include_vertex,
const std::vector<bool>& orient_vertex,
Eigen::ConstRef<Eigen::MatrixXd> full_rest_positions,
Eigen::ConstRef<Eigen::MatrixXi> edges = Eigen::MatrixXi(),
Eigen::ConstRef<Eigen::MatrixXi> faces = Eigen::MatrixXi(),
const Eigen::SparseMatrix<double>& displacement_map
= Eigen::SparseMatrix<double>());¶ Construct a new Collision Mesh object from a full mesh vertices.
- Parameters:¶
- const std::vector<bool> &include_vertex¶
Vector of bools indicating whether each vertex should be included in the collision mesh.
- const std::vector<bool> &orient_vertex¶
Vector of bools indicating whether each vertex is orientable.
- Eigen::ConstRef<Eigen::MatrixXd> full_rest_positions¶
The vertices of the full mesh at rest (|V| × dim).
- Eigen::ConstRef<Eigen::MatrixXi> edges = Eigen::MatrixXi()¶
The edges of the collision mesh indexed into the full mesh vertices (|E| × 2).
- Eigen::ConstRef<Eigen::MatrixXi> faces = Eigen::MatrixXi()¶
The faces of the collision mesh indexed into the full mesh vertices (|F| × 3).
- const Eigen::SparseMatrix<double> &displacement_map = Eigen::SparseMatrix<double>()¶
The displacement mapping from displacements on the full mesh to the collision mesh.
-
CollisionMesh(const std::vector<bool>& include_vertex,
const std::vector<bool>& orient_vertex,
const std::vector<bool>& obstacle_vertex,
Eigen::ConstRef<Eigen::MatrixXd> full_rest_positions,
Eigen::ConstRef<Eigen::MatrixXi> edges = Eigen::MatrixXi(),
Eigen::ConstRef<Eigen::MatrixXi> faces = Eigen::MatrixXi(),
const Eigen::SparseMatrix<double>& displacement_map
= Eigen::SparseMatrix<double>());¶ Construct a new Collision Mesh object from a full mesh vertices.
- Parameters:¶
- const std::vector<bool> &include_vertex¶
Vector of bools indicating whether each vertex should be included in the collision mesh.
- const std::vector<bool> &orient_vertex¶
Vector of bools indicating whether each vertex is orientable.
- const std::vector<bool> &obstacle_vertex¶
Vector of bools indicating whether each vertex comes from an obstacle. Like include_vertex, it is indexed by full mesh vertex (|V|).
- Eigen::ConstRef<Eigen::MatrixXd> full_rest_positions¶
The vertices of the full mesh at rest (|V| × dim).
- Eigen::ConstRef<Eigen::MatrixXi> edges = Eigen::MatrixXi()¶
The edges of the collision mesh indexed into the full mesh vertices (|E| × 2).
- Eigen::ConstRef<Eigen::MatrixXi> faces = Eigen::MatrixXi()¶
The faces of the collision mesh indexed into the full mesh vertices (|F| × 3).
- const Eigen::SparseMatrix<double> &displacement_map = Eigen::SparseMatrix<double>()¶
The displacement mapping from displacements on the full mesh to the collision mesh.
- Throws:¶
std::invalid_argument– if obstacle_vertex does not have one entry per full mesh vertex.
- void init_adjacencies();¶
Initialize vertex-vertex and edge-vertex adjacencies.
- void init_area_jacobians();¶
Initialize vertex and edge areas.
- ~CollisionMesh() = default;¶
Destroy the Collision Mesh object.
- inline size_t num_vertices() const;¶
Get the number of vertices in the collision mesh.
- inline size_t num_codim_vertices() const;¶
Get the number of codimensional vertices in the collision mesh.
- inline size_t num_codim_edges() const;¶
Get the number of codimensional edges in the collision mesh.
- inline size_t num_edges() const;¶
Get the number of edges in the collision mesh.
- inline size_t num_faces() const;¶
Get the number of faces in the collision mesh.
- inline size_t dim() const;¶
Get the dimension of the mesh.
- inline size_t ndof() const;¶
Get the number of degrees of freedom in the collision mesh.
- inline size_t full_num_vertices() const;¶
Get the number of vertices in the full mesh.
- inline size_t full_ndof() const;¶
Get the number of degrees of freedom in the full mesh.
- inline const Eigen::MatrixXd& rest_positions() const;¶
Get the vertices of the collision mesh at rest (|V| × dim).
- inline const Eigen::VectorXi& codim_vertices() const;¶
Get the indices of codimensional vertices of the collision mesh (|CV| × 1).
- inline bool is_obstacle_edge(const index_t i) const;¶
Check if edge i is from an obstacle.
Note
An edge is an obstacle only if both of its vertices are obstacle vertices. An edge with one dynamic vertex still moves, so we treat it as dynamic (e.g., a rope whose end is anchored to a static obstacle).
- inline bool is_obstacle_face(const index_t i) const;¶
Check if face i is from an obstacle.
Note
A face is an obstacle only if all three of its vertices are obstacle vertices. As with edges, a face touching a dynamic vertex moves, so we treat it as dynamic.
- inline const Eigen::VectorXi& codim_edges() const;¶
Get the indices of codimensional edges of the collision mesh (|CE| × 1).
- inline const Eigen::MatrixXi& edges() const;¶
Get the edges of the collision mesh (|E| × 2).
- inline const Eigen::MatrixXi& faces() const;¶
Get the faces of the collision mesh (|F| × 3).
- inline const Eigen::MatrixXi& faces_to_edges() const;¶
Get the mapping from faces to edges of the collision mesh (|F| × 3).
- double max_edge_length() const;¶
Compute the maximum rest length of all edges.
-
std::vector<Eigen::Vector3d> face_normals(
Eigen::ConstRef<Eigen::MatrixXd> vertices) const;¶ Compute the unit normal of each face for the given vertex positions.
Note
3D only (requires triangular faces).
-
inline const std::vector<std::vector<index_t>>&
vertices_to_edges() const;¶ Get the mapping from vertices to edges of the collision mesh.
-
inline const std::vector<std::vector<index_t>>&
vertices_to_faces() const;¶ Get the mapping from vertices to faces of the collision mesh.
-
inline const std::vector<std::vector<index_t>>&
edges_to_faces() const;¶ Get the mapping from edges to faces of the collision mesh.
- Returns:¶
A vector of size |E|, where each entry is a vector of face indices adjacent to that edge.
-
Eigen::MatrixXd vertices(
Eigen::ConstRef<Eigen::MatrixXd> full_positions) const;¶ Compute the vertex positions from the positions of the full mesh.
-
Eigen::MatrixXd displace_vertices(
Eigen::ConstRef<Eigen::MatrixXd> full_displacements) const;¶ Compute the vertex positions from vertex displacements on the full mesh.
-
Eigen::MatrixXd map_displacements(
Eigen::ConstRef<Eigen::MatrixXd> full_displacements) const;¶ Map vertex displacements on the full mesh to vertex displacements on the collision mesh.
- inline index_t to_full_vertex_id(const index_t id) const;¶
Map a vertex ID to the corresponding vertex ID in the full mesh.
- inline const Eigen::VectorXi& to_full_vertex_id() const;¶
Get the complete mapping of vertex IDs to their corresponding vertex IDs in the full mesh.
- Returns:¶
Vector of size num_vertices() where each entry is the full vertex ID corresponding to the collision mesh vertex ID.
-
Eigen::VectorXd to_full_dof(
Eigen::ConstRef<Eigen::VectorXd> x) const;¶ Map a vector quantity on the collision mesh to the full mesh.
This is useful for mapping gradients from the collision mesh to the full mesh (i.e., applies the chain-rule).
- Parameters:¶
- Returns:¶
Vector quantity on the full mesh with size equal to full_ndof().
-
Eigen::SparseMatrix<double> to_full_dof(
const Eigen::SparseMatrix<double>& X) const;¶ Map a matrix quantity on the collision mesh to the full mesh.
This is useful for mapping Hessians from the collision mesh to the full mesh (i.e., applies the chain-rule).
- Parameters:¶
- Returns:¶
Matrix quantity on the full mesh with size equal to full_ndof() × full_ndof().
- inline bool is_selection_dof_map() const;¶
Whether the full ↔ collision DOF map is a pure selection matrix.
This is the case unless a (non-empty) displacement map was provided at construction. When true, to_full_dof() is equivalent to scattering each collision DOF to the full DOF of the same vertex and component, so derivatives can be assembled directly in full-mesh DOFs instead of applying to_full_dof() after the fact. The scalar index of that scatter depends on IPC_TOOLKIT_VERTEX_DERIVATIVE_LAYOUT: collision DOF
imaps to full DOFdim * to_full_vertex_id(i / dim) + i % dimwhen the layout is RowMajor (the default), and tofull_num_vertices() * d + to_full_vertex_id(v)for collision DOFnum_vertices() * d + vwhen it is ColMajor.
-
inline const std::vector<std::vector<index_t>>&
vertex_vertex_adjacencies() const;¶ Get the vertex-vertex adjacency matrix.
-
inline const std::vector<std::vector<index_t>>&
vertex_edge_adjacencies() const;¶ Get the vertex-edge adjacency matrix.
-
inline const std::vector<std::vector<index_t>>&
vertex_face_adjacencies() const;¶ Get the vertex-face adjacency matrix.
-
inline const std::vector<std::vector<index_t>>&
edge_vertex_adjacencies() const;¶ Get the edge-vertex adjacency matrix.
- inline bool are_adjacencies_initialized() const;¶
Determine if the adjacencies have been initialized by calling init_adjacencies().
- inline bool is_vertex_on_boundary(const index_t vi) const;¶
Is a vertex on the boundary of the collision mesh?
- inline const Eigen::VectorXd& vertex_areas() const;¶
Get the barycentric area of the vertices.
- inline const Eigen::VectorXd& face_areas() const;¶
Get the area of the faces (3D).
-
void set_vertex_areas(
Eigen::ConstRef<Eigen::VectorXd> vertex_areas);¶ Override the vertex areas used as collision weights.
Note
Use this when the quadrature weight of a vertex is not its barycentric area (e.g., axisymmetric models where each vertex stands for a ring of contact). Collisions built before this call keep their old weights.
Note
Custom areas do not support shape derivatives: this throws if the area Jacobians were already initialized, and init_area_jacobians() throws afterwards.
- Parameters:¶
- Eigen::ConstRef<Eigen::VectorXd> vertex_areas¶
New vertex areas (size num_vertices()). Must be finite and non-negative (zero is allowed, e.g., for axisymmetric primitives on the symmetry axis).
-
inline const Eigen::SparseVector<double>& vertex_area_gradient(
const size_t vi) const;¶ Get the gradient of the barycentric area of a vertex wrt the rest positions of all points.
- inline const Eigen::VectorXd& edge_areas() const;¶
Get the barycentric area of the edges.
- void set_edge_areas(Eigen::ConstRef<Eigen::VectorXd> edge_areas);¶
Override the edge areas used as collision weights.
Note
See set_vertex_areas() for the caveats on stale collisions and shape derivatives.
- Parameters:¶
- Eigen::ConstRef<Eigen::VectorXd> edge_areas¶
New edge areas (size num_edges()). Must be finite and non-negative (zero is allowed, e.g., for axisymmetric primitives on the symmetry axis).
-
inline const Eigen::SparseVector<double>& edge_area_gradient(
const size_t ei) const;¶ Get the gradient of the barycentric area of an edge wrt the rest positions of all points.
- inline bool are_area_jacobians_initialized() const;¶
Determine if the area Jacobians have been initialized by calling init_area_jacobians().
- inline bool has_thickness() const;¶
Determine if the primitives have a thickness (see set_thickness()).
- inline double vertex_thickness(const index_t vi) const;¶
Get the thickness of a vertex (zero without a thickness).
- inline double edge_thickness(const index_t ei) const;¶
Get the thickness of an edge (zero without a thickness).
- inline double face_thickness(const index_t fi) const;¶
Get the thickness of a face (zero without a thickness).
- inline const Eigen::VectorXd& vertex_thicknesses() const;¶
Get the thickness of the vertices (empty without a thickness).
- inline const Eigen::VectorXd& edge_thicknesses() const;¶
Get the thickness of the edges (empty without a thickness).
- inline const Eigen::VectorXd& face_thicknesses() const;¶
Get the thickness of the faces (empty without a thickness).
- inline double max_thickness() const;¶
Get the largest thickness of any primitive (zero without a thickness).
-
template <typename Candidate>
inline double pair_thickness(const Candidate& candidate) const;¶ Get the sum of a pair’s two primitives’ thicknesses (zero without a thickness).
-
void set_thickness(
Eigen::ConstRef<Eigen::VectorXd> vertex_thickness,
Eigen::ConstRef<Eigen::VectorXd> edge_thickness,
Eigen::ConstRef<Eigen::VectorXd> face_thickness);¶ Give every vertex, edge, and face a thickness.
Each primitive is offset outward by its thickness, so two primitives touch when they are the sum of their thicknesses apart. Collisions built from this mesh add that sum to their minimum distance (NormalCollision::dmin), the broad phase inflates each primitive’s box by its thickness, and CCD stops each pair at that sum plus the minimum distance. A sheet of total thickness h, for example, gives each of its primitives h / 2.
Note
Collisions and candidates built before this call keep their old distances.
Note
CCD stops each edge-edge and face-vertex pair at its own thickness, while the collision it reduces to (e.g., vertex-vertex at a face’s corner) keeps that sub-primitive’s thickness. Keep each vertex and edge no thicker than the thickest face or edge containing it, as set_vertex_thickness() and set_face_thickness() do, or a collision-free step can end inside such a collision’s minimum distance.
- Parameters:¶
- Eigen::ConstRef<Eigen::VectorXd> vertex_thickness¶
Thickness of each vertex (size num_vertices()). Must be finite and non-negative, as must the others.
- Eigen::ConstRef<Eigen::VectorXd> edge_thickness¶
Thickness of each edge (size num_edges()).
- Eigen::ConstRef<Eigen::VectorXd> face_thickness¶
Thickness of each face (size num_faces()).
-
void set_vertex_thickness(
Eigen::ConstRef<Eigen::VectorXd> vertex_thickness);¶ Give each vertex a thickness, which its edges and faces inherit.
An edge or face takes the largest thickness of its vertices. This suits thickness given per vertex, such as rods of varying radius.
See also
- Parameters:¶
- Eigen::ConstRef<Eigen::VectorXd> vertex_thickness¶
Thickness of each vertex (size num_vertices()).
-
void set_face_thickness(
Eigen::ConstRef<Eigen::VectorXd> face_thickness,
Eigen::ConstRef<Eigen::VectorXd> vertex_thickness
= Eigen::VectorXd());¶ Give each face a thickness, which its edges and vertices inherit.
An edge or vertex takes the largest thickness of the faces it bounds, so a seam between a thick and a thin panel is as thick as the thick one. An edge on no face takes the larger thickness of its two vertices. This suits thickness that is piecewise constant over the surface, such as garment panels of different fabrics.
See also
- Parameters:¶
- Eigen::ConstRef<Eigen::VectorXd> face_thickness¶
Thickness of each face (size num_faces()).
- Eigen::ConstRef<Eigen::VectorXd> vertex_thickness = Eigen::VectorXd()¶
Least thickness of each vertex (size num_vertices()), or empty for zero. It is the whole thickness of a vertex on no face.
- void clear_thickness();¶
Remove the primitives’ thickness.
Public Members¶
- CollisionFilter can_collide;¶
A filter for determining if two vertices (and the primitives containing them) can collide.
By default all primitives can collide with all other primitives.
- std::vector<Eigen::Hyperplane<double, 3>> planes;¶
Analytic planes in the scene that can be collided with.
This is useful for representing infinite planes (e.g., the ground plane) or planes that are not part of the collision mesh.
Public Static Functions¶
-
static inline CollisionMesh build_from_full_mesh(
Eigen::ConstRef<Eigen::MatrixXd> full_rest_positions,
Eigen::ConstRef<Eigen::MatrixXi> edges,
Eigen::ConstRef<Eigen::MatrixXi> faces = Eigen::MatrixXi());¶ Helper function that automatically builds include_vertex using construct_is_on_surface.
- Parameters:¶
- Returns:¶
Constructed CollisionMesh.
-
static std::vector<bool> construct_is_on_surface(
const size_t num_vertices,
Eigen::ConstRef<Eigen::MatrixXi> edges,
Eigen::ConstRef<Eigen::VectorXi> codim_vertices
= Eigen::VectorXi());¶ Construct a vector of bools indicating whether each vertex is on the surface.
Protected Functions¶
- void init_edges_to_faces();¶
Initialize map from edges to adjacent faces.
- void init_codim_vertices();¶
Initialize the codimensional vertices.
- void init_codim_edges();¶
Initialize the codimensional edges.
- void init_selection_matrices(const int dim);¶
Initialize the selection matrix from full vertices/DOF to collision vertices/DOF.
- void init_areas();¶
Initialize vertex and edge areas.
Protected Attributes¶
- Eigen::MatrixXd m_full_rest_positions;¶
The full vertex positions at rest (|FV| × dim).
- Eigen::MatrixXd m_rest_positions;¶
The vertex positions at rest (|V| × dim).
- std::vector<bool> m_is_codim_vertex;¶
The mask of codimensional vertices (|V|).
- std::vector<bool> m_is_orient_vertex;¶
The mask of orientable vertices (|V|).
- std::vector<bool> m_is_obstacle_vertex;¶
The mask of obstacle vertices (|V|).
- Eigen::VectorXi m_codim_vertices;¶
The indices of codimensional vertices (|CV| × 1).
- std::vector<bool> m_is_codim_edge;¶
The mask of codimensional edges (|E|).
- Eigen::VectorXi m_codim_edges;¶
The indices of codimensional edges (|CE| × 1).
- Eigen::MatrixXi m_edges;¶
Edges as rows of indicies into vertices (|E| × 2).
- Eigen::MatrixXi m_faces;¶
Triangular faces as rows of indicies into vertices (|F| × 3).
- Eigen::MatrixXi m_faces_to_edges;¶
Map from faces edges to rows of edges (|F| × 3).
- std::vector<std::vector<index_t>> m_edges_to_faces;¶
Map from edges to adjacent faces (|E| entries, variable length).
- Eigen::VectorXi m_full_vertex_to_vertex;¶
Map from full vertices to collision vertices.
Note
Negative values indicate full vertex is dropped.
- Eigen::VectorXi m_vertex_to_full_vertex;¶
Map from collision vertices to full vertices.
- Eigen::SparseMatrix<double> m_select_vertices;¶
Selection matrix S ∈ ℝ^{collision×full} for vertices.
- Eigen::SparseMatrix<double> m_select_dof;¶
Selection matrix S ∈ ℝ^{(dim*collision)×(dim*full)} for DOF.
- Eigen::SparseMatrix<double> m_displacement_map;¶
Mapping from full displacements to collision displacements.
Note
this is premultiplied by m_select_vertices
- Eigen::SparseMatrix<double> m_displacement_dof_map;¶
Mapping from full displacements DOF to collision displacements DOF.
Note
this is premultiplied by m_select_dof
- bool m_is_selection_dof_map = true;¶
Whether the user-provided displacement map is the identity (i.e., m_displacement_dof_map is a pure selection matrix).
- std::vector<std::vector<index_t>> m_vertex_vertex_adjacencies;¶
Vertices adjacent to vertices.
- std::vector<std::vector<index_t>> m_vertex_edge_adjacencies;¶
Edges adjacent to vertices.
- std::vector<std::vector<index_t>> m_vertex_face_adjacencies;¶
Faces adjacent to vertices.
- std::vector<std::vector<index_t>> m_edge_vertex_adjacencies;¶
Vertices adjacent to edges (i.e., vertices are on a triangle that contains the edge but not the edge itself).
- std::vector<std::vector<index_t>> m_vertices_to_faces;¶
For each vertex, the faces adjacent to it.
- std::vector<std::vector<index_t>> m_vertices_to_edges;¶
For each vertex, the edges adjacent to it.
- std::vector<bool> m_is_vertex_on_boundary;¶
Is vertex on the boundary of the triangle mesh in 3D or polyline in 2D?
- Eigen::VectorXd m_vertex_areas;¶
Vertex areas 2D: 1/2 sum of length of connected edges 3D: 1/3 sum of area of connected triangles.
- Eigen::VectorXd m_edge_areas;¶
Edge areas 3D: 1/3 sum of area of connected triangles.
- bool m_has_custom_areas = false;¶
Were the areas overridden by the user (so the Jacobians no longer match)?
- Eigen::VectorXd m_face_areas;¶
Face areas 3D: per-face area.
- std::vector<Eigen::SparseVector<double>> m_vertex_area_jacobian;¶
The rows of the Jacobian of the vertex areas vector.
- std::vector<Eigen::SparseVector<double>> m_edge_area_jacobian;¶
The rows of the Jacobian of the edge areas vector.
- Eigen::VectorXd m_vertex_thickness;¶
Thickness of each vertex (empty without a thickness).
- Eigen::VectorXd m_edge_thickness;¶
Thickness of each edge (empty without a thickness).
- Eigen::VectorXd m_face_thickness;¶
Thickness of each face (empty without a thickness).
- double m_max_thickness = 0;¶
Largest thickness of any primitive.