iMSTK
Interactive Medical Simulation Toolkit
imstkCollisionInteraction.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 "imstkCDObjectFactory.h"
8 #include "imstkCollisionInteraction.h"
9 #include "imstkCollidingObject.h"
10 #include "imstkCollisionDetectionAlgorithm.h"
11 #include "imstkCollisionHandling.h"
12 #include "imstkTaskGraph.h"
13 
14 namespace imstk
15 {
16 CollisionInteraction::CollisionInteraction(
17  std::string objName,
18  std::shared_ptr<CollidingObject> objA,
19  std::shared_ptr<CollidingObject> objB,
20  std::string cdType = "") : SceneObject(objName),
21  m_objA(objA), m_objB(objB)
22 {
23  CHECK(objA != nullptr) << "CollisionInteraction requires a CollidingObject objA";
24  CHECK(objB != nullptr) << "CollisionInteraction requires a CollidingObject objB";
25 
26  m_collisionDetectionNode = std::make_shared<TaskNode>(std::bind(&CollisionInteraction::updateCD, this),
27  objA->getName() + "_vs_" + objB->getName() + "_CollisionDetection");
28  m_taskGraph->addNode(m_collisionDetectionNode);
29 
30  m_collisionHandleANode = std::make_shared<TaskNode>(std::bind(&CollisionInteraction::updateCHA, this),
31  objA->getName() + "_vs_" + objB->getName() + "_CollisionHandlingA", true);
32  m_taskGraph->addNode(m_collisionHandleANode);
33 
34  m_collisionHandleBNode = std::make_shared<TaskNode>(std::bind(&CollisionInteraction::updateCHB, this),
35  objA->getName() + "_vs_" + objB->getName() + "_CollisionHandlingB", true);
36  m_taskGraph->addNode(m_collisionHandleBNode);
37 
38  // Setup a step to update geometries before detecting collision
39  m_collisionGeometryUpdateNode = std::make_shared<TaskNode>([this]() {
40  if (m_didUpdateThisFrame)
41  {
42  return;
43  }
44  m_didUpdateThisFrame = true;
45  updateCollisionGeometry();
46  },
47  objA->getName() + "_vs_" + objB->getName() + "_CollisionGeometryUpdate", true);
48  m_taskGraph->addNode(m_collisionGeometryUpdateNode);
49 
50  // Get default cdType if one not provided
51  if (cdType.empty())
52  {
53  cdType = getCDType(*objA, *objB);
54  }
55 
56  // Setup the CD
57  m_colDetect = CDObjectFactory::makeCollisionDetection(cdType);
58  m_colDetect->setInput(objA->getCollidingGeometry(), 0);
59  m_colDetect->setInput(objB->getCollidingGeometry(), 1);
60  setCollisionDetection(m_colDetect);
61 }
62 
63 void
64 CollisionInteraction::setCollisionDetection(std::shared_ptr<CollisionDetectionAlgorithm> colDetect)
65 {
66  m_colDetect = colDetect;
67 }
68 
69 void
70 CollisionInteraction::setCollisionHandlingA(std::shared_ptr<CollisionHandling> colHandlingA)
71 {
72  m_colHandlingA = colHandlingA;
73 }
74 
75 void
76 CollisionInteraction::setCollisionHandlingB(std::shared_ptr<CollisionHandling> colHandlingB)
77 {
78  m_colHandlingB = colHandlingB;
79 }
80 
81 void
82 CollisionInteraction::setCollisionHandlingAB(std::shared_ptr<CollisionHandling> colHandlingAB)
83 {
84  m_colHandlingA = m_colHandlingB = colHandlingAB;
85 }
86 
87 void
89 {
90  if (m_colDetect != nullptr)
91  {
92  m_colDetect->update();
93  }
94 
95  auto dataVector = m_colDetect->getCollisionDataVector();
96  for (const auto& item : *dataVector)
97  {
98  if (item->elementsA.empty() && item->elementsB.empty())
99  {
100  continue;
101  }
102  m_objA->addCollision(m_objB, item);
103  m_objB->addCollision(m_objA, item);
104  }
105 }
106 
107 void
109 {
110  if (m_colHandlingA != nullptr)
111  {
112  m_colHandlingA->update();
113  }
114 }
115 
116 void
118 {
119  if (m_colHandlingB != nullptr)
120  {
121  m_colHandlingB->update();
122  }
123 }
124 
125 void
126 CollisionInteraction::updateCollisionGeometry()
127 {
128  // Ensure the collision geometry is updated before checking collision
129  // this could involve a geometry map or something, ex: simulated
130  // tet mesh mapped to a collision surface mesh
131  if (auto colObj1 = std::dynamic_pointer_cast<CollidingObject>(m_objA))
132  {
133  colObj1->updateGeometries();
134  }
135  if (auto colObj2 = std::dynamic_pointer_cast<CollidingObject>(m_objB))
136  {
137  colObj2->updateGeometries();
138  }
139 }
140 
141 void
143 {
144  m_collisionDetectionNode->setEnabled(enabled);
145 
146  if (m_colDetect != nullptr)
147  {
148  for (size_t i = 0; i < m_colDetect->getCollisionDataVectorSize(); ++i)
149  {
150  if (auto data = m_colDetect->getCollisionData())
151  {
152  // Clear the data (since CD clear is only run before CD is performed)
153  data->elementsA.resize(0);
154  data->elementsB.resize(0);
155  }
156  }
157  }
158  else
159  {
160  LOG(WARNING) << "Tried to enable/disable collision, but no CD method was provided";
161  }
162 }
163 
164 bool
165 CollisionInteraction::getEnabled() const
166 {
167  return m_collisionDetectionNode->m_enabled;
168 }
169 
170 void
172 {
173  m_didUpdateThisFrame = false;
174 }
175 } // namespace imstk
void setCollisionHandlingAB(std::shared_ptr< CollisionHandling > colHandlingAB)
Set the two-way Collision Handling for both objects.
void setCollisionHandlingB(std::shared_ptr< CollisionHandling > colHandlingB)
Set the Collision Handling for object B.
Compound Geometry.
static std::shared_ptr< CollisionDetectionAlgorithm > makeCollisionDetection(const std::string collisionTypeName)
attempts to create a new CD algorithm
void visualUpdate() override
Update the visuals, called before render.
void setCollisionHandlingA(std::shared_ptr< CollisionHandling > colHandlingA)
Set the Collision Handling for object A.
virtual void setEnabled(const bool enabled)
Enable or disable the interaction, when disabled the interaction isn&#39;t executed and no response will ...