iMSTK
Interactive Medical Simulation Toolkit
imstkRigidObjectCollision.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 "imstkRigidObjectCollision.h"
8 #include "imstkCDObjectFactory.h"
9 #include "imstkCollisionData.h"
10 #include "imstkCollisionDetectionAlgorithm.h"
11 #include "imstkParallelFor.h"
12 #include "imstkPointSet.h"
13 #include "imstkRigidBodyCH.h"
14 #include "imstkRigidBodyModel2.h"
15 #include "imstkRigidObject2.h"
16 #include "imstkTaskGraph.h"
17 #include "imstkVecDataArray.h"
18 
19 namespace imstk
20 {
21 RigidObjectCollision::RigidObjectCollision(std::shared_ptr<RigidObject2> rbdObj1, std::shared_ptr<CollidingObject> obj2,
22  std::string cdType) :
23  CollisionInteraction("RigidObjectCollision" + rbdObj1->getName() + "_vs_" + obj2->getName(), rbdObj1, obj2, cdType)
24 {
25  std::shared_ptr<RigidBodyModel2> model1 = rbdObj1->getRigidBodyModel2();
26 
27  // Only one handler is used, this means we only support one-way collisions or two-way
28  // If you want two one-way's, use two RigidObjectCollisions
29  auto ch = std::make_shared<RigidBodyCH>();
30  ch->setInputCollisionData(m_colDetect->getCollisionData());
31  ch->setInputObjectA(rbdObj1);
32  ch->setInputObjectB(obj2);
33 
34  m_copyVertToPrevNode = std::make_shared<TaskNode>([ = ]()
35  {
36  copyVertsToPrevious();
37  }, "CopyVertsToPrevious");
38  m_taskGraph->addNode(m_copyVertToPrevNode);
39  m_computeDisplacementNode = std::make_shared<TaskNode>([ = ]()
40  {
41  measureDisplacementFromPrevious();
42  }, "ComputeDisplacements");
43  m_taskGraph->addNode(m_computeDisplacementNode);
44 
45  if (auto rbdObj2 = std::dynamic_pointer_cast<RigidObject2>(obj2))
46  {
47  std::shared_ptr<RigidBodyModel2> model2 = rbdObj2->getRigidBodyModel2();
48 
49  // These could possibly be the same node if they belong to the same system
50  // Handled implicitly
51  m_taskGraph->addNode(model1->getComputeTentativeVelocitiesNode());
52  m_taskGraph->addNode(model2->getComputeTentativeVelocitiesNode());
53 
54  m_taskGraph->addNode(model1->getSolveNode());
55  m_taskGraph->addNode(model2->getSolveNode());
56 
57  setCollisionHandlingAB(ch);
58  }
59  else
60  {
61  // Define where collision interaction happens
62  m_taskGraph->addNode(model1->getComputeTentativeVelocitiesNode());
63  m_taskGraph->addNode(obj2->getTaskGraph()->getSource());
64 
65  m_taskGraph->addNode(model1->getSolveNode());
66  m_taskGraph->addNode(obj2->getUpdateNode());
67 
68  // Setup the handlers for only A and inform CD it only needs to generate A
69  m_colDetect->setGenerateCD(true, false);
70  setCollisionHandlingA(ch);
71  }
72 
73  m_taskGraph->addNode(rbdObj1->getUpdateGeometryNode());
74  m_taskGraph->addNode(rbdObj1->getTaskGraph()->getSource());
75  m_taskGraph->addNode(rbdObj1->getTaskGraph()->getSink());
76  m_taskGraph->addNode(obj2->getTaskGraph()->getSource());
77  m_taskGraph->addNode(obj2->getTaskGraph()->getSink());
78 }
79 
80 void
81 RigidObjectCollision::setBaumgarteStabilization(double beta)
82 {
83  std::dynamic_pointer_cast<RigidBodyCH>(getCollisionHandlingA())->setBaumgarteStabilization(beta);
84 }
85 
86 const double
87 RigidObjectCollision::getBeta() const
88 {
89  return std::dynamic_pointer_cast<RigidBodyCH>(getCollisionHandlingA())->getBeta();
90 }
91 
92 void
93 RigidObjectCollision::setFriction(double frictionalCoefficient)
94 {
95  std::dynamic_pointer_cast<RigidBodyCH>(getCollisionHandlingA())->setFriction(frictionalCoefficient);
96 }
97 
98 const double
99 RigidObjectCollision::getFriction() const
100 {
101  return std::dynamic_pointer_cast<RigidBodyCH>(getCollisionHandlingA())->getFriction();
102 }
103 
104 void
105 RigidObjectCollision::initGraphEdges(std::shared_ptr<TaskNode> source, std::shared_ptr<TaskNode> sink)
106 {
108 
109  auto rbdObj1 = std::dynamic_pointer_cast<RigidObject2>(m_objA);
110  std::shared_ptr<RigidBodyModel2> rbdModel1 = rbdObj1->getRigidBodyModel2();
111 
112  std::shared_ptr<TaskNode> handlerABNode = m_collisionHandleANode;
113 
114  if (auto rbdObj2 = std::dynamic_pointer_cast<RigidObject2>(m_objB))
115  {
116  std::shared_ptr<RigidBodyModel2> rbdModel2 = rbdObj2->getRigidBodyModel2();
117 
118  // Note: ComputeTenative and RbdModel may be the same
119  // ComputeTenative Velocities 1 ComputeTenative Velocities 2
120  // Collision Detection
121  // Collision Handling
122  // Rbd Solve 1 Rbd Solve 2
123  m_taskGraph->addEdge(rbdModel1->getComputeTentativeVelocitiesNode(), m_collisionDetectionNode);
124  m_taskGraph->addEdge(rbdModel2->getComputeTentativeVelocitiesNode(), m_collisionDetectionNode);
125 
126  m_taskGraph->addEdge(m_collisionDetectionNode, handlerABNode);
127  m_taskGraph->addEdge(handlerABNode, rbdModel1->getSolveNode());
128  m_taskGraph->addEdge(handlerABNode, rbdModel2->getSolveNode());
129  }
130  else
131  {
132  // Note: ComputeTenative and RbdModel may be the same
133  /* ComputeTenative Velocities 1 CollidingObject Source
134  Collision Detection
135  Collision Handling \
136  Rbd Solve 1 CollidingObject Update */
137  m_taskGraph->addEdge(rbdModel1->getComputeTentativeVelocitiesNode(), m_collisionDetectionNode);
138  m_taskGraph->addEdge(m_objB->getTaskGraph()->getSource(), m_collisionDetectionNode);
139 
140  m_taskGraph->addEdge(m_collisionDetectionNode, handlerABNode);
141  m_taskGraph->addEdge(handlerABNode, rbdModel1->getSolveNode());
142  m_taskGraph->addEdge(m_collisionDetectionNode, m_objB->getUpdateNode());
143  }
144 
145  // \todo: This should be handled differently (per object, not per interaction)
146  std::shared_ptr<PointSet> pointSet = std::dynamic_pointer_cast<PointSet>(rbdObj1->getPhysicsGeometry());
147  const bool measureDisplacements = (pointSet != nullptr && pointSet->hasVertexAttribute("displacements"));
148 
149  // The tentative body is never actually computed, it should be good to catch the contact
150  // in the next frame
151  if (measureDisplacements)
152  {
153  // 1.) Copy the vertices at the start of the frame
154  m_taskGraph->addEdge(rbdObj1->getTaskGraph()->getSource(), m_copyVertToPrevNode);
155  m_taskGraph->addEdge(m_copyVertToPrevNode, rbdObj1->getRigidBodyModel2()->getComputeTentativeVelocitiesNode());
156 
157  // If you were to update to tentative, you'd do it here, then compute displacements
158 
159  // 2.) Compute the displacements after updating geometry
160  m_taskGraph->addEdge(rbdObj1->getUpdateGeometryNode(), m_computeDisplacementNode);
161  m_taskGraph->addEdge(m_computeDisplacementNode, rbdObj1->getTaskGraph()->getSink());
162  }
163 }
164 
165 void
166 RigidObjectCollision::copyVertsToPrevious()
167 {
168  auto obj1 = std::dynamic_pointer_cast<RigidObject2>(m_objA);
169  std::shared_ptr<PointSet> pointSet = std::dynamic_pointer_cast<PointSet>(obj1->getPhysicsGeometry());
170 
171  if (pointSet != nullptr && pointSet->hasVertexAttribute("displacements"))
172  {
173  std::shared_ptr<VecDataArray<double, 3>> verticesPtr = pointSet->getVertexPositions();
174  VecDataArray<double, 3>& vertices = *verticesPtr;
175  VecDataArray<double, 3>& prevVertices = *m_prevVertices;
176 
177  if (prevVertices.size() != vertices.size())
178  {
179  prevVertices.resize(vertices.size());
180  }
181  std::copy_n(vertices.getPointer(), vertices.size(), prevVertices.getPointer());
182  }
183 }
184 
185 void
186 RigidObjectCollision::measureDisplacementFromPrevious()
187 {
188  auto obj1 = std::dynamic_pointer_cast<RigidObject2>(m_objA);
189  std::shared_ptr<PointSet> pointSet = std::dynamic_pointer_cast<PointSet>(obj1->getPhysicsGeometry());
190 
191  if (pointSet != nullptr && pointSet->hasVertexAttribute("displacements"))
192  {
193  std::shared_ptr<VecDataArray<double, 3>> displacements =
194  std::dynamic_pointer_cast<VecDataArray<double, 3>>(pointSet->getVertexAttribute("displacements"));
195  VecDataArray<double, 3>& displacementsArr = *displacements;
196 
197  std::shared_ptr<VecDataArray<double, 3>> verticesPtr = pointSet->getVertexPositions();
198  VecDataArray<double, 3>& vertices = *verticesPtr;
199  VecDataArray<double, 3>& prevVertices = *m_prevVertices;
200 
201  ParallelUtils::parallelFor(displacements->size(),
202  [&](const int i)
203  {
204  displacementsArr[i] = vertices[i] - prevVertices[i];
205  });
206  }
207 }
208 } // namespace imstk
Base class for all geometries represented by discrete points and elements The pointsets follow a pipe...
Definition: imstkPointSet.h:25
Compound Geometry.
void resize(const int size) override
Resize data array to hold exactly size number of values.
std::shared_ptr< VecDataArray< double, 3 > > getVertexPositions(DataType type=DataType::PostTransform) const
Returns the vector of current positions of the mesh vertices.
std::shared_ptr< RigidBodyModel2 > getRigidBodyModel2()
Add local force at a position relative to object.
std::shared_ptr< TaskGraph > m_taskGraph
Computational Graph.
Scene objects that are governed by rigid body dynamics under the RigidBodyModel2. ...
void initGraphEdges()
Initializes the edges of the SceneObject&#39;s computational graph.