iMSTK
Interactive Medical Simulation Toolkit
PBDInjectExample.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 "imstkDirectionalLight.h"
9 #include "imstkKeyboardDeviceClient.h"
10 #include "imstkKeyboardSceneControl.h"
11 #include "imstkMouseDeviceClient.h"
12 #include "imstkMouseSceneControl.h"
13 #include "imstkPbdModel.h"
14 #include "imstkPbdModelConfig.h"
15 #include "imstkRbdConstraint.h"
16 #include "imstkRenderMaterial.h"
17 #include "imstkRigidBodyModel2.h"
18 #include "imstkRigidObject2.h"
19 #include "imstkRigidObjectController.h"
20 #include "imstkScene.h"
21 #include "imstkSceneManager.h"
22 #include "imstkSimulationManager.h"
23 #include "imstkSimulationUtils.h"
24 #include "imstkVisualModel.h"
25 #include "imstkVTKViewer.h"
26 #include "InflatableObject.h"
27 
28 #ifdef iMSTK_USE_HAPTICS
29 #define EXAMPLE_USE_HAPTICS
30 #endif
31 
32 #ifdef EXAMPLE_USE_HAPTICS
33 #include "imstkDeviceManager.h"
34 #include "imstkDeviceManagerFactory.h"
35 #else
36 #include "imstkDummyClient.h"
37 #endif
38 
39 using namespace imstk;
40 
41 static std::shared_ptr<RigidObject2>
42 makeToolObj(const std::string& name)
43 {
44  //auto toolGeom = std::make_shared<Sphere>(Vec3d(0.0, 0.0, 0.0), 1.0);
45  auto toolGeom = std::make_shared<LineMesh>();
46  VecDataArray<double, 3> vertices = { Vec3d(0.0, 0.0, 0.0), Vec3d(0.0, 2.0, 0.0) };
47  VecDataArray<int, 2> indices = { Vec2i(0, 1) };
48  toolGeom->initialize(std::make_shared<VecDataArray<double, 3>>(vertices),
49  std::make_shared<VecDataArray<int, 2>>(indices));
50 
51  auto toolObj = std::make_shared<RigidObject2>(name);
52  toolObj->setVisualGeometry(toolGeom);
53  toolObj->setCollidingGeometry(toolGeom);
54  toolObj->setPhysicsGeometry(toolGeom);
55  toolObj->getVisualModel(0)->getRenderMaterial()->setColor(Color::Blue);
56  toolObj->getVisualModel(0)->getRenderMaterial()->setDisplayMode(RenderMaterial::DisplayMode::Wireframe);
57  toolObj->getVisualModel(0)->getRenderMaterial()->setBackFaceCulling(false);
58  toolObj->getVisualModel(0)->getRenderMaterial()->setLineWidth(10.0);
59 
60  auto rbdModel = std::make_shared<RigidBodyModel2>();
61  rbdModel->getConfig()->m_gravity = Vec3d::Zero();
62  rbdModel->getConfig()->m_maxNumIterations = 6;
63  toolObj->setDynamicalModel(rbdModel);
64 
65  toolObj->getRigidBody()->m_mass = 10.0;
66  toolObj->getRigidBody()->m_intertiaTensor = Mat3d::Identity() * 10000.0;
67  toolObj->getRigidBody()->m_initPos = Vec3d(0.0, 0.8, 0.0);
68  toolObj->getRigidBody()->m_isStatic = false;
69 
70  auto controller = toolObj->addComponent<RigidObjectController>();
71  controller->setControlledObject(toolObj);
72  controller->setTranslationScaling(10.0);
73  controller->setLinearKs(20000.0);
74  controller->setAngularKs(10000000.0);
75  controller->setForceScaling(0.0);
76  controller->setSmoothingKernelSize(15);
77  controller->setUseCritDamping(true);
78  controller->setUseForceSmoothening(true);
79 
80  return toolObj;
81 }
82 
83 static void
84 inject(std::shared_ptr<InflatableObject> tissueObj, std::shared_ptr<RigidObject2> toolObj,
85  Vec3d& toolTip, const double radius, const double rate)
86 {
87  // The LineMesh used for collision with the PBD tissue
88  std::shared_ptr<LineMesh> lineMesh = std::dynamic_pointer_cast<LineMesh>(toolObj->getCollidingGeometry());
89  const Vec3d vertex = lineMesh->getVertexPosition(0);
90 
91  if ((toolTip - vertex).norm() > 0.01)
92  {
93  toolTip = vertex;
94  tissueObj->setUpdateAffectedConstraint();
95  }
96 
97  tissueObj->inject(toolTip, radius, rate);
98 }
99 
104 int
105 main()
106 {
107  // Setup logger (write to file and stdout)
109 
110  // Setup the scene
111  auto scene = std::make_shared<Scene>("PbdInjectExample");
112  scene->getActiveCamera()->setPosition(0.12, 4.51, 16.51);
113  scene->getActiveCamera()->setFocalPoint(0.0, 0.0, 0.0);
114  scene->getActiveCamera()->setViewUp(0.0, 0.96, -0.28);
115 
116  // Setup a tissue
117  const Vec3d tissueSize = Vec3d(10.0, 3.0, 10.0);
118  const Vec3i tissueDim = Vec3i(20, 5, 20);
119  const Vec3d tissueCenter = Vec3d(0.1, -1.0, 0.0);
120  const double radius = tissueSize[0] / 5.0;
121  auto tissueObj = std::make_shared<InflatableObject>("PbdTissue",
122  tissueSize, tissueDim, tissueCenter);
123  scene->addSceneObject(tissueObj);
124 
125  // Setup a tool
126  Vec3d toolTip = tissueCenter + Vec3d(0.0, tissueSize[1] / 2.0, 0.0);
127  std::shared_ptr<RigidObject2> toolObj = makeToolObj("RbdTool");
128  scene->addSceneObject(toolObj);
129 
130  // Light
131  auto light = std::make_shared<DirectionalLight>();
132  light->setFocalPoint(Vec3d(5, -8, -5));
133  light->setIntensity(1.0);
134  scene->addLight("light", light);
135 
136  // Run the simulation
137  {
138  // Setup a viewer to render
139  auto viewer = std::make_shared<VTKViewer>();
140  viewer->setActiveScene(scene);
141  viewer->setVtkLoggerMode(VTKViewer::VTKLoggerMode::MUTE);
142  viewer->setDebugAxesLength(0.1, 0.1, 0.1);
143 
144  // Setup a scene manager to advance the scene
145  auto sceneManager = std::make_shared<SceneManager>();
146  sceneManager->setActiveScene(scene);
147  sceneManager->pause(); // Start simulation paused
148 
149  auto driver = std::make_shared<SimulationManager>();
150  driver->addModule(viewer);
151  driver->addModule(sceneManager);
152  driver->setDesiredDt(0.01);
153 
154  // Add default mouse and keyboard controls to the viewer
155  std::shared_ptr<Entity> mouseAndKeyControls =
156  SimulationUtils::createDefaultSceneControl(driver);
157  scene->addSceneObject(mouseAndKeyControls);
158 
159 #ifdef EXAMPLE_USE_HAPTICS
160  // Setup default haptics manager
161  std::shared_ptr<DeviceManager> hapticManager = DeviceManagerFactory::makeDeviceManager();
162  std::shared_ptr<DeviceClient> deviceClient = hapticManager->makeDeviceClient();
163  driver->addModule(hapticManager);
164 
165  connect<Event>(sceneManager, SceneManager::postUpdate, [&](Event*)
166  {
167  if (deviceClient->getButton(0))
168  {
169  inject(tissueObj, toolObj, toolTip, radius, 0.001);
170  }
171  else if (deviceClient->getButton(1))
172  {
173  inject(tissueObj, toolObj, toolTip, radius, -0.001);
174  }
175  });
176 #else
177  auto deviceClient = std::make_shared<DummyClient>();
178  // Use keyboard controls
179  connect<Event>(sceneManager, SceneManager::preUpdate, [&](Event*)
180  {
181  const Vec2d mousePos = viewer->getMouseDevice()->getPos();
182  const Vec3d worldPos = Vec3d(mousePos[0] - 0.5, mousePos[1] - 0.5, 0.0) * 0.5;
183 
184  deviceClient->setPosition(worldPos);
185  });
186 #endif
187  auto controller = toolObj->getComponent<RigidObjectController>();
188  controller->setDevice(deviceClient);
189 
190  // Key controls for injection
191  connect<Event>(sceneManager, SceneManager::preUpdate, [&](Event*)
192  {
193  if (viewer->getKeyboardDevice()->getButton('s') == KEY_PRESS)
194  {
195  inject(tissueObj, toolObj, toolTip, radius, 0.001);
196  }
197  else if (viewer->getKeyboardDevice()->getButton('a') == KEY_PRESS)
198  {
199  inject(tissueObj, toolObj, toolTip, radius, -0.001);
200  }
201  });
202 
203  connect<Event>(sceneManager, &SceneManager::preUpdate, [&](Event*)
204  {
205  // Keep the tool moving in real time
206  toolObj->getRigidBodyModel2()->getConfig()->m_dt = sceneManager->getDt();
207  tissueObj->getPbdModel()->getConfig()->m_dt = sceneManager->getDt();
208  });
209 
210  std::cout << "================================================\n";
211  std::cout << "Key s : injection \n" << "Key a : deflation \n";
212  std::cout << "================================================\n\n";
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 ...
const Vec3d & getVertexPosition(const size_t vertNum, DataType type=DataType::PostTransform) const
Returns the position of a vertex given its index.
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...
static LoggerG3 & startLogger()
Starts logger with default sinks, use getInstance to create a logger with no sinks.