iMSTK
Interactive Medical Simulation Toolkit
imstkRigidObjectLevelSetCollision.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 "imstkRigidObjectLevelSetCollision.h"
8 #include "imstkCollisionData.h"
9 #include "imstkImplicitGeometry.h"
10 #include "imstkImplicitGeometryToPointSetCCD.h"
11 #include "imstkImplicitGeometryToPointSetCD.h"
12 #include "imstkLevelSetCH.h"
13 #include "imstkLevelSetDeformableObject.h"
14 #include "imstkLevelSetModel.h"
15 #include "imstkParallelFor.h"
16 #include "imstkRigidBodyCH.h"
17 #include "imstkRigidBodyModel2.h"
18 #include "imstkRigidObject2.h"
19 #include "imstkSurfaceMesh.h"
20 #include "imstkTaskGraph.h"
21 #include "imstkVecDataArray.h"
22 
23 namespace imstk
24 {
25 RigidObjectLevelSetCollision::RigidObjectLevelSetCollision(std::shared_ptr<RigidObject2> obj1, std::shared_ptr<LevelSetDeformableObject> obj2) :
26  CollisionInteraction("RigidObjectLevelSetCollision" + obj1->getName() + "_vs_" + obj2->getName(), obj1, obj2, std::string("ImplicitGeometryToPointSetCCD")),
27  m_prevVertices(std::make_shared<VecDataArray<double, 3>>())
28 {
29  std::shared_ptr<RigidBodyModel2> rbdModel = obj1->getRigidBodyModel2();
30  std::shared_ptr<LevelSetModel> lvlSetModel = obj2->getLevelSetModel();
31 
32  if (rbdModel == nullptr || lvlSetModel == nullptr)
33  {
34  LOG(WARNING) << "RigidObjectCollisionPair, could not create";
35  return;
36  }
37 
38  // Graph of explicit interaction
39  // [compute tentative velocities] [lvlSetSource]
40  // [CD]
41  // [Add rigid constraints] [Apply impulses]
42  // [Solve rbd system] [Evolve levelset]
43  // Here the CH's adds constraints to the system on the LHS, and impulses to the levelset RHS
44 
45  m_taskGraph->addNode(rbdModel->getComputeTentativeVelocitiesNode());
46  m_taskGraph->addNode(lvlSetModel->getGenerateVelocitiesBeginNode());
47 
48  m_taskGraph->addNode(rbdModel->getSolveNode());
49  m_taskGraph->addNode(lvlSetModel->getGenerateVelocitiesEndNode());
50 
51  // Setup the rigid body handler to move the rigid body according to collision data
52  auto rbdCH = std::make_shared<RigidBodyCH>();
53  rbdCH->setInputRigidObjectA(obj1);
54  rbdCH->setInputCollidingObjectB(obj2);
55  rbdCH->setInputCollisionData(m_colDetect->getCollisionData());
56  rbdCH->setFriction(0.0);
57  setCollisionHandlingA(rbdCH);
58 
59  // Setup the levelset handler to erode the levelset according to collision data
60  auto lvlSetCH = std::make_shared<LevelSetCH>();
61  lvlSetCH->setInputLvlSetObj(obj2);
62  lvlSetCH->setInputRigidObj(obj1);
63  lvlSetCH->setInputCollisionData(m_colDetect->getCollisionData());
64  setCollisionHandlingB(lvlSetCH);
65 
66  m_copyVertToPrevNode = std::make_shared<TaskNode>([ = ]()
67  {
68  copyVertsToPrevious();
69  }, "CopyVertsToPrevious");
70  m_taskGraph->addNode(m_copyVertToPrevNode);
71 
72  m_computeDisplacementNode =
73  std::make_shared<TaskNode>(std::bind(&RigidObjectLevelSetCollision::measureDisplacementFromPrevious, this),
74  "ComputeDisplacements");
75  m_taskGraph->addNode(m_computeDisplacementNode);
76 
77  // Give the point set displacements for CCD, if it doesn't already have them
78  auto pointSet = std::dynamic_pointer_cast<PointSet>(obj1->getCollidingGeometry());
79  if (pointSet != nullptr && !pointSet->hasVertexAttribute("displacements"))
80  {
81  auto displacementsPtr = std::make_shared<VecDataArray<double, 3>>(pointSet->getNumVertices());
82  pointSet->setVertexAttribute("displacements", displacementsPtr);
83  displacementsPtr->fill(Vec3d::Zero());
84  }
85 
86  m_taskGraph->addNode(obj1->getUpdateGeometryNode());
87  m_taskGraph->addNode(obj1->getTaskGraph()->getSource());
88  m_taskGraph->addNode(obj1->getTaskGraph()->getSink());
89 }
90 
91 void
92 RigidObjectLevelSetCollision::initGraphEdges(std::shared_ptr<TaskNode> source, std::shared_ptr<TaskNode> sink)
93 {
95 
96  auto rbdObj1 = std::dynamic_pointer_cast<RigidObject2>(m_objA);
97  std::shared_ptr<RigidBodyModel2> rbdModel = rbdObj1->getRigidBodyModel2();
98 
99  auto lvlSetObj2 = std::dynamic_pointer_cast<LevelSetDeformableObject>(m_objB);
100  std::shared_ptr<LevelSetModel> lsmModel = lvlSetObj2->getLevelSetModel();
101 
102  std::shared_ptr<TaskNode> rbdHandlerNode = m_collisionHandleANode;
103  std::shared_ptr<TaskNode> lsmHandlerNode = m_collisionHandleBNode;
104 
111  m_taskGraph->addEdge(rbdModel->getComputeTentativeVelocitiesNode(), m_collisionDetectionNode);
112  m_taskGraph->addEdge(lsmModel->getGenerateVelocitiesBeginNode(), m_collisionDetectionNode);
113 
114  m_taskGraph->addEdge(m_collisionDetectionNode, rbdHandlerNode);
115  m_taskGraph->addEdge(m_collisionDetectionNode, lsmHandlerNode);
116 
117  m_taskGraph->addEdge(rbdHandlerNode, rbdModel->getSolveNode());
118  m_taskGraph->addEdge(lsmHandlerNode, lsmModel->getGenerateVelocitiesEndNode());
119 
120  std::shared_ptr<PointSet> pointSet = std::dynamic_pointer_cast<PointSet>(rbdObj1->getPhysicsGeometry());
121  const bool measureDisplacements = (pointSet != nullptr && pointSet->hasVertexAttribute("displacements"));
122 
123  // The tentative body is never actually computed, it should be good to catch the contact
124  // in the next frame
125  if (measureDisplacements)
126  {
127  // 1.) Copy the vertices at the start of the frame
128  m_taskGraph->addEdge(rbdObj1->getTaskGraph()->getSource(), m_copyVertToPrevNode);
129  m_taskGraph->addEdge(m_copyVertToPrevNode,
130  rbdObj1->getRigidBodyModel2()->getComputeTentativeVelocitiesNode());
131 
132  // If you were to update to tentative, you'd do it here, then compute displacements
133 
134  // 2.) Compute the displacements after updating geometry
135  m_taskGraph->addEdge(rbdObj1->getUpdateGeometryNode(), m_computeDisplacementNode);
136  m_taskGraph->addEdge(m_computeDisplacementNode, rbdObj1->getTaskGraph()->getSink());
137  }
138 }
139 
140 void
141 RigidObjectLevelSetCollision::copyVertsToPrevious()
142 {
143  auto obj1 = std::dynamic_pointer_cast<RigidObject2>(m_objA);
144  std::shared_ptr<PointSet> pointSet = std::dynamic_pointer_cast<PointSet>(obj1->getPhysicsGeometry());
145 
146  if (pointSet != nullptr && pointSet->hasVertexAttribute("displacements"))
147  {
148  std::shared_ptr<VecDataArray<double, 3>> verticesPtr = pointSet->getVertexPositions();
149  VecDataArray<double, 3>& vertices = *verticesPtr;
150  VecDataArray<double, 3>& prevVertices = *m_prevVertices;
151 
152  if (prevVertices.size() != vertices.size())
153  {
154  prevVertices.resize(vertices.size());
155  }
156  std::copy_n(vertices.getPointer(), vertices.size(), prevVertices.getPointer());
157  }
158 }
159 
160 void
161 RigidObjectLevelSetCollision::measureDisplacementFromPrevious()
162 {
163  auto obj1 = std::dynamic_pointer_cast<RigidObject2>(m_objA);
164  std::shared_ptr<PointSet> pointSet = std::dynamic_pointer_cast<PointSet>(obj1->getPhysicsGeometry());
165 
166  if (pointSet != nullptr && pointSet->hasVertexAttribute("displacements"))
167  {
168  std::shared_ptr<VecDataArray<double, 3>> displacements =
169  std::dynamic_pointer_cast<VecDataArray<double, 3>>(pointSet->getVertexAttribute("displacements"));
170  VecDataArray<double, 3>& displacementsArr = *displacements;
171 
172  std::shared_ptr<VecDataArray<double, 3>> verticesPtr = pointSet->getVertexPositions();
173  VecDataArray<double, 3>& vertices = *verticesPtr;
174  VecDataArray<double, 3>& prevVertices = *m_prevVertices;
175 
176  ParallelUtils::parallelFor(displacements->size(),
177  [&](const int i)
178  {
179  displacementsArr[i] = vertices[i] - prevVertices[i];
180  });
181  }
182 }
183 } // namespace imstk
Base class for all geometries represented by discrete points and elements The pointsets follow a pipe...
Definition: imstkPointSet.h:25
void setCollisionHandlingB(std::shared_ptr< CollisionHandling > colHandlingB)
Set the Collision Handling for object B.
Compound Geometry.
void resize(const int size) override
Resize data array to hold exactly size number of values.
Base class for scene objects that move and/or deform under position based dynamics formulation...
std::shared_ptr< CollisionDetectionAlgorithm > m_colDetect
Collision detection algorithm.
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.
void setCollisionHandlingA(std::shared_ptr< CollisionHandling > colHandlingA)
Set the Collision Handling for object A.
std::shared_ptr< TaskGraph > m_taskGraph
Computational Graph.
std::shared_ptr< LevelSetModel > getLevelSetModel()
Get the LevelSet model of the object.
Scene objects that are governed by rigid body dynamics under the RigidBodyModel2. ...
void initGraphEdges()
Initializes the edges of the SceneObject&#39;s computational graph.