iMSTK
Interactive Medical Simulation Toolkit
FemurCutExample.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 "FemurObject.h"
8 #include "imstkCamera.h"
9 #include "imstkDeviceManager.h"
10 #include "imstkDeviceManagerFactory.h"
11 #include "imstkDirectionalLight.h"
12 #include "imstkKeyboardDeviceClient.h"
13 #include "imstkKeyboardSceneControl.h"
14 #include "imstkLevelSetCH.h"
15 #include "imstkLevelSetModel.h"
16 #include "imstkMeshIO.h"
17 #include "imstkMouseDeviceClient.h"
18 #include "imstkMouseSceneControl.h"
19 #include "imstkObjectControllerGhost.h"
20 #include "imstkRbdConstraint.h"
21 #include "imstkRigidBodyCH.h"
22 #include "imstkRigidBodyModel2.h"
23 #include "imstkRigidObject2.h"
24 #include "imstkRigidObjectController.h"
25 #include "imstkRigidObjectLevelSetCollision.h"
26 #include "imstkScene.h"
27 #include "imstkSceneManager.h"
28 #include "imstkSimulationManager.h"
29 #include "imstkSimulationUtils.h"
30 #include "imstkSurfaceMesh.h"
31 #include "imstkVisualModel.h"
32 #include "imstkVolumeRenderMaterial.h"
33 #include "imstkVTKViewer.h"
34 
35 #ifndef iMSTK_USE_HAPTICS
36 #include "imstkDummyClient.h"
37 #include "imstkMouseDeviceClient.h"
38 #endif
39 
40 using namespace imstk;
41 
42 std::shared_ptr<RigidObject2>
43 makeRigidObj(const std::string& name)
44 {
45  auto rbdModel = std::make_shared<RigidBodyModel2>();
46  rbdModel->getConfig()->m_maxNumIterations = 8;
47  rbdModel->getConfig()->m_velocityDamping = 1.0;
48  rbdModel->getConfig()->m_angularVelocityDamping = 1.0;
49  rbdModel->getConfig()->m_maxNumConstraints = 40;
50  rbdModel->getConfig()->m_gravity = Vec3d::Zero();
51 
52  // Create the first rbd, plane floor
53  auto rigidObj = std::make_shared<RigidObject2>(name);
54 
55  auto toolMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/Surgical Instruments/Scalpel/Scalpel_Hull_Subdivided_Shifted.stl");
56  toolMesh->rotate(Vec3d(0.0, 1.0, 0.0), 3.14, Geometry::TransformType::ApplyToData);
57  toolMesh->rotate(Vec3d(1.0, 0.0, 0.0), -1.57, Geometry::TransformType::ApplyToData);
58  toolMesh->scale(Vec3d(0.07, 0.07, 0.07), Geometry::TransformType::ApplyToData);
59 
60  auto material = std::make_shared<RenderMaterial>();
61  material->setDisplayMode(RenderMaterial::DisplayMode::Surface);
62  material->setShadingModel(RenderMaterial::ShadingModel::PBR);
63  material->setMetalness(0.9);
64  material->setRoughness(0.4);
65  material->setDiffuseColor(Color(0.7, 0.7, 0.7));
66 
67  // Create the object
68  rigidObj->setVisualGeometry(toolMesh);
69  rigidObj->setPhysicsGeometry(toolMesh);
70  rigidObj->setCollidingGeometry(toolMesh);
71  rigidObj->setDynamicalModel(rbdModel);
72  rigidObj->getVisualModel(0)->setRenderMaterial(material);
73  rigidObj->getRigidBody()->m_mass = 10.0;
74  rigidObj->getRigidBody()->m_intertiaTensor = Mat3d::Identity() * 10000.0;
75  rigidObj->getRigidBody()->m_initPos = Vec3d(0.0, 1.0, 2.0);
76 
77  // Add a component for controlling via another device
78  auto controller = rigidObj->addComponent<RigidObjectController>();
79  controller->setControlledObject(rigidObj);
80  controller->setLinearKs(50000.0);
81  controller->setAngularKs(300000000.0);
82  controller->setUseCritDamping(true);
83  controller->setForceScaling(0.005);
84  controller->setTranslationOffset(Vec3d(0.4, 0.7, 1.6));
85  controller->setSmoothingKernelSize(30);
86 
87  // Add extra component to tool for the ghost
88  auto controllerGhost = rigidObj->addComponent<ObjectControllerGhost>();
89  controllerGhost->setUseForceFade(true);
90  controllerGhost->setController(controller);
91 
92  return rigidObj;
93 }
94 
100 int
101 main()
102 {
103  // Setup logger (write to file and stdout)
105 
106  auto scene = std::make_shared<Scene>("FemurCut");
107 
108  // Setup the Femur
109  auto femurObj = std::make_shared<FemurObject>();
110  scene->addSceneObject(femurObj);
111 
112  // Setup the tool that cuts the femur
113  std::shared_ptr<RigidObject2> rbdObj = makeRigidObj("ToolObject");
114  scene->addSceneObject(rbdObj);
115 
116  // Setup cutting interaction between level set femur and rigid object tool
117  auto cutting = std::make_shared<RigidObjectLevelSetCollision>(rbdObj, femurObj);
118  {
119  auto colHandlerA = std::dynamic_pointer_cast<RigidBodyCH>(cutting->getCollisionHandlingA());
120  colHandlerA->setUseFriction(false);
121  colHandlerA->setBaumgarteStabilization(0.05); // inelastic collision
122 
123  auto colHandlerB = std::dynamic_pointer_cast<LevelSetCH>(cutting->getCollisionHandlingB());
124  colHandlerB->setLevelSetVelocityScaling(0.01);
125  colHandlerB->setKernel(3, 1.0);
126  //colHandlerB->setLevelSetVelocityScaling(0.0); // Can't push the levelset
127  colHandlerB->setUseProportionalVelocity(true);
128  }
129  scene->addInteraction(cutting);
130 
131  // Light
132  auto light = std::make_shared<DirectionalLight>();
133  light->setDirection(Vec3d(0.0, -8.0, -5.0));
134  light->setIntensity(1.0);
135  scene->addLight("light", light);
136 
137  // Adjust camera
138  scene->getActiveCamera()->setFocalPoint(0.25, 0.83, 1.58);
139  scene->getActiveCamera()->setPosition(0.243, 1.06, 1.95);
140  scene->getActiveCamera()->setViewUp(0.05, 0.86, -0.51);
141 
142  {
143  auto viewer = std::make_shared<VTKViewer>();
144  viewer->setVtkLoggerMode(VTKViewer::VTKLoggerMode::MUTE);
145  viewer->setActiveScene(scene);
146 
147  // Add a module to run the scene
148  auto sceneManager = std::make_shared<SceneManager>();
149  sceneManager->setActiveScene(scene);
150 
151  auto driver = std::make_shared<SimulationManager>();
152  driver->addModule(viewer);
153  driver->addModule(sceneManager);
154  driver->setDesiredDt(0.001); // Exactly 1000ups
155 
156 #ifdef iMSTK_USE_HAPTICS
157  // Setup default haptics manager
158  std::shared_ptr<DeviceManager> hapticManager = DeviceManagerFactory::makeDeviceManager();
159  driver->addModule(hapticManager);
160  std::shared_ptr<DeviceClient> deviceClient = hapticManager->makeDeviceClient();
161 #else
162  auto deviceClient = std::make_shared<DummyClient>();
163  connect<Event>(sceneManager, &SceneManager::postUpdate, [&](Event*)
164  {
165  const Vec2d mousePos = viewer->getMouseDevice()->getPos();
166  const Vec3d worldPos = Vec3d(mousePos[0] * 0.5 - 0.5, mousePos[1] * 0.2 + 0.1, -0.025);
167  deviceClient->setPosition(worldPos);
168  });
169 #endif
170 
171  auto controller = rbdObj->getComponent<RigidObjectController>();
172  controller->setDevice(deviceClient);
173 
174  std::shared_ptr<ObjectControllerGhost> ghostObj = rbdObj->addComponent<ObjectControllerGhost>();
175  ghostObj->setController(controller);
176 
177  connect<Event>(sceneManager, &SceneManager::preUpdate,
178  [&](Event*)
179  {
180  rbdObj->getRigidBodyModel2()->getConfig()->m_dt = sceneManager->getDt();
181  femurObj->getLevelSetModel()->getConfig()->m_dt = sceneManager->getDt();
182  });
183 
184  // Add default mouse and keyboard controls to the viewer
185  std::shared_ptr<Entity> mouseAndKeyControls =
186  SimulationUtils::createDefaultSceneControl(driver);
187  scene->addSceneObject(mouseAndKeyControls);
188 
189  driver->start();
190  }
191 
192  return 0;
193 }
Applies impulses to the leveset given point direction collision data propotional to the force on the ...
Base class for events which contain a type, priority, and data priority defaults to 0 and uses a grea...
void setUseForceFade(bool useForceFade)
Get/Set whether to use force fade or not. Force fade sets opacity of ghost geometry according to forc...
Compound Geometry.
static std::shared_ptr< DeviceManager > makeDeviceManager()
Attempts to create a new DeviceManager by whichever is default If multiple haptic managers are built ...
This class uses the provided device to control the provided rigid object via virtual coupling...
Color in RGB space.
Definition: imstkColor.h:24
Creates rigid body contact and frictional constraints given collision data then adds them to the rigi...
A behaviour that renders a second copy of the controlled object at a lower opacity in the physical po...
Physically based rendering.
static LoggerG3 & startLogger()
Starts logger with default sinks, use getInstance to create a logger with no sinks.