iMSTK
Interactive Medical Simulation Toolkit
NeedleRigidBodyCH.h
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 #pragma once
8 
9 #include "imstkMacros.h"
10 #include "imstkNeedle.h"
11 #include "imstkPuncturable.h"
12 #include "imstkRbdContactConstraint.h"
13 #include "imstkRigidBodyCH.h"
14 #include "imstkRigidBodyModel2.h"
15 #include "imstkRigidObject2.h"
16 
17 #include "RbdAxesLockingConstraint.h"
18 #include "RbdAngularLockingConstraint.h"
19 
20 using namespace imstk;
21 
22 class NeedleRigidBodyCH : public RigidBodyCH
23 {
24 public:
25  NeedleRigidBodyCH() = default;
26  ~NeedleRigidBodyCH() override = default;
27 
28  IMSTK_TYPE_NAME(NeedleRigidBodyCH)
29 
30  void setNeedleForceThreshold(double needleForceThreshold) { m_needleForceThreshold = needleForceThreshold; }
31  double getNeedleForceThrehsold() const { return m_needleForceThreshold; }
32 
33 protected:
37  void handle(
38  const std::vector<CollisionElement>& elementsA,
39  const std::vector<CollisionElement>& elementsB) override
40  {
41  std::shared_ptr<CollidingObject> needleObj = getInputObjectA();
42  m_needle = needleObj->getComponent<Needle>();
43  std::shared_ptr<CollidingObject> tissueObj = getInputObjectB();
44  m_puncturable = tissueObj->getComponent<Puncturable>();
45 
46  // Do it the normal way
47  RigidBodyCH::handle(elementsA, elementsB);
48 
49  // If no collision, needle must be removed
50  if (elementsA.size() == 0)
51  {
52  m_needle->setState(getPunctureId(m_needle, m_puncturable), Puncture::State::REMOVED);
53  }
54  }
55 
60  std::shared_ptr<RigidObject2> rbdObj,
61  const Vec3d& contactPt, const Vec3d& contactNormal,
62  const double contactDepth) override
63  {
64  // If the normal force exceeds threshold the needle may insert
65  const PunctureId punctureId = getPunctureId(m_needle, m_puncturable);
66 
67  const Vec3d n = contactNormal.normalized();
68  if (m_needle->getState(punctureId) == Puncture::State::TOUCHING)
69  {
70  // Get all inwards force
71  const Vec3d needleAxes = m_needle->getNeedleDirection();
72  const double fN = std::max(needleAxes.dot(rbdObj->getRigidBody()->getForce()), 0.0);
73 
74  if (fN > m_needleForceThreshold)
75  {
76  LOG(INFO) << "Puncture!\n";
77  m_needle->setState(punctureId, Puncture::State::INSERTED);
78 
79  // Record the axes to constrain too
80  m_initNeedleAxes = needleAxes;
81  m_initNeedleOrientation = Quatd::FromTwoVectors(Vec3d(0.0, -1.0, 0.0), needleAxes);
82  m_initContactPt = contactPt;
83  }
84  }
85 
86  // Only add contact normal constraint if not inserted
87  if (m_needle->getState(punctureId) == Puncture::State::TOUCHING)
88  {
89  auto contactConstraint = std::make_shared<RbdContactConstraint>(
90  rbdObj->getRigidBody(), nullptr,
91  n, contactPt, contactDepth,
92  m_beta,
93  RbdConstraint::Side::A);
94  contactConstraint->compute(rbdObj->getRigidBodyModel2()->getTimeStep());
95  rbdObj->getRigidBodyModel2()->addConstraint(contactConstraint);
96  }
97  // Lock to the initial axes when the needle is inserted
98  else if (m_needle->getState(punctureId) == Puncture::State::INSERTED)
99  {
100  auto needleLockConstraint = std::make_shared<RbdAxesLockingConstraint>(
101  rbdObj->getRigidBody(),
102  m_initContactPt, m_initNeedleAxes,
103  0.05);
104  needleLockConstraint->compute(rbdObj->getRigidBodyModel2()->getTimeStep());
105  rbdObj->getRigidBodyModel2()->addConstraint(needleLockConstraint);
106 
107  auto needleLockConstraint2 = std::make_shared<RbdAngularLockingConstraint>(
108  rbdObj->getRigidBody(), m_initNeedleOrientation, 0.05);
109  needleLockConstraint2->compute(rbdObj->getRigidBodyModel2()->getTimeStep());
110  rbdObj->getRigidBodyModel2()->addConstraint(needleLockConstraint2);
111  }
112  }
113 
114 protected:
115  double m_needleForceThreshold = 250.0;
116 
117  std::shared_ptr<Needle> m_needle;
118  std::shared_ptr<Puncturable> m_puncturable;
119  Vec3d m_initContactPt = Vec3d::Zero();
120  Vec3d m_initNeedleAxes = Vec3d::Zero();
121  Quatd m_initNeedleOrientation = Quatd::Identity();
122 };
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 ...
Compound Geometry.
void handle(const std::vector< CollisionElement > &elementsA, const std::vector< CollisionElement > &elementsB) override
Handle the collision/contact data.
Base for all needles in imstk it supports global puncture state, per object puncture state...
Definition: imstkNeedle.h:20
virtual void handle(const std::vector< CollisionElement > &elementsA, const std::vector< CollisionElement > &elementsB) override
Add rigid body constraints according to contacts.
Creates rigid body contact and frictional constraints given collision data then adds them to the rigi...
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.
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