iMSTK
Interactive Medical Simulation Toolkit
RbdLapToolCollisionExample.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 "imstkDummyClient.h"
13 #include "imstkIsometricMap.h"
14 #include "imstkKeyboardDeviceClient.h"
15 #include "imstkKeyboardSceneControl.h"
16 #include "imstkMeshIO.h"
17 #include "imstkMouseDeviceClient.h"
18 #include "imstkMouseSceneControl.h"
19 #include "imstkObjectControllerGhost.h"
20 #include "imstkPbdModel.h"
21 #include "imstkPbdModelConfig.h"
22 #include "imstkPbdObject.h"
23 #include "imstkPbdObjectCollision.h"
24 #include "imstkPbdObjectController.h"
25 #include "imstkPlane.h"
26 #include "imstkPortHoleInteraction.h"
27 #include "imstkRbdConstraint.h"
28 #include "imstkRenderMaterial.h"
29 #include "imstkScene.h"
30 #include "imstkSceneManager.h"
31 #include "imstkSimulationManager.h"
32 #include "imstkSimulationUtils.h"
33 #include "imstkSphere.h"
34 #include "imstkSurfaceMesh.h"
35 #include "imstkVisualModel.h"
36 #include "imstkVTKViewer.h"
37 
38 using namespace imstk;
39 
40 //#define USE_TWO_HAPTIC_DEVICES
41 
42 std::shared_ptr<PbdObject>
43 makeLapToolObj(const std::string& name,
44  std::shared_ptr<PbdModel> model)
45 {
46  auto lapTool = std::make_shared<PbdObject>(name);
47 
48  const double capsuleLength = 0.3;
49  auto toolGeom = std::make_shared<Capsule>(Vec3d(0.0, 0.0, capsuleLength * 0.5 - 0.005),
50  0.002,
51  capsuleLength,
52  Quatd(Rotd(PI_2, Vec3d(1.0, 0.0, 0.0))));
53 
54  auto lapToolVisualGeom = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/Surgical Instruments/LapTool/laptool_all_in_one.obj");
55 
56  lapTool->setDynamicalModel(model);
57  lapTool->setPhysicsGeometry(toolGeom);
58  lapTool->setCollidingGeometry(toolGeom);
59  lapTool->setVisualGeometry(lapToolVisualGeom);
60  lapTool->setPhysicsToVisualMap(std::make_shared<IsometricMap>(toolGeom, lapToolVisualGeom));
61 
62  std::shared_ptr<RenderMaterial> material = lapTool->getVisualModel(0)->getRenderMaterial();
63  material->setIsDynamicMesh(false);
64  material->setMetalness(1.0);
65  material->setRoughness(0.2);
66  material->setShadingModel(RenderMaterial::ShadingModel::PBR);
67 
68  lapTool->getPbdBody()->setRigid(
69  Vec3d(0.0, 0.0, capsuleLength * 0.5) + Vec3d(0.0, 0.1, -1.0),
70  10.0,
71  Quatd::Identity(),
72  Mat3d::Identity() * 0.08);
73 
74  auto controller = lapTool->addComponent<PbdObjectController>();
75  controller->setControlledObject(lapTool);
76  controller->setLinearKs(10000.0);
77  controller->setAngularKs(10.0);
78  controller->setForceScaling(0.01);
79  controller->setSmoothingKernelSize(15);
80  controller->setUseForceSmoothening(true);
81 
82  // The center of mass of the object is at the tip this allows most force applied
83  // to the tool at the tip upon touch to be translated into linear force. Suitable
84  // for 3dof devices.
85  //
86  // However, the point at which you actually apply force is on the back of the tool,
87  // this is important for the inversion of control in lap tools (right movement at the
88  // back should move the tip left).
89  controller->setHapticOffset(Vec3d(0.0, 0.0, capsuleLength));
90 
91  return lapTool;
92 }
93 
99 int
100 main()
101 {
102  // Write log to stdout and file
104 
105  auto scene = std::make_shared<Scene>("RbdLapToolCollision");
106 
107  auto bodyObject = std::make_shared<CollidingObject>("body");
108  {
109  auto surfMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/human/full_body/body.obj");
110  auto bodyPlane = std::make_shared<Plane>(Vec3d(0.0, 0.09, -1.0), Vec3d(0.0, 1.0, 0.0));
111  bodyObject->setCollidingGeometry(bodyPlane);
112  bodyObject->setVisualGeometry(surfMesh);
113  bodyObject->getVisualModel(0)->getRenderMaterial()->setShadingModel(
115  std::shared_ptr<RenderMaterial> material =
116  bodyObject->getVisualModel(0)->getRenderMaterial();
117  material->setRoughness(0.8);
118  material->setMetalness(0.1);
119  material->setOpacity(0.5);
120  }
121  scene->addSceneObject(bodyObject);
122 
123  auto model = std::make_shared<PbdModel>();
124  model->getConfig()->m_gravity = Vec3d::Zero();
125  model->getConfig()->m_dt = 0.001;
126  model->getConfig()->m_doPartitioning = false;
127 
128  std::shared_ptr<PbdObject> lapTool1 = makeLapToolObj("lapTool1", model);
129  scene->addSceneObject(lapTool1);
130 
131  std::shared_ptr<PbdObject> lapTool2 = makeLapToolObj("lapTool2", model);
132  scene->addSceneObject(lapTool2);
133 
134  auto collision = std::make_shared<PbdObjectCollision>(lapTool1, lapTool2);
135  collision->setRigidBodyCompliance(0.00001);
136  scene->addInteraction(collision);
137 
138  // Plane with which to move haptic point of tool on
139  auto mousePlane = std::make_shared<Plane>(Vec3d(0.03, 0.1, -0.95), Vec3d(0.1, 0.0, 1.0));
140  mousePlane->setWidth(0.3);
141 
142  // Camera
143  scene->getActiveCamera()->setPosition(-0.039, 0.57, -0.608);
144  scene->getActiveCamera()->setFocalPoint(0.001, 0.178, -1.043);
145  scene->getActiveCamera()->setViewUp(0.018, 0.742, -0.671);
146 
147  // Light
148  auto light = std::make_shared<DirectionalLight>();
149  light->setIntensity(1.0);
150  scene->addLight("light", light);
151 
152  std::shared_ptr<DeviceManager> hapticManager = DeviceManagerFactory::makeDeviceManager();
153 
154 #ifdef USE_TWO_HAPTIC_DEVICES
155  std::shared_ptr<DeviceClient> leftDeviceClient = hapticManager->makeDeviceClient("Default Device");
156  auto leftController = lapTool2->getComponent<PbdObjectController>();
157  leftController->setDevice(leftDeviceClient);
158  leftController->setTranslationOffset(Vec3d(0.0, 0.1, -1.0));
159 
160  std::shared_ptr<DeviceClient> rightDeviceClient = hapticManager->makeDeviceClient("Device2");
161  auto rightController = lapTool1->getComponent<PbdObjectController>();
162  rightController->setDevice(rightDeviceClient);
163  rightController->setTranslationOffset(Vec3d(0.0, 0.1, -1.0));
164 #else
165  std::shared_ptr<DeviceClient> leftDeviceClient = hapticManager->makeDeviceClient(); // Default device
166  auto leftController = lapTool2->getComponent<PbdObjectController>();
167  leftController->setDevice(leftDeviceClient);
168  leftController->setTranslationOffset(Vec3d(0.0, 0.1, -1.0));
169 
170  auto rightDeviceClient = std::make_shared<DummyClient>();
171  auto rightController = lapTool1->getComponent<PbdObjectController>();
172  rightController->setDevice(rightDeviceClient);
173 #endif
174 
175  // Add port holes
176  auto portHoleInteraction = lapTool1->addComponent<PortHoleInteraction>();
177  portHoleInteraction->setTool(lapTool1);
178  portHoleInteraction->setPortHoleLocation(Vec3d(0.015, 0.092, -1.117));
179  auto sphere = std::make_shared<Sphere>(Vec3d(0.015, 0.092, -1.117), 0.01);
180  auto rightPortVisuals = lapTool1->addComponent<VisualModel>();
181  rightPortVisuals->setGeometry(sphere);
182  portHoleInteraction->setToolGeometry(lapTool1->getCollidingGeometry());
183  portHoleInteraction->setCompliance(0.000001);
184 
185  auto portHoleInteraction2 = lapTool2->addComponent<PortHoleInteraction>();
186  portHoleInteraction2->setTool(lapTool2);
187  portHoleInteraction2->setPortHoleLocation(Vec3d(-0.065, 0.078, -1.127));
188  auto sphere2 = std::make_shared<Sphere>(Vec3d(-0.065, 0.078, -1.127), 0.01);
189  auto leftPortVisuals = lapTool2->addComponent<VisualModel>();
190  leftPortVisuals->setGeometry(sphere2);
191  portHoleInteraction2->setToolGeometry(lapTool2->getCollidingGeometry());
192  portHoleInteraction2->setCompliance(0.000001);
193 
194  // Run the simulation
195  {
196  // Setup a viewer to render in its own thread
197  auto viewer = std::make_shared<VTKViewer>();
198  viewer->setActiveScene(scene);
199  viewer->setDebugAxesLength(0.01, 0.01, 0.01);
200 
201  // Setup a scene manager to advance the scene in its own thread
202  auto sceneManager = std::make_shared<SceneManager>();
203  sceneManager->setActiveScene(scene);
204  sceneManager->pause();
205 
206  auto driver = std::make_shared<SimulationManager>();
207  driver->addModule(viewer);
208  driver->addModule(sceneManager);
209  driver->addModule(hapticManager);
210  driver->setDesiredDt(0.001);
211 
212  // Add default mouse and keyboard controls to the viewer
213  std::shared_ptr<Entity> mouseAndKeyControls =
214  SimulationUtils::createDefaultSceneControl(driver);
215  scene->addSceneObject(mouseAndKeyControls);
216 
217 #ifndef USE_TWO_HAPTIC_DEVICES
218  // Process Mouse tool movement & presses
219  double dummyOffset = 0.0;
220  connect<Event>(sceneManager, &SceneManager::postUpdate,
221  [&](Event*)
222  {
223  std::shared_ptr<MouseDeviceClient> mouseDeviceClient = viewer->getMouseDevice();
224  const Vec2d& mousePos = mouseDeviceClient->getPos();
225 
226  auto geom =
227  std::dynamic_pointer_cast<AnalyticalGeometry>(lapTool2->getPhysicsGeometry());
228 
229  // Use plane definition for dummy movement
230  Vec3d a = Vec3d(0.0, 1.0, 0.0);
231  Vec3d b = a.cross(mousePlane->getNormal()).normalized();
232  a = b.cross(mousePlane->getNormal());
233  const double width = mousePlane->getWidth();
234  rightDeviceClient->setPosition(mousePlane->getPosition() +
235  a * width * (mousePos[1] - 0.5) +
236  b * width * (mousePos[0] - 0.5) +
237  geom->getOrientation().toRotationMatrix().col(1).normalized() *
238  dummyOffset);
239  });
240  connect<MouseEvent>(viewer->getMouseDevice(), &MouseDeviceClient::mouseScroll,
241  [&](MouseEvent* e)
242  {
243  dummyOffset += e->m_scrollDx * 0.01;
244  });
245 #endif
246  connect<Event>(sceneManager, &SceneManager::preUpdate,
247  [&](Event*)
248  {
249  model->getConfig()->m_dt = sceneManager->getDt();
250  });
251 
252  driver->start();
253  }
254 
255  return 0;
256 }
Base class for any analytical geometrical representation.
Base class for events which contain a type, priority, and data priority defaults to 0 and uses a grea...
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 ...
Defines the behaviour to constrain a PbdObject LineMesh or Capsule to a fixed port hole location...
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.
Contains geometric, material, and render information.