iMSTK
Interactive Medical Simulation Toolkit
imstkPbdCollisionHandling.h
1 /*
2 ** This file is part of the Interactive Medical Simulation Toolkit (iMSTK)
3 ** iMSTK is distributed under the Apache License, Version 2.0.
4 ** See accompanying NOTICE for details.
5 */
6 
7 #pragma once
8 
9 #include "imstkCollisionHandling.h"
10 #include "imstkPbdConstraint.h"
11 
12 #include <unordered_map>
13 
14 namespace imstk
15 {
16 enum PbdContactCase
17 {
18  Vertex, // Mesh vertex either from Pbd or CollidingObject
19  Edge, // Mesh edge either from Pbd or CollidingObject
20  Triangle, // Mesh triangle either from Pbd or CollidingObject
21  Body, // Body
22  Primitive, // Not a mesh at all still could be any CD data type
23  None
24 };
25 static std::string
26 getContactCaseStr(PbdContactCase contactCase)
27 {
28  switch (contactCase)
29  {
30  case PbdContactCase::Body:
31  return "Body";
32  case PbdContactCase::Edge:
33  return "Edge";
34  case PbdContactCase::Primitive:
35  return "Primitive";
36  case PbdContactCase::Triangle:
37  return "Triangle";
38  case PbdContactCase::Vertex:
39  return "Vertex";
40  default:
41  return "None";
42  }
43  ;
44 }
45 
53 {
54  PbdContactCase elemAType;
55  PbdContactCase elemBType;
56  bool ccd;
57 
58  friend std::ostream& operator<<(std::ostream& os, const PbdCHTableKey& dt);
59 
60  bool operator==(const PbdCHTableKey& other) const
61  {
62  return
63  (elemAType == other.elemAType)
64  && (elemBType == other.elemBType)
65  && (ccd == other.ccd);
66  }
67 };
68 } // namespace imstk
69 
70 namespace std
71 {
78 template<>
79 struct hash<imstk::PbdCHTableKey>
80 {
81  std::size_t operator()(const imstk::PbdCHTableKey& k) const
82  {
83  using std::size_t;
84  using std::hash;
85 
86  // Base on the bit width of each value
87  std::size_t v0 = static_cast<std::size_t>(k.elemAType); // first 2 bits
88  std::size_t v1 = static_cast<std::size_t>(k.elemBType); // Next 2 bits
89  std::size_t v2 = static_cast<std::size_t>(k.ccd); // Next bit
90  return v0 ^ (v1 << 3) ^ (v2 << 5);
91  }
92 };
93 } // namespace std
94 
95 namespace imstk
96 {
97 class PbdObject;
98 class PbdModel;
99 class PointSet;
100 class PointwiseMap;
101 
118 {
119 public:
120  enum class ObjType
121  {
122  PbdDeformable,
123  PbdRigid,
124  Colliding
125  };
127  {
128  CollisionSideData() = default;
129 
130  // Objects
131  PbdObject* pbdObj = nullptr;
132  CollidingObject* colObj = nullptr;
133  ObjType objType = ObjType::Colliding;
134 
135  PbdModel* model = nullptr;
136  double compliance = 0.0;
137  double stiffness = 0.0;
138  Geometry* geometry = nullptr;
139  PointSet* pointSet = nullptr;
140  VecDataArray<double, 3>* vertices = nullptr;
141  PointwiseMap* mapPtr = nullptr;
142  AbstractDataArray* indicesPtr = nullptr;
143  int bodyId = 0;
144 
145  Geometry* prevGeometry = nullptr;
146  };
151  struct ColElemSide
152  {
153  const CollisionElement* elem = nullptr;
154  const CollisionSideData* data = nullptr;
155  };
156 
158  ~PbdCollisionHandling() override;
159 
160  IMSTK_TYPE_NAME(PbdCollisionHandling)
161 
162 
163  double getRestitution() const { return m_restitution; }
167  void setRestitution(const double restitution) { m_restitution = restitution; }
169 
174  double getFriction() const { return m_friction; }
175  void setFriction(const double friction) { m_friction = friction; }
177 
182  bool getUseCorrectVelocity() const { return m_useCorrectVelocity; }
183  void setUseCorrectVelocity(const bool useCorrectVelocity) { m_useCorrectVelocity = useCorrectVelocity; }
185 
189  int getCCDSubsteps() const { return m_ccdSubsteps; }
190  void setCCDSubsteps(const int ccdSubsteps) { m_ccdSubsteps = ccdSubsteps; }
192 
196  void setEnableBoundaryCollisions(const bool enableBoundaryCollisions) { m_enableBoundaryCollisions = enableBoundaryCollisions; }
197  const bool getEnableBoundaryCollisions() const { return m_enableBoundaryCollisions; }
199 
205  void setRigidBodyCompliance(const double compliance) { m_compliance = compliance; }
206  double getRigidBodyCompliance() const { return m_compliance; }
208 
214  void setDeformableStiffnessA(const double stiffness) { m_stiffness[0] = stiffness; }
215  double getDeformableStiffnessA() const { return m_stiffness[0]; }
216  void setDeformableStiffnessB(const double stiffness) { m_stiffness[1] = stiffness; }
217  double getDeformableStiffnessB() const { return m_stiffness[1]; }
219 
224  const std::vector<PbdConstraint*>& getConstraints() const { return m_collisionConstraints; }
225 
230  std::pair<PbdParticleId, Vec3d> getBodyAndContactPoint(
231  const CollisionElement& elem,
232  const CollisionSideData& data);
233 
234 protected:
235  std::array<PbdParticleId, 2> getEdge(
236  const CollisionElement& elem,
237  const CollisionSideData& side);
238  std::array<PbdParticleId, 3> getTriangle(
239  const CollisionElement& elem,
240  const CollisionSideData& side);
245  std::array<PbdParticleId, 1> getVertex(
246  const CollisionElement& elem,
247  const CollisionSideData& side);
248 
253  CollisionSideData getDataFromObject(std::shared_ptr<CollidingObject> obj);
254 
259  PbdContactCase getCaseFromElement(const ColElemSide& elem);
260 
264  void handle(
265  const std::vector<CollisionElement>& elementsA,
266  const std::vector<CollisionElement>& elementsB) override;
267 
271  void handleElementPair(ColElemSide sideA, ColElemSide sideB);
272 
273  // -----------------One-Way Rigid on X Cases-----------------
274  virtual void addConstraint_Body_V(
275  const ColElemSide& sideA,
276  const ColElemSide& sideB);
277  virtual void addConstraint_Body_E(
278  const ColElemSide& sideA,
279  const ColElemSide& sideB);
280  virtual void addConstraint_Body_T(
281  const ColElemSide& sideA,
282  const ColElemSide& sideB);
283  // ---------------Two-Way Rigid on Rigid Cases---------------
284  virtual void addConstraint_Body_Body(
285  const ColElemSide& sideA,
286  const ColElemSide& sideB);
287 
288  // ----------DeformableMesh on DeformableMesh Cases----------
289  virtual void addConstraint_V_T(
290  const ColElemSide& sideA,
291  const ColElemSide& sideB);
292  virtual void addConstraint_E_E(
293  const ColElemSide& sideA,
294  const ColElemSide& sideB);
295  virtual void addConstraint_E_E_CCD(
296  const ColElemSide& sideA,
297  const ColElemSide& sideB);
298  virtual void addConstraint_V_E(
299  const ColElemSide& sideA,
300  const ColElemSide& sideB);
301  virtual void addConstraint_V_V(
302  const ColElemSide& sideA,
303  const ColElemSide& sideB);
304 
305 private:
306  double m_restitution = 0.0;
307  double m_friction = 0.0;
308 
311  bool m_enableBoundaryCollisions = false;
312  double m_compliance = 0.000001;
313  bool m_useCorrectVelocity = true;
314  std::array<double, 2> m_stiffness = { 0.3, 0.3 };
315  int m_ccdSubsteps = 25;
316 
320  void deleteCollisionConstraints();
321 
328  void orderCollisionConstraints();
329 
330 protected:
331 
332  // Enum for binning constraint types to order for solver
333  // and defining the order
334  enum ConstraintType
335  {
336  // Rigid on rigid
337  BodyBody = 0,
338  // Rigid on mesh
339  BodyVertex,
340  BodyEdge,
341  BodyTriangle,
342  // mesh on mesh non-ccd constraints
343  VertexVertex,
344  VertexEdge,
345  EdgeEdge,
346  VertexTriangle,
347  // CCD constraints
348  EdgeEdgeCCD,
349  NumTypes
350  };
351 
352  template<class T>
353  T* getCachedConstraint(ConstraintType type);
354 
355  // Vectors to split out constraint types and allow for ordering
356  // A single constraint instance should always either be in a bin or the cache
357  // additionally it _may_ be in the m_collisionConstraints structure
358  std::vector<PbdConstraint*> m_constraintBins[NumTypes];
359  std::vector<PbdConstraint*> m_constraintCache[NumTypes];
360 
361  std::vector<PbdConstraint*> m_collisionConstraints;
362 
363  std::unordered_map<PbdCHTableKey, std::function<void(
364  const ColElemSide& elemA, const ColElemSide& elemB)>> m_funcTable;
365 };
366 } // namespace imstk
This class implements the position based dynamics model. The PbdModel is a constraint based model tha...
Definition: imstkPbdModel.h:41
Base class for all geometries represented by discrete points and elements The pointsets follow a pipe...
Definition: imstkPointSet.h:25
Implements PBD based collision handling. Given an input PbdObject and CollisionData it creates & adds...
const std::vector< PbdConstraint * > & getConstraints() const
Return the constraints generated by this handler This list of constraints is ordered in orderCollisio...
Compound Geometry.
int getCCDSubsteps() const
Get/Set the number of substeps used in CCD constraints.
This class serves as the base class of DataArray, for typeless use.
double getFriction() const
Get/Set the friction, which gives how much velocity is removed along the tangents during contact...
Returns a hash value for a PointEntry.
void setRigidBodyCompliance(const double compliance)
Get/Set compliance of rigid body contacts. Defaults to 0 compliance/infinitely stiff. This is what is needed most of the time but sometimes making a contact a bit softer can be helpful.
Union of collision elements. We use a union to avoid polymorphism. There may be many elements and acc...
Base class for any geometrical representation.
Definition: imstkGeometry.h:22
void setEnableBoundaryCollisions(const bool enableBoundaryCollisions)
Get enableBoundaryCollision.
Base class for scene objects that move and/or deform under position based dynamics formulation...
bool getUseCorrectVelocity() const
Get/Set whether velocity is corrected (in some cases this could cause instabilities) ...
Base class for all collision handling classes.
PointwiseMap can compute & apply a mapping between parent and child PointSet geometries.
Packs the collision element together with the data it will need to process it (for swapping) ...
std::vector< PbdConstraint * > m_collisionConstraints
Vector of all collision constraints.
void setDeformableStiffnessA(const double stiffness)
Get/Set stiffness of deformable contacts. Defaults to 1.0. This is what is needed most of the time bu...
A SceneObject with a geometry for collision.
Used as a key in a function table to decide how to handle resulting collision.