iMSTK
Interactive Medical Simulation Toolkit
NeedleRigidBodyCH.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 "NeedleRigidBodyCH.h"
8 #include "imstkArcNeedle.h"
9 #include "imstkPuncturable.h"
10 #include "imstkRbdContactConstraint.h"
11 #include "imstkRigidBodyModel2.h"
12 #include "imstkRigidObject2.h"
13 #include "RbdPointToArcConstraint.h"
14 
15 void
17  const std::vector<CollisionElement>& elementsA,
18  const std::vector<CollisionElement>& elementsB)
19 {
20  // Do it the normal way
21  RigidBodyCH::handle(elementsA, elementsB);
22 
23  // If no collision, needle must be removed
24  auto needleObj = std::dynamic_pointer_cast<RigidObject2>(getInputObjectA());
25  auto needle = needleObj->getComponent<ArcNeedle>();
26 
27  std::shared_ptr<CollidingObject> tissueObj = getInputObjectB();
28  auto puncturable = tissueObj->getComponent<Puncturable>();
29 
30  const PunctureId punctureId = getPunctureId(needle, puncturable);
31  const Puncture::State state = needle->getState(punctureId);
32 
33  if (elementsA.size() != 0)
34  {
35  if (state == Puncture::State::INSERTED)
36  {
37  const Mat3d& rot = needleObj->getRigidBody()->getOrientation().toRotationMatrix();
38  const Vec3d& pos = needleObj->getRigidBody()->getPosition();
39 
40  const Mat3d& arcBasis = rot * needle->getArcBasis();
41  const Vec3d& arcCenter = pos + rot * needle->getArcCenter();
42  const double arcRadius = needle->getArcRadius();
43  const double arcBeginRad = needle->getBeginRad();
44  const double arcEndRad = needle->getEndRad();
45 
46  // Constrain along the axes, whilst allowing "pushing" of the contact point
47  auto pointToArcConstraint = std::make_shared<RbdPointToArcConstraint>(
48  needleObj->getRigidBody(),
49  arcCenter,
50  arcBeginRad, arcEndRad,
51  arcRadius,
52  arcBasis,
53  m_initContactPt,
54  m_beta);
55  pointToArcConstraint->compute(needleObj->getRigidBodyModel2()->getTimeStep());
56  needleObj->getRigidBodyModel2()->addConstraint(pointToArcConstraint);
57  }
58  }
59  else
60  {
61  if (state == Puncture::State::INSERTED || state == Puncture::State::TOUCHING)
62  {
63  if (state == Puncture::State::INSERTED)
64  {
65  LOG(INFO) << "Unpuncture!";
66  }
67  needle->setState(punctureId, Puncture::State::REMOVED);
68  }
69  }
70 }
71 
72 void
74  std::shared_ptr<RigidObject2> rbdObj,
75  const Vec3d& contactPt, const Vec3d& contactNormal,
76  const double contactDepth)
77 {
78  // If no collision, needle must be removed
79  auto needleObj = std::dynamic_pointer_cast<RigidObject2>(getInputObjectA());
80  auto needle = needleObj->getComponent<ArcNeedle>();
81 
82  std::shared_ptr<CollidingObject> tissueObj = getInputObjectB();
83  auto puncturable = tissueObj->getComponent<Puncturable>();
84  const PunctureId punctureId = getPunctureId(needle, puncturable);
85 
86  // If removed and we are here, we must now be touching
87  if (needle->getState(punctureId) == Puncture::State::REMOVED)
88  {
89  needle->setState(punctureId, Puncture::State::TOUCHING);
90  }
91 
92  // If touching we may test for insertion
93  const Vec3d n = contactNormal.normalized();
94  if (needle->getState(punctureId) == Puncture::State::TOUCHING)
95  {
96  // Get all inwards force
97  const double fN = std::max(-contactNormal.dot(rbdObj->getRigidBody()->getForce()), 0.0);
98 
99  // If the normal force exceeds threshold the needle may insert
100  if (fN > m_forceThreshold)
101  {
102  LOG(INFO) << "Puncture!";
103  needle->setState(punctureId, Puncture::State::INSERTED);
104  puncturable->setPuncture(punctureId, needle->getPuncture(punctureId));
105 
106  // Record the initial contact point
107  m_initOrientation = Quatd(rbdObj->getCollidingGeometry()->getRotation());
108  m_initContactPt = contactPt;
109  }
110  }
111 
112  // Only add contact normal constraint if not inserted
113  Puncture::State state = needle->getState(punctureId);
114  if (state == Puncture::State::TOUCHING)
115  {
116  auto contactConstraint = std::make_shared<RbdContactConstraint>(
117  rbdObj->getRigidBody(), nullptr,
118  n, contactPt, contactDepth,
119  m_beta,
120  RbdConstraint::Side::A);
121  contactConstraint->compute(rbdObj->getRigidBodyModel2()->getTimeStep());
122  rbdObj->getRigidBodyModel2()->addConstraint(contactConstraint);
123  }
124 }
PunctureId getPunctureId(std::shared_ptr< Needle > needle, std::shared_ptr< Puncturable > puncturable, const int supportId)
Get puncture id between needle and puncturable.
Place this on an object to make it puncturable by a needle. This allows puncturables to know they&#39;ve ...
std::shared_ptr< Component > getComponent(const unsigned int index) const
Get a component by index.
Definition: imstkEntity.cpp:43
void handle(const std::vector< CollisionElement > &elementsA, const std::vector< CollisionElement > &elementsB) override
Handle the collision/contact data.
std::shared_ptr< CollidingObject > getInputObjectA() const
Get the input objects.
void addConstraint(std::shared_ptr< RigidObject2 > rbdObj, const Vec3d &contactPt, const Vec3d &contactNormal, const double contactDepth) override
Add constraint for the rigid body given contact.
Scene objects that are governed by rigid body dynamics under the RigidBodyModel2. ...
std::tuple< int, int, int > PunctureId
Punctures are identified via three ints. The needle id, the puncturable id, and a local id that allow...
Definition: imstkPuncture.h:21