iMSTK
Interactive Medical Simulation Toolkit
imstkPbdObjectCollision.cpp
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 #include "imstkPbdObjectCollision.h"
8 #include "imstkCDObjectFactory.h"
9 #include "imstkCollisionData.h"
10 #include "imstkCCDAlgorithm.h"
11 #include "imstkCollisionDetectionAlgorithm.h"
12 #include "imstkPbdCollisionHandling.h"
13 #include "imstkPbdModel.h"
14 #include "imstkPbdObject.h"
15 #include "imstkPbdSolver.h"
16 #include "imstkTaskGraph.h"
17 
18 namespace imstk
19 {
20 PbdObjectCollision::PbdObjectCollision(std::shared_ptr<PbdObject> obj1, std::shared_ptr<CollidingObject> obj2,
21  std::string cdType) :
22  CollisionInteraction("PbdObjectCollision_" + obj1->getName() + "_vs_" + obj2->getName(), obj1, obj2, cdType)
23 {
24  setupConnections(obj1, obj2, cdType);
25 }
26 
27 void
28 PbdObjectCollision::setRestitution(const double restitution)
29 {
30  auto pbdCH = std::dynamic_pointer_cast<PbdCollisionHandling>(getCollisionHandlingA());
31  CHECK(pbdCH != nullptr) << "No PbdCollisionHandling set";
32  pbdCH->setRestitution(restitution);
33 }
34 
35 double
36 PbdObjectCollision::getRestitution() const
37 {
38  auto pbdCH = std::dynamic_pointer_cast<PbdCollisionHandling>(getCollisionHandlingA());
39  CHECK(pbdCH != nullptr) << "No PbdCollisionHandling set";
40  return pbdCH->getRestitution();
41 }
42 
43 void
44 PbdObjectCollision::setFriction(const double friction)
45 {
46  auto pbdCH = std::dynamic_pointer_cast<PbdCollisionHandling>(getCollisionHandlingA());
47  CHECK(pbdCH != nullptr) << "No PbdCollisionHandling set";
48  pbdCH->setFriction(friction);
49 }
50 
51 double
52 PbdObjectCollision::getFriction() const
53 {
54  auto pbdCH = std::dynamic_pointer_cast<PbdCollisionHandling>(getCollisionHandlingA());
55  CHECK(pbdCH != nullptr) << "No PbdCollisionHandling set";
56  return pbdCH->getFriction();
57 }
58 
59 bool
61 {
62  auto pbdCH = std::dynamic_pointer_cast<PbdCollisionHandling>(getCollisionHandlingA());
63  CHECK(pbdCH != nullptr) << "No PbdCollisionHandling set";
64  return pbdCH->getUseCorrectVelocity();
65 }
66 
67 void
68 PbdObjectCollision::setUseCorrectVelocity(const bool useCorrectVelocity)
69 {
70  auto pbdCH = std::dynamic_pointer_cast<PbdCollisionHandling>(getCollisionHandlingA());
71  CHECK(pbdCH != nullptr) << "No PbdCollisionHandling set";
72  pbdCH->setUseCorrectVelocity(useCorrectVelocity);
73 }
74 
75 void
77 {
78  auto pbdCH = std::dynamic_pointer_cast<PbdCollisionHandling>(getCollisionHandlingA());
79  CHECK(pbdCH != nullptr) << "No PbdCollisionHandling set";
80  pbdCH->setRigidBodyCompliance(compliance);
81 }
82 
83 double
84 PbdObjectCollision::getRigidBodyCompliance() const
85 {
86  auto pbdCH = std::dynamic_pointer_cast<PbdCollisionHandling>(getCollisionHandlingA());
87  CHECK(pbdCH != nullptr) << "No PbdCollisionHandling set";
88  return pbdCH->getRigidBodyCompliance();
89 }
90 
91 void
93 {
94  auto pbdCH = std::dynamic_pointer_cast<PbdCollisionHandling>(getCollisionHandlingA());
95  CHECK(pbdCH != nullptr) << "No PbdCollisionHandling set";
96  pbdCH->setDeformableStiffnessA(stiffness);
97 }
98 
99 double
100 PbdObjectCollision::getDeformableStiffnessA() const
101 {
102  auto pbdCH = std::dynamic_pointer_cast<PbdCollisionHandling>(getCollisionHandlingA());
103  CHECK(pbdCH != nullptr) << "No PbdCollisionHandling set";
104  return pbdCH->getDeformableStiffnessA();
105 }
106 
107 void
108 PbdObjectCollision::setDeformableStiffnessB(const double stiffness)
109 {
110  auto pbdCH = std::dynamic_pointer_cast<PbdCollisionHandling>(getCollisionHandlingA());
111  CHECK(pbdCH != nullptr) << "No PbdCollisionHandling set";
112  pbdCH->setDeformableStiffnessB(stiffness);
113 }
114 
115 double
116 PbdObjectCollision::getDeformableStiffnessB() const
117 {
118  auto pbdCH = std::dynamic_pointer_cast<PbdCollisionHandling>(getCollisionHandlingA());
119  CHECK(pbdCH != nullptr) << "No PbdCollisionHandling set";
120  return pbdCH->getDeformableStiffnessB();
121 }
122 
123 void
124 PbdObjectCollision::initGraphEdges(std::shared_ptr<TaskNode> source, std::shared_ptr<TaskNode> sink)
125 {
127 
128  auto pbdObj1 = std::dynamic_pointer_cast<PbdObject>(m_objA);
129  std::shared_ptr<SceneObject> obj2 = m_objB;
130 
131  std::shared_ptr<TaskNode> chNodeAB = m_collisionHandleANode;
132 
133  // Ensure a complete graph
134  m_taskGraph->addEdge(source, pbdObj1->getTaskGraph()->getSource());
135  m_taskGraph->addEdge(pbdObj1->getTaskGraph()->getSink(), sink);
136  m_taskGraph->addEdge(source, obj2->getTaskGraph()->getSource());
137  m_taskGraph->addEdge(obj2->getTaskGraph()->getSink(), sink);
138 
139  // -------------------------------------------------------------------------
140  // Internal Constraint Solve -> Collision Geometry Update -> Collision Detection ->
141  // PbdHandlerAB -> Collision Constraint Solve -> CCD Update Prev Geometry ->
142  // Update Pbd Velocity -> Correct Velocities for Collision (restitution+friction)
143  // -------------------------------------------------------------------------
144  m_taskGraph->addEdge(pbdObj1->getPbdModel()->getIntegratePositionNode(), m_collisionGeometryUpdateNode);
145  m_taskGraph->addEdge(m_collisionGeometryUpdateNode, m_collisionDetectionNode);
146  m_taskGraph->addEdge(m_collisionDetectionNode, chNodeAB); // A=AB=B
147  m_taskGraph->addEdge(chNodeAB, pbdObj1->getPbdModel()->getSolveNode());
148 
149  m_taskGraph->addEdge(pbdObj1->getPbdModel()->getSolveNode(), m_updatePrevGeometryCCDNode);
150  m_taskGraph->addEdge(m_updatePrevGeometryCCDNode, pbdObj1->getPbdModel()->getUpdateVelocityNode());
151 
152  if (std::dynamic_pointer_cast<PbdObject>(obj2) == nullptr)
153  {
154  m_taskGraph->addEdge(obj2->getUpdateGeometryNode(), m_collisionGeometryUpdateNode);
155  m_taskGraph->addEdge(m_collisionDetectionNode, obj2->getTaskGraph()->getSink());
156  }
157 }
158 
159 void
160 PbdObjectCollision::setupConnections(std::shared_ptr<PbdObject> obj1, std::shared_ptr<CollidingObject> obj2, std::string cdType /*= ""*/)
161 {
162  // Setup the handler
163  std::shared_ptr<PbdCollisionHandling> ch = std::make_shared<PbdCollisionHandling>();
164  ch->setInputObjectA(obj1);
165  ch->setInputObjectB(obj2);
166  ch->setInputCollisionData(m_colDetect->getCollisionDataVector());
167 
168  m_updatePrevGeometryCCDNode = std::make_shared<TaskNode>([&]()
169  {
170  // Confirm if the collision detection algorithm is a CCD algorithm,
171  // and update the cached geometry accordingly.
172  if (auto pbdCCD = std::dynamic_pointer_cast<CCDAlgorithm>(getCollisionDetection()))
173  {
174  // \todo: These inputs could be flipped in the algorithm
175  std::dynamic_pointer_cast<CollidingObject>(m_objA)->updateGeometries();
176  std::dynamic_pointer_cast<CollidingObject>(m_objB)->updateGeometries();
177  pbdCCD->updatePreviousTimestepGeometry(pbdCCD->getInput(0), pbdCCD->getInput(1));
178  }
179  });
180  m_taskGraph->addNode(m_updatePrevGeometryCCDNode);
181 
183 
184  m_taskGraph->addNode(obj1->getTaskGraph()->getSource());
185  m_taskGraph->addNode(obj1->getTaskGraph()->getSink());
186  m_taskGraph->addNode(obj2->getTaskGraph()->getSource());
187  m_taskGraph->addNode(obj2->getTaskGraph()->getSink());
188 
189  std::shared_ptr<PbdModel> pbdModel = obj1->getPbdModel();
190  m_taskGraph->addNode(pbdModel->getSolveNode());
191  m_taskGraph->addNode(pbdModel->getIntegratePositionNode());
192  m_taskGraph->addNode(pbdModel->getUpdateVelocityNode());
193 
194  if (auto pbdObj2 = std::dynamic_pointer_cast<PbdObject>(obj2))
195  {
196  CHECK(pbdModel == pbdObj2->getPbdModel()) << "PbdObjectCollision may only be used with PbdObjects that share the same PbdModel";
197  }
198  else
199  {
200  m_taskGraph->addNode(obj2->getUpdateGeometryNode());
201  }
202 }
203 } // namespace imstk
void setCollisionHandlingAB(std::shared_ptr< CollisionHandling > colHandlingAB)
Set the two-way Collision Handling for both objects.
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.
bool getUseCorrectVelocity() const
Get/Set whether velocity is corrected (in some cases this could cause instabilities) ...
Implements PBD based collision handling. Given an input PbdObject and CollisionData it creates & adds...
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...
virtual void updateGeometries()
Update the geometries.
Compound Geometry.
std::shared_ptr< CollisionDetectionAlgorithm > m_colDetect
Collision detection algorithm.
PbdObjectCollision(std::shared_ptr< PbdObject > obj1, std::shared_ptr< CollidingObject > obj2, std::string cdType="")
Constructor for PbdObject-PbdObject or PbdObject-CollidingObject collisions.
Base class for scene objects that move and/or deform under position based dynamics formulation...
Abstract class for defining collision interactions between objects.
void setFriction(const double friction)
Get/Set the friction, which gives how much velocity is removed along the tangents during contact...
std::shared_ptr< TaskGraph > m_taskGraph
Computational Graph.
void setRestitution(const double restitution)
Get/Set the restitution, which gives how much velocity is removed along the contact normals during co...
A SceneObject with a geometry for collision.
void initGraphEdges()
Initializes the edges of the SceneObject&#39;s computational graph.