iMSTK
Interactive Medical Simulation Toolkit
pbdSutureSelfCCD.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 "imstkCamera.h"
8 #include "imstkKeyboardDeviceClient.h"
9 #include "imstkKeyboardSceneControl.h"
10 #include "imstkMeshIO.h"
11 #include "imstkMouseDeviceClient.h"
12 #include "imstkMouseSceneControl.h"
13 #include "imstkPbdModel.h"
14 #include "imstkPbdModelConfig.h"
15 #include "imstkPbdObject.h"
16 #include "imstkPbdObjectCollision.h"
17 #include "imstkRbdConstraint.h"
18 #include "imstkRenderMaterial.h"
19 #include "imstkRigidBodyModel2.h"
20 #include "imstkRigidObject2.h"
21 #include "imstkRigidObjectController.h"
22 #include "imstkScene.h"
23 #include "imstkSceneManager.h"
24 #include "imstkSimulationManager.h"
25 #include "imstkSimulationUtils.h"
26 #include "imstkVisualModel.h"
27 #include "imstkVTKViewer.h"
28 
29 #ifdef iMSTK_USE_HAPTICS
30 #include "imstkDeviceManager.h"
31 #include "imstkDeviceManagerFactory.h"
32 #else
33 #include "imstkDummyClient.h"
34 #endif
35 
36 using namespace imstk;
37 
41 static std::shared_ptr<PbdObject>
42 makePbdString(const std::string& name, const std::string& filename)
43 {
44  // Setup the Geometry
45  auto stringMesh = MeshIO::read<LineMesh>(filename);
46 
47  const int numVerts = stringMesh->getNumVertices();
48 
49  // Setup the Parameters
50  auto pbdParams = std::make_shared<PbdModelConfig>();
51  pbdParams->m_gravity = Vec3d(0.0, -9.8, 0.0);
52  pbdParams->m_dt = 0.0005;
53  pbdParams->m_iterations = 1;
54  pbdParams->m_linearDampingCoeff = 0.03;
55 
56  // Setup the Model
57  auto pbdModel = std::make_shared<PbdModel>();
58  pbdModel->configure(pbdParams);
59 
60  // Setup the VisualModel
61  auto material = std::make_shared<RenderMaterial>();
62  material->setBackFaceCulling(false);
63  material->setColor(Color::Red);
64  material->setLineWidth(4.0);
65  material->setPointSize(6.0);
66  material->setDisplayMode(RenderMaterial::DisplayMode::Wireframe);
67 
68  auto visualModel = std::make_shared<VisualModel>();
69  visualModel->setGeometry(stringMesh);
70  visualModel->setRenderMaterial(material);
71 
72  // Setup the Object
73  auto stringObj = std::make_shared<PbdObject>(name);
74  stringObj->addVisualModel(visualModel);
75  stringObj->setPhysicsGeometry(stringMesh);
76  stringObj->setCollidingGeometry(stringMesh);
77  stringObj->setDynamicalModel(pbdModel);
78 
79  stringObj->getPbdBody()->uniformMassValue = 0.0001 / numVerts; // grams
80  stringObj->getPbdBody()->fixedNodeIds = { 0, 1,
81  stringMesh->getNumVertices() - 2, stringMesh->getNumVertices() - 1 };
82  pbdParams->enableConstraint(PbdModelConfig::ConstraintGenType::Distance, 200.0);
83  pbdParams->enableBendConstraint(0.01, 1);
84  //pbdParams->enableBendConstraint(.5, 2);
85 
86  return stringObj;
87 }
88 
89 static std::shared_ptr<RigidObject2>
90 makeNeedleObj()
91 {
92  auto needleObj = std::make_shared<RigidObject2>();
93 
94  auto sutureMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/Surgical Instruments/Needles/c6_suture.stl");
95 
96  const Mat4d rot = mat4dRotation(Rotd(-PI_2, Vec3d(0.0, 1.0, 0.0))) *
97  mat4dRotation(Rotd(-0.6, Vec3d(1.0, 0.0, 0.0)));
98  sutureMesh->transform(rot, Geometry::TransformType::ApplyToData);
99 
100  needleObj->setVisualGeometry(sutureMesh);
101  needleObj->setCollidingGeometry(sutureMesh);
102  needleObj->setPhysicsGeometry(sutureMesh);
103  needleObj->getVisualModel(0)->getRenderMaterial()->setColor(Color(0.9, 0.9, 0.9));
104  needleObj->getVisualModel(0)->getRenderMaterial()->setShadingModel(RenderMaterial::ShadingModel::PBR);
105  needleObj->getVisualModel(0)->getRenderMaterial()->setRoughness(0.5);
106  needleObj->getVisualModel(0)->getRenderMaterial()->setMetalness(1.0);
107 
108  std::shared_ptr<RigidBodyModel2> rbdModel = std::make_shared<RigidBodyModel2>();
109  rbdModel->getConfig()->m_gravity = Vec3d::Zero();
110  rbdModel->getConfig()->m_maxNumIterations = 5;
111  needleObj->setDynamicalModel(rbdModel);
112 
113  needleObj->getRigidBody()->m_mass = 1.0;
114  needleObj->getRigidBody()->m_intertiaTensor = Mat3d::Identity() * 10000.0;
115  needleObj->getRigidBody()->m_initPos = Vec3d(0.0, 0.0, 0.0);
116 
117  auto controller = needleObj->addComponent<RigidObjectController>();
118  controller->setControlledObject(needleObj);
119  controller->setTranslationOffset(Vec3d(-0.02, 0.02, 0.0));
120  controller->setLinearKs(1000.0);
121  controller->setAngularKs(10000000.0);
122  controller->setUseCritDamping(true);
123  controller->setForceScaling(0.0);
124 
125  return needleObj;
126 }
127 
130 int
131 main()
132 {
133  // Setup logger (write to file and stdout)
135 
136  auto scene = std::make_shared<Scene>("PbdSutureSelfCCD");
137 
138  std::shared_ptr<PbdObject> threadObj =
139  // makePbdString("selfCCDLine", "");
140  makePbdString("granny_knot", iMSTK_DATA_ROOT "/LineMesh/granny_knot.obj");
141  scene->addSceneObject(threadObj);
142 
143  auto interaction = std::make_shared<PbdObjectCollision>(threadObj, threadObj);
144  // Important parameter for stability, take multiple smaller steps to resolve multiple contacts
145  interaction->setDeformableStiffnessA(0.05);
146  interaction->setDeformableStiffnessB(0.05);
147  scene->addInteraction(interaction);
148 
149  // Create the arc needle
150  std::shared_ptr<RigidObject2> needleObj = makeNeedleObj();
151  scene->addSceneObject(needleObj);
152 
153  // Adjust the camera
154  scene->getActiveCamera()->setFocalPoint(0.022, -0.045, -0.01);
155  scene->getActiveCamera()->setPosition(0.02, -0.02, 0.2);
156  scene->getActiveCamera()->setViewUp(0, 1, 0);
157 
158  // Run the simulation
159  {
160  // Setup a viewer to render
161  auto viewer = std::make_shared<VTKViewer>();
162  viewer->setActiveScene(scene);
163  viewer->setDebugAxesLength(0.01, 0.01, 0.01);
164  viewer->setBackgroundColors(Color(202.0 / 255.0, 212.0 / 255.0, 157.0 / 255.0));
165 
166  // Setup a scene manager to advance the scene
167  auto sceneManager = std::make_shared<SceneManager>();
168  sceneManager->setActiveScene(scene);
169  sceneManager->pause(); // Start simulation paused
170 
171  // Setup a simulation manager to manage renders & scene updates
172  auto driver = std::make_shared<SimulationManager>();
173  driver->addModule(viewer);
174  driver->addModule(sceneManager);
175  driver->setDesiredDt(0.0005); // 1ms, 1000hz //timestep
176 
177  auto controller = needleObj->getComponent<RigidObjectController>();
178 #ifdef iMSTK_USE_HAPTICS
179  // Setup default haptics manager
180  std::shared_ptr<DeviceManager> hapticManager = DeviceManagerFactory::makeDeviceManager();
181  std::shared_ptr<DeviceClient> deviceClient = hapticManager->makeDeviceClient();
182  driver->addModule(hapticManager);
183 #else
184  auto deviceClient = std::make_shared<DummyClient>();
185  deviceClient->setOrientation(Quatd(Rotd(1.57, Vec3d(0.0, 1.0, 0.0))));
186 
187  connect<MouseEvent>(viewer->getMouseDevice(), &MouseDeviceClient::mouseMove,
188  [&](MouseEvent* e)
189  {
190  const Vec2d& mousePos = viewer->getMouseDevice()->getPos();
191  const Vec2d pos = (mousePos - Vec2d(0.5, 0.5)) * 0.1;
192  deviceClient->setPosition(Vec3d(pos[0], pos[1], 0.0));
193  });
194 #endif
195  controller->setDevice(deviceClient);
196 
197  // Update the thread fixed points to the controlled needle
198  connect<Event>(sceneManager, &SceneManager::preUpdate,
199  [&](Event*)
200  {
201  auto threadLineMesh = std::dynamic_pointer_cast<LineMesh>(threadObj->getPhysicsGeometry());
202  std::shared_ptr<Geometry> geom = needleObj->getPhysicsGeometry();
203  const Vec3d pos = geom->getTranslation();
204  const Mat3d rot = geom->getRotation();
205  (*threadLineMesh->getVertexPositions())[1] = pos;
206  (*threadLineMesh->getVertexPositions())[0] = pos + rot * Vec3d(0.0, 0.002, 0.0);
207  });
208 
209  // Add default mouse and keyboard controls to the viewer
210  std::shared_ptr<Entity> mouseAndKeyControls =
211  SimulationUtils::createDefaultSceneControl(driver);
212  scene->addSceneObject(mouseAndKeyControls);
213 
214  driver->start();
215  }
216 
217  return 0;
218 }
Base class for events which contain a type, priority, and data priority defaults to 0 and uses a grea...
Compound Geometry.
static std::shared_ptr< DeviceManager > makeDeviceManager()
Attempts to create a new DeviceManager by whichever is default If multiple haptic managers are built ...
Base class for all volume mesh types.
Definition: imstkLineMesh.h:18
This class uses the provided device to control the provided rigid object via virtual coupling...
Color in RGB space.
Definition: imstkColor.h:24
Provides the information of a mouse event, this includes button presses/releases and scrolling...
Physically based rendering.
static LoggerG3 & startLogger()
Starts logger with default sinks, use getInstance to create a logger with no sinks.