iMSTK
Interactive Medical Simulation Toolkit
PBDThinTissueCutExample.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 "imstkDeviceManager.h"
9 #include "imstkDeviceManagerFactory.h"
10 #include "imstkDirectionalLight.h"
11 #include "imstkGeometryUtilities.h"
12 #include "imstkKeyboardDeviceClient.h"
13 #include "imstkKeyboardSceneControl.h"
14 #include "imstkMouseDeviceClient.h"
15 #include "imstkMouseSceneControl.h"
16 #include "imstkPbdModel.h"
17 #include "imstkPbdModelConfig.h"
18 #include "imstkPbdObject.h"
19 #include "imstkPbdObjectCollision.h"
20 #include "imstkPbdObjectController.h"
21 #include "imstkPbdObjectCutting.h"
22 #include "imstkRenderMaterial.h"
23 #include "imstkScene.h"
24 #include "imstkSceneManager.h"
25 #include "imstkSceneObjectController.h"
26 #include "imstkSimulationManager.h"
27 #include "imstkSimulationUtils.h"
28 #include "imstkVertexLabelVisualModel.h"
29 #include "imstkVTKViewer.h"
30 
31 using namespace imstk;
32 
36 static std::shared_ptr<PbdObject>
37 makeTissueObj(const std::string& name,
38  const double width,
39  const double height,
40  const int nRows,
41  const int nCols,
42  std::shared_ptr<PbdModel> model)
43 {
44  // Setup the Geometry
45  std::shared_ptr<SurfaceMesh> clothMesh =
46  GeometryUtils::toTriangleGrid(Vec3d::Zero(),
47  Vec2d(width, height), Vec2i(nRows, nCols));
48  clothMesh->translate(Vec3d(0.0, height * 0.5, width * 0.5),
49  Geometry::TransformType::ApplyToData);
50 
51  // Setup the VisualModel
52  auto material = std::make_shared<RenderMaterial>();
53  material->setBackFaceCulling(false);
54  material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
55 
56  auto visualModel = std::make_shared<VisualModel>();
57  visualModel->setGeometry(clothMesh);
58  visualModel->setRenderMaterial(material);
59 
60  auto vertexLabelModel = std::make_shared<VertexLabelVisualModel>();
61  vertexLabelModel->setGeometry(clothMesh);
62  vertexLabelModel->setFontSize(20.0);
63  vertexLabelModel->setTextColor(Color::Red);
64 
65  // Setup the Object
66  auto tissueObj = std::make_shared<PbdObject>();
67  tissueObj->addVisualModel(visualModel);
68  tissueObj->addVisualModel(vertexLabelModel);
69  tissueObj->setPhysicsGeometry(clothMesh);
70  tissueObj->setCollidingGeometry(clothMesh);
71  tissueObj->setDynamicalModel(model);
72  tissueObj->getPbdBody()->fixedNodeIds = { 0, nCols - 1 };
73  tissueObj->getPbdBody()->uniformMassValue = 0.01;
74 
75  model->getConfig()->enableConstraint(PbdModelConfig::ConstraintGenType::Distance,
76  1e4, tissueObj->getPbdBody()->bodyHandle);
77  model->getConfig()->enableConstraint(PbdModelConfig::ConstraintGenType::Dihedral,
78  0.1, tissueObj->getPbdBody()->bodyHandle);
79 
80  return tissueObj;
81 }
82 
83 static std::shared_ptr<PbdObject>
84 makeToolObj(std::shared_ptr<PbdModel> model)
85 {
86  // Create a cutting plane object in the scene
87  std::shared_ptr<SurfaceMesh> cutGeom =
88  GeometryUtils::toTriangleGrid(Vec3d::Zero(),
89  Vec2d(0.03, 0.03), Vec2i(2, 2));
90  cutGeom->updatePostTransformData();
91 
92  auto toolObj = std::make_shared<PbdObject>("CuttingObject");
93  toolObj->setVisualGeometry(cutGeom);
94  toolObj->setCollidingGeometry(cutGeom);
95  toolObj->setPhysicsGeometry(cutGeom);
96  toolObj->getVisualModel(0)->getRenderMaterial()->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
97  toolObj->getVisualModel(0)->getRenderMaterial()->setBackFaceCulling(false);
98 
99  toolObj->setDynamicalModel(model);
100  toolObj->getPbdBody()->setRigid(
101  Vec3d(0.0, 0.0, 0.0), // Position
102  1.0, // Mass
103  Quatd::Identity(), // Orientation
104  Mat3d::Identity() * 10000.0); // Inertia
105 
106  auto controller = toolObj->addComponent<PbdObjectController>();
107  controller->setControlledObject(toolObj);
108  controller->setLinearKs(20000.0);
109  controller->setAngularKs(8000000.0);
110  controller->setUseCritDamping(true);
111  controller->setForceScaling(0.025);
112  controller->setSmoothingKernelSize(10);
113  controller->setUseForceSmoothening(true);
114 
115  return toolObj;
116 }
117 
122 int
123 main()
124 {
125  // Setup logger (write to file and stdout)
127 
128  // Scene
129  auto scene = std::make_shared<Scene>("PbdThinTissueCut");
130  scene->getActiveCamera()->setPosition(Vec3d(0.0, 0.1, 0.3));
131  scene->getActiveCamera()->setFocalPoint(Vec3d(0.0, 0.02, 0.05));
132 
133  // Setup the Model
134  auto pbdModel = std::make_shared<PbdModel>();
135  pbdModel->getConfig()->m_doPartitioning = false;
136  pbdModel->getConfig()->m_dt = 0.005; // realtime used in update calls later in main
137  pbdModel->getConfig()->m_iterations = 5;
138  //pbdModel->getConfig()->m_gravity = Vec3d(0.0, -9.8, 0.0);
139  pbdModel->getConfig()->m_gravity = Vec3d(0.0, -7.0, 0.0);
140 
141  std::shared_ptr<PbdObject> toolObj = makeToolObj(pbdModel);
142  scene->addSceneObject(toolObj);
143 
144  // Create a pbd cloth object in the scene
145  std::shared_ptr<PbdObject> tissueObj = makeTissueObj("Tissue",
146  0.1, 0.1, 12, 12,
147  pbdModel);
148  scene->addSceneObject(tissueObj);
149 
150  // Add cutting interaction
151  auto cutting = std::make_shared<PbdObjectCutting>(tissueObj, toolObj);
152  cutting->setEpsilon(0.001);
153  scene->addInteraction(cutting);
154 
155  // Add collision interaction (order matters for MeshtoMesh)
156  // Requires per element collision
157  //scene->addInteraction(std::make_shared<PbdObjectCollision>(toolObj, tissueObj));
158 
159  // Setup default haptics manager
160  std::shared_ptr<DeviceManager> hapticManager = DeviceManagerFactory::makeDeviceManager();
161  std::shared_ptr<DeviceClient> deviceClient = hapticManager->makeDeviceClient();
162  auto controller = toolObj->getComponent<PbdObjectController>();
163  controller->setDevice(deviceClient);
164 
165  // Light
166  auto light = std::make_shared<DirectionalLight>();
167  light->setFocalPoint(Vec3d(5.0, -8.0, -5.0));
168  light->setIntensity(1.0);
169  scene->addLight("light", light);
170 
171  {
172  // Setup a viewer to render
173  auto viewer = std::make_shared<VTKViewer>();
174  viewer->setActiveScene(scene);
175 
176  // Setup a scene manager to advance the scene
177  auto sceneManager = std::make_shared<SceneManager>();
178  sceneManager->setActiveScene(scene);
179  sceneManager->pause(); // Start simulation paused
180 
181  auto driver = std::make_shared<SimulationManager>();
182  driver->addModule(hapticManager);
183  driver->addModule(viewer);
184  driver->addModule(sceneManager);
185  driver->setDesiredDt(0.005);
186 
187  // Add default mouse and keyboard controls to the viewer
188  std::shared_ptr<Entity> mouseAndKeyControls =
189  SimulationUtils::createDefaultSceneControl(driver);
190  scene->addSceneObject(mouseAndKeyControls);
191 
192  // Queue haptic button press to be called after scene thread
193  queueConnect<ButtonEvent>(deviceClient, &DeviceClient::buttonStateChanged, sceneManager,
194  [&](ButtonEvent* e)
195  {
196  // When button 0 is pressed replace the PBD cloth with a cut one
197  if (e->m_button == 0 && e->m_buttonState == BUTTON_PRESSED)
198  {
199  cutting->apply();
200  }
201  });
202  connect<KeyEvent>(viewer->getKeyboardDevice(), &KeyboardDeviceClient::keyPress,
203  [&](KeyEvent* e)
204  {
205  if (e->m_key == 'g')
206  {
207  cutting->apply();
208  }
209  });
210 
211  std::cout << "================================================\n";
212  std::cout << "Haptic button 0 or key 'g' to cut the cloth.\n";
213  std::cout << "================================================\n\n";
214 
215  driver->start();
216  }
217  return 0;
218 }
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.
This class uses the provided device to control the provided rigid object via virtual coupling...
Compound Geometry.
static std::shared_ptr< DeviceManager > makeDeviceManager()
Attempts to create a new DeviceManager by whichever is default If multiple haptic managers are built ...
Provides the information of a key event (press, release, & which key)
static LoggerG3 & startLogger()
Starts logger with default sinks, use getInstance to create a logger with no sinks.