iMSTK
Interactive Medical Simulation Toolkit
imstkPortHoleInteraction.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 "imstkPortHoleInteraction.h"
8 #include "imstkCapsule.h"
9 #include "imstkLineMesh.h"
10 #include "imstkPbdContactConstraint.h"
11 #include "imstkPbdModel.h"
12 #include "imstkPbdObject.h"
13 #include "imstkPbdSolver.h"
14 #include "imstkTaskGraph.h"
15 #include "imstkTaskNode.h"
16 
17 namespace imstk
18 {
19 PortHoleInteraction::PortHoleInteraction(const std::string& name) : SceneBehaviour(true, name),
20  m_portConstraint(std::make_shared<PbdRigidLineToPointConstraint>())
21 {
22  m_portHoleHandleNode = std::make_shared<TaskNode>([&]()
23  {
24  handlePortHole();
25  }, "PortHoleHandle");
26  m_collisionGeometryUpdateNode = std::make_shared<TaskNode>([&]()
27  {
28  m_toolObject->updateGeometries();
29  }, "CollisionGeometryUpdate");
30 
31  m_constraints.resize(1);
32  m_constraints[0] = m_portConstraint.get();
33 }
34 
35 void
37 {
38  CHECK(m_toolObject != nullptr) << "PortHoleInteraction requires a input tool object,"
39  "please provide it with PortHoleInteraction::setTool";
40  CHECK(m_toolGeom != nullptr) << "PortHoleInteraction requires a tool geometry,"
41  "please provide it with PortHoleInteraction::setToolGeometry";
42 
43  m_taskGraph->addNode(m_portHoleHandleNode);
44  m_taskGraph->addNode(m_collisionGeometryUpdateNode);
45  m_taskGraph->addNode(m_toolObject->getPbdModel()->getIntegratePositionNode());
46  m_taskGraph->addNode(m_toolObject->getPbdModel()->getSolveNode());
47 }
48 
49 void
50 PortHoleInteraction::setTool(std::shared_ptr<PbdObject> toolObject)
51 {
52  CHECK(m_toolObject == nullptr) << "PortHoleInteraction does not yet support changing"
53  "the tool at runtime, please set before initialization of the scene";
54  m_toolObject = toolObject;
55 }
56 
57 void
58 PortHoleInteraction::setToolGeometry(std::shared_ptr<Geometry> toolGeom)
59 {
60  CHECK(std::dynamic_pointer_cast<LineMesh>(toolGeom) != nullptr
61  || std::dynamic_pointer_cast<Capsule>(toolGeom) != nullptr) <<
62  "PortHoleInteraction only works with capsule or line tool geometry";
63  m_toolGeom = toolGeom;
64 }
65 
66 void
67 PortHoleInteraction::handlePortHole()
68 {
69  // \todo: Extend to support constraint of non single element tools and non straight tools
70  CHECK(m_toolGeom != nullptr) <<
71  "PortHoleInteraction requires a tool geometry";
72 
73  Vec3d p, q;
74  p = q = Vec3d::Zero();
75  if (auto lineMesh = std::dynamic_pointer_cast<LineMesh>(m_toolGeom))
76  {
77  CHECK(lineMesh->getNumVertices() == 2) <<
78  "PortHoleInteraction currently only works with straight single segment lines";
79 
80  p = (*lineMesh->getVertexPositions())[0];
81  q = (*lineMesh->getVertexPositions())[1];
82  }
83  else if (auto capsule = std::dynamic_pointer_cast<Capsule>(m_toolGeom))
84  {
85  const Vec3d capsule1Pos = capsule->getPosition();
86  const Vec3d capsule1Axis = capsule->getOrientation().toRotationMatrix().col(1).normalized();
87  const double capsule1HalfLength = capsule->getLength() * 0.5;
88  const Vec3d diff1 = capsule1Axis * capsule1HalfLength;
89 
90  p = capsule1Pos - diff1;
91  q = capsule1Pos + diff1;
92  }
93 
94  std::shared_ptr<PbdModel> pbdModel = m_toolObject->getPbdModel();
95  const PbdParticleId vid = pbdModel->addVirtualParticle(m_portHoleLocation, 0.0);
96 
97  m_portConstraint->initConstraint(m_toolObject->getPbdModel()->getBodies(),
98  { m_toolObject->getPbdBody()->bodyHandle, 0 },
99  p, q, vid,
100  m_compliance);
101 
102  pbdModel->getSolver()->addConstraints(&m_constraints);
103 }
104 
105 void
106 PortHoleInteraction::initGraphEdges(std::shared_ptr<TaskNode> source, std::shared_ptr<TaskNode> sink)
107 {
108  // Add the collision constraint after internal solve but before collision solve
109  // Also ensure collision geometry is up to date
110  m_taskGraph->addEdge(source, m_toolObject->getPbdModel()->getSolveNode());
111 
112  m_taskGraph->addEdge(m_toolObject->getPbdModel()->getIntegratePositionNode(), m_collisionGeometryUpdateNode);
113  m_taskGraph->addEdge(m_collisionGeometryUpdateNode, m_portHoleHandleNode);
114  m_taskGraph->addEdge(m_portHoleHandleNode, m_toolObject->getPbdModel()->getSolveNode());
115 
116  m_taskGraph->addEdge(m_portHoleHandleNode, sink);
117 }
118 } // namespace imstk
void init() override
Initialize the component, called at a later time after all component construction is complete...
std::pair< int, int > PbdParticleId
Index pair that refers to a particle in a PbdState. Index 0 is the body id, Index 1 is the particle i...
Compound Geometry.