iMSTK
Interactive Medical Simulation Toolkit
PbdThinTissueGraspingExample.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 "imstkCapsule.h"
9 #include "imstkDeviceManager.h"
10 #include "imstkDeviceManagerFactory.h"
11 #include "imstkDirectionalLight.h"
12 #include "imstkGeometryUtilities.h"
13 #include "imstkImageData.h"
14 #include "imstkKeyboardDeviceClient.h"
15 #include "imstkKeyboardSceneControl.h"
16 #include "imstkLaparoscopicToolController.h"
17 #include "imstkMeshIO.h"
18 #include "imstkMouseDeviceClient.h"
19 #include "imstkMouseSceneControl.h"
20 #include "imstkPbdModel.h"
21 #include "imstkPbdModelConfig.h"
22 #include "imstkPbdObject.h"
23 #include "imstkPbdObjectCollision.h"
24 #include "imstkPbdObjectGrasping.h"
25 #include "imstkRenderMaterial.h"
26 #include "imstkScene.h"
27 #include "imstkSceneManager.h"
28 #include "imstkSimulationManager.h"
29 #include "imstkSimulationUtils.h"
30 #include "imstkVisualModel.h"
31 #include "imstkVTKViewer.h"
32 
33 using namespace imstk;
34 
38 static std::shared_ptr<PbdObject>
39 makeTissueObj(const std::string& name,
40  const double width,
41  const double height,
42  const int rowCount,
43  const int colCount)
44 {
45  // Setup the Geometry
46  std::shared_ptr<SurfaceMesh> mesh =
47  GeometryUtils::toTriangleGrid(Vec3d::Zero(),
48  Vec2d(width, height), Vec2i(rowCount, colCount),
49  Quatd::Identity(), 2.0);
50 
51  // Setup the Parameters
52  auto pbdParams = std::make_shared<PbdModelConfig>();
53  pbdParams->enableConstraint(PbdModelConfig::ConstraintGenType::Distance, 10000.0);
54  pbdParams->enableConstraint(PbdModelConfig::ConstraintGenType::Dihedral, 0.1);
55  pbdParams->m_gravity = Vec3d(0.0, -0.01, 0.0);
56  pbdParams->m_dt = 0.005;
57  pbdParams->m_iterations = 4;
58  pbdParams->m_linearDampingCoeff = 0.01;
59 
60  // Setup the Model
61  auto pbdModel = std::make_shared<PbdModel>();
62  pbdModel->configure(pbdParams);
63 
64  // Setup the VisualModel
65  auto material = std::make_shared<RenderMaterial>();
66  material->setBackFaceCulling(false);
67  material->setDisplayMode(RenderMaterial::DisplayMode::Surface);
68  material->setShadingModel(RenderMaterial::ShadingModel::PBR);
69  auto diffuseTex = MeshIO::read<ImageData>(iMSTK_DATA_ROOT "/textures/fleshDiffuse.jpg");
70  material->addTexture(std::make_shared<Texture>(diffuseTex, Texture::Type::Diffuse));
71  auto normalTex = MeshIO::read<ImageData>(iMSTK_DATA_ROOT "/textures/fleshNormal.jpg");
72  material->addTexture(std::make_shared<Texture>(normalTex, Texture::Type::Normal));
73  auto ormTex = MeshIO::read<ImageData>(iMSTK_DATA_ROOT "/textures/fleshORM.jpg");
74  material->addTexture(std::make_shared<Texture>(ormTex, Texture::Type::ORM));
75 
76  // Setup the Object
77  auto tissueObj = std::make_shared<PbdObject>(name);
78  tissueObj->setVisualGeometry(mesh);
79  tissueObj->getVisualModel(0)->setRenderMaterial(material);
80  tissueObj->setPhysicsGeometry(mesh);
81  tissueObj->setCollidingGeometry(mesh);
82  tissueObj->setDynamicalModel(pbdModel);
83  for (int x = 0; x < rowCount; x++)
84  {
85  for (int y = 0; y < colCount; y++)
86  {
87  if (x == 0 || y == 0 || x == rowCount - 1 || y == colCount - 1)
88  {
89  tissueObj->getPbdBody()->fixedNodeIds.push_back(x * colCount + y);
90  }
91  }
92  }
93  tissueObj->getPbdBody()->uniformMassValue = 1.0;
94 
95  return tissueObj;
96 }
97 
102 int
103 main()
104 {
105  // Setup logger (write to file and stdout)
107 
108  auto scene = std::make_shared<Scene>("PbdThinTissueGrasping");
109  scene->getActiveCamera()->setPosition(0.001, 0.05, 0.15);
110  scene->getActiveCamera()->setFocalPoint(0.0, 0.0, 0.0);
111  scene->getActiveCamera()->setViewUp(0.0, 0.96, -0.28);
112 
113  auto geomShaft = std::make_shared<Capsule>();
114  geomShaft->setLength(1.0);
115  geomShaft->setRadius(0.005);
116  geomShaft->setOrientation(Quatd(Rotd(PI_2, Vec3d(1.0, 0.0, 0.0))));
117  geomShaft->setTranslation(Vec3d(0.0, 0.0, 0.5));
118  auto objShaft = std::make_shared<CollidingObject>("ShaftObject");
119  objShaft->setVisualGeometry(MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/Surgical Instruments/LapTool/pivot.obj"));
120  objShaft->setCollidingGeometry(geomShaft);
121  scene->addSceneObject(objShaft);
122 
123  auto geomUpperJaw = std::make_shared<Capsule>();
124  geomUpperJaw->setLength(0.05);
125  geomUpperJaw->setTranslation(Vec3d(0.0, 0.0013, -0.016));
126  geomUpperJaw->setRadius(0.004);
127  geomUpperJaw->setOrientation(Quatd(Rotd(PI_2, Vec3d(1.0, 0.0, 0.0))));
128  auto objUpperJaw = std::make_shared<CollidingObject>("UpperJawObject");
129  objUpperJaw->setVisualGeometry(MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/Surgical Instruments/LapTool/upper.obj"));
130  objUpperJaw->setCollidingGeometry(geomUpperJaw);
131  scene->addSceneObject(objUpperJaw);
132 
133  auto geomLowerJaw = std::make_shared<Capsule>();
134  geomLowerJaw->setLength(0.05);
135  geomLowerJaw->setTranslation(Vec3d(0.0, -0.0013, -0.016));
136  geomLowerJaw->setRadius(0.004);
137  geomLowerJaw->setOrientation(Quatd(Rotd(PI_2, Vec3d(1.0, 0.0, 0.0))));
138  auto objLowerJaw = std::make_shared<CollidingObject>("LowerJawObject");
139  objLowerJaw->setVisualGeometry(MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/Surgical Instruments/LapTool/lower.obj"));
140  objLowerJaw->setCollidingGeometry(geomLowerJaw);
141  scene->addSceneObject(objLowerJaw);
142 
143  auto pickGeom = std::make_shared<Capsule>();
144  pickGeom->setLength(0.05);
145  pickGeom->setTranslation(Vec3d(0.0, 0.0, -0.016));
146  pickGeom->setRadius(0.006);
147  pickGeom->setOrientation(Quatd(Rotd(PI_2, Vec3d(1.0, 0.0, 0.0))));
148 
149  // 300mm x 300mm patch of tissue
150  std::shared_ptr<PbdObject> tissueObj = makeTissueObj("Tissue", 0.1, 0.1, 16, 16);
151  scene->addSceneObject(tissueObj);
152 
153  // Setup default haptics manager
154  std::shared_ptr<DeviceManager> hapticManager = DeviceManagerFactory::makeDeviceManager();
155  std::shared_ptr<DeviceClient> deviceClient = hapticManager->makeDeviceClient();
156 
157  // Create and add virtual coupling object controller in the scene
158  auto controller = std::make_shared<LaparoscopicToolController>();
159  controller->setParts(objShaft, objUpperJaw, objLowerJaw, pickGeom);
160  controller->setDevice(deviceClient);
161  controller->setJawAngleChange(1.0);
162  scene->addControl(controller);
163 
164  // Add collision for both jaws of the tool
165  auto upperJawCollision = std::make_shared<PbdObjectCollision>(tissueObj, objUpperJaw);
166  auto lowerJawCollision = std::make_shared<PbdObjectCollision>(tissueObj, objLowerJaw);
167  scene->addInteraction(upperJawCollision);
168  scene->addInteraction(lowerJawCollision);
169 
170  // Add picking interaction for both jaws of the tool
171  auto jawPicking = std::make_shared<PbdObjectGrasping>(tissueObj);
172  scene->addInteraction(jawPicking);
173 
174  // Light
175  auto light = std::make_shared<DirectionalLight>();
176  light->setFocalPoint(Vec3d(0.0, -1.0, -1.0));
177  light->setIntensity(1.0);
178  scene->addLight("light", light);
179 
180  // Run the simulation
181  {
182  // Setup a viewer to render
183  auto viewer = std::make_shared<VTKViewer>();
184  viewer->setActiveScene(scene);
185  viewer->setDebugAxesLength(0.01, 0.01, 0.01);
186 
187  // Setup a scene manager to advance the scene
188  auto sceneManager = std::make_shared<SceneManager>();
189  sceneManager->setActiveScene(scene);
190  sceneManager->pause(); // Start simulation paused
191 
192  auto driver = std::make_shared<SimulationManager>();
193  driver->addModule(hapticManager);
194  driver->addModule(viewer);
195  driver->addModule(sceneManager);
196  driver->setDesiredDt(0.005);
197 
198  // Add default mouse and keyboard controls to the viewer
199  std::shared_ptr<Entity> mouseAndKeyControls =
200  SimulationUtils::createDefaultSceneControl(driver);
201  scene->addSceneObject(mouseAndKeyControls);
202 
203  connect<Event>(sceneManager, &SceneManager::postUpdate,
204  [&](Event*)
205  {
206  // Simulate the cloth in real time
207  tissueObj->getPbdModel()->getConfig()->m_dt = sceneManager->getDt();
208  });
209 
210  connect<Event>(controller, &LaparoscopicToolController::JawClosed,
211  [&](Event*)
212  {
213  LOG(INFO) << "Jaw Closed!";
214 
215  upperJawCollision->setEnabled(false);
216  lowerJawCollision->setEnabled(false);
217  jawPicking->beginCellGrasp(pickGeom, "SurfaceMeshToCapsuleCD");
218  });
219  connect<Event>(controller, &LaparoscopicToolController::JawOpened,
220  [&](Event*)
221  {
222  LOG(INFO) << "Jaw Opened!";
223 
224  upperJawCollision->setEnabled(true);
225  lowerJawCollision->setEnabled(true);
226  jawPicking->endGrasp();
227  });
228 
229  driver->start();
230  }
231 
232  return 0;
233 }
std::shared_ptr< SurfaceMesh > toTriangleGrid(const Vec3d &center, const Vec2d &size, const Vec2i &dim, const Quatd orientation=Quatd::Identity(), const double uvScale=1.0)
Produces a triangle grid on a plane given the imstkPlane.
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 ...
Physically based rendering.
static LoggerG3 & startLogger()
Starts logger with default sinks, use getInstance to create a logger with no sinks.