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 "imstkIsometricMap.h" 14 #include "imstkMeshIO.h" 15 #include "imstkPbdContactConstraint.h" 16 #include "imstkPbdModel.h" 17 #include "imstkPbdModelConfig.h" 18 #include "imstkPbdObject.h" 19 #include "imstkPbdObjectCollision.h" 20 #include "imstkPbdObjectController.h" 21 #include "imstkPbdObjectGrasping.h" 22 #include "imstkPlane.h" 23 #include "imstkPortHoleInteraction.h" 24 #include "imstkRenderMaterial.h" 25 #include "imstkScene.h" 26 #include "imstkSceneControlText.h" 27 #include "imstkSceneManager.h" 28 #include "imstkSimulationManager.h" 29 #include "imstkSimulationUtils.h" 30 #include "imstkSphere.h" 31 #include "imstkVisualModel.h" 32 #include "imstkVTKViewer.h" 34 using namespace imstk;
38 #ifndef USE_TWO_HAPTIC_DEVICES 39 #include "imstkDummyClient.h" 40 #include "imstkMouseDeviceClient.h" 42 #include "imstkDeviceClient.h" 48 std::shared_ptr<PbdObject>
49 makeLapToolObj(
const std::string& name,
50 std::shared_ptr<PbdModel> model)
52 auto lapTool = std::make_shared<PbdObject>(name);
54 const double capsuleLength = 0.3;
55 auto toolGeom = std::make_shared<Capsule>(
56 Vec3d(0.0, 0.0, capsuleLength * 0.5 - 0.005),
59 Quatd(Rotd(PI_2, Vec3d(1.0, 0.0, 0.0))));
61 const double lapToolHeadLength = 0.01;
62 auto graspCapsule = std::make_shared<Capsule>(
63 Vec3d(0.0, 0.0, lapToolHeadLength * 0.5),
66 Quatd::FromTwoVectors(Vec3d(0.0, 1.0, 0.0), Vec3d(0.0, 0.0, 1.0)));
68 auto lapToolVisualGeom = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT
"/Surgical Instruments/LapTool/laptool_all_in_one.obj");
70 lapTool->setDynamicalModel(model);
71 lapTool->setPhysicsGeometry(toolGeom);
72 lapTool->setCollidingGeometry(toolGeom);
73 lapTool->setVisualGeometry(lapToolVisualGeom);
74 lapTool->setPhysicsToVisualMap(std::make_shared<IsometricMap>(toolGeom, lapToolVisualGeom));
77 auto graspVisualModel = std::make_shared<VisualModel>();
78 graspVisualModel->setGeometry(graspCapsule);
79 graspVisualModel->getRenderMaterial()->setIsDynamicMesh(
false);
80 graspVisualModel->setIsVisible(
false);
81 lapTool->addVisualModel(graspVisualModel);
83 std::shared_ptr<RenderMaterial> material = lapTool->getVisualModel(0)->getRenderMaterial();
84 material->setIsDynamicMesh(
false);
85 material->setMetalness(1.0);
86 material->setRoughness(0.2);
89 lapTool->getPbdBody()->setRigid(
90 Vec3d(0.0, 0.0, capsuleLength * 0.5) + Vec3d(0.0, 0.1, -1.0),
93 Mat3d::Identity() * 0.08);
96 controller->setControlledObject(lapTool);
97 controller->setLinearKs(10000.0);
98 controller->setAngularKs(10.0);
99 controller->setForceScaling(0.01);
100 controller->setSmoothingKernelSize(15);
101 controller->setUseForceSmoothening(
true);
110 controller->setHapticOffset(Vec3d(0.0, 0.0, capsuleLength));
114 auto graspCapsuleMap = std::make_shared<IsometricMap>(toolGeom, graspCapsule);
115 auto graspCapsuleUpdate = lapTool->addComponent<
LambdaBehaviour>(
"graspCapsuleUpdate");
116 graspCapsuleUpdate->setUpdate([ = ](
const double&)
118 graspCapsuleMap->update();
127 static std::shared_ptr<PbdObject>
129 const std::string& name,
130 const Vec3d& pos,
const Vec3d& dir,
const int numVerts,
131 const double stringLength,
132 std::shared_ptr<PbdObject> needleObj)
134 auto stringObj = std::make_shared<PbdObject>(name);
137 std::shared_ptr<LineMesh> stringMesh =
141 auto material = std::make_shared<RenderMaterial>();
142 material->setBackFaceCulling(
false);
143 material->setColor(Color::Red);
144 material->setLineWidth(2.0);
145 material->setPointSize(6.0);
146 material->setDisplayMode(RenderMaterial::DisplayMode::Wireframe);
149 stringObj->setVisualGeometry(stringMesh);
150 stringObj->getVisualModel(0)->setRenderMaterial(material);
151 stringObj->setPhysicsGeometry(stringMesh);
152 stringObj->setCollidingGeometry(stringMesh);
153 std::shared_ptr<PbdModel> model = needleObj->getPbdModel();
154 stringObj->setDynamicalModel(model);
156 stringObj->getPbdBody()->uniformMassValue = 0.02;
158 const int bodyHandle = stringObj->getPbdBody()->bodyHandle;
159 model->getConfig()->enableConstraint(PbdModelConfig::ConstraintGenType::Distance, 1000.0,
163 model->getConfig()->enableBendConstraint(1.0, 1,
true, bodyHandle);
167 auto needleLineMesh = std::dynamic_pointer_cast<
LineMesh>(needleObj->getPhysicsGeometry());
173 const Vec3d endOfNeedle = (*needleLineMesh->getVertexPositions())[0];
174 auto attachmentConstraint = std::make_shared<PbdBodyToBodyDistanceConstraint>();
175 attachmentConstraint->initConstraint(model->getBodies(),
176 { needleObj->getPbdBody()->bodyHandle, 0 },
178 { stringObj->getPbdBody()->bodyHandle, 0 },
198 auto scene = std::make_shared<Scene>(
"PbdLapToolSuturing");
199 scene->getActiveCamera()->setFocalPoint(0.00100544, 0.0779848, -1.20601);
200 scene->getActiveCamera()->setPosition(-0.000866941, 0.0832288, -1.20377);
201 scene->getActiveCamera()->setViewUp(0.0601552, 0.409407, -0.910367);
203 auto model = std::make_shared<PbdModel>();
204 model->getConfig()->m_gravity = Vec3d::Zero();
205 model->getConfig()->m_dt = 0.001;
206 model->getConfig()->m_doPartitioning =
false;
208 auto bodyObject = std::make_shared<CollidingObject>(
"body");
210 auto surfMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT
"/human/full_body/body.obj");
211 auto bodyPlane = std::make_shared<Plane>(Vec3d(0.0, -0.04, -1.0), Vec3d(0.0, 1.0, 0.0));
212 bodyObject->setCollidingGeometry(bodyPlane);
213 bodyObject->setVisualGeometry(surfMesh);
214 bodyObject->getVisualModel(0)->getRenderMaterial()->setShadingModel(
216 std::shared_ptr<RenderMaterial> material =
217 bodyObject->getVisualModel(0)->getRenderMaterial();
218 material->setRoughness(0.8);
219 material->setMetalness(0.1);
220 material->setOpacity(0.5);
222 scene->addSceneObject(bodyObject);
224 std::shared_ptr<PbdObject> leftToolObj = makeLapToolObj(
"leftLapTool", model);
225 scene->addSceneObject(leftToolObj);
226 std::shared_ptr<PbdObject> rightToolObj = makeLapToolObj(
"rightLapTool", model);
227 scene->addSceneObject(rightToolObj);
230 auto needleObj = std::make_shared<PbdObject>();
232 auto needleMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT
"/Surgical Instruments/Needles/c6_suture.stl");
233 auto needleLineMesh = MeshIO::read<LineMesh>(iMSTK_DATA_ROOT
"/Surgical Instruments/Needles/c6_suture_hull.vtk");
235 needleMesh->translate(Vec3d(0.0, -0.0047, -0.0087), Geometry::TransformType::ApplyToData);
236 needleLineMesh->translate(Vec3d(0.0, -0.0047, -0.0087), Geometry::TransformType::ApplyToData);
237 needleObj->setVisualGeometry(needleMesh);
238 needleObj->setCollidingGeometry(needleLineMesh);
239 needleObj->setPhysicsGeometry(needleLineMesh);
240 needleObj->setPhysicsToVisualMap(std::make_shared<IsometricMap>(needleLineMesh, needleMesh));
241 needleObj->setDynamicalModel(model);
242 needleObj->getPbdBody()->setRigid(
243 Vec3d(0.02, 0.0, -1.26),
246 Mat3d::Identity() * 0.01);
247 needleObj->getVisualModel(0)->getRenderMaterial()->setColor(Color::Orange);
249 scene->addSceneObject(needleObj);
252 auto sutureThreadObj = makePbdString(
"sutureThread",
253 Vec3d(0.02, 0.0, -1.26), Vec3d(0.0, 0.0, 1.0), 50, 0.2, needleObj);
254 scene->addSceneObject(sutureThreadObj);
256 auto collision = std::make_shared<PbdObjectCollision>(leftToolObj, rightToolObj);
257 collision->setRigidBodyCompliance(0.00001);
258 scene->addInteraction(collision);
259 auto threadCollision0 = std::make_shared<PbdObjectCollision>(leftToolObj, sutureThreadObj);
260 threadCollision0->setRigidBodyCompliance(0.0001);
261 threadCollision0->setUseCorrectVelocity(
false);
263 scene->addInteraction(threadCollision0);
264 auto threadCollision1 = std::make_shared<PbdObjectCollision>(rightToolObj, sutureThreadObj);
265 threadCollision1->setRigidBodyCompliance(0.0001);
266 threadCollision1->setUseCorrectVelocity(
false);
268 scene->addInteraction(threadCollision1);
270 auto leftNeedleGrasping = std::make_shared<PbdObjectGrasping>(needleObj, leftToolObj);
271 leftNeedleGrasping->setCompliance(0.00001);
272 scene->addInteraction(leftNeedleGrasping);
273 auto leftThreadGrasping = std::make_shared<PbdObjectGrasping>(sutureThreadObj, leftToolObj);
274 leftThreadGrasping->setCompliance(0.00001);
275 scene->addInteraction(leftThreadGrasping);
276 auto rightNeedleGrasping = std::make_shared<PbdObjectGrasping>(needleObj, rightToolObj);
277 rightNeedleGrasping->setCompliance(0.00001);
278 scene->addInteraction(rightNeedleGrasping);
279 auto rightThreadGrasping = std::make_shared<PbdObjectGrasping>(sutureThreadObj, rightToolObj);
280 rightThreadGrasping->setCompliance(0.00001);
281 scene->addInteraction(rightThreadGrasping);
284 auto threadOnThreadCollision = std::make_shared<PbdObjectCollision>(sutureThreadObj, sutureThreadObj);
285 threadOnThreadCollision->setDeformableStiffnessA(0.05);
286 threadOnThreadCollision->setDeformableStiffnessB(0.05);
287 scene->addInteraction(threadOnThreadCollision);
290 auto mousePlane = std::make_shared<Plane>(Vec3d(0.03, 0.1, -0.95), Vec3d(0.1, 0.0, 1.0));
291 mousePlane->setWidth(0.3);
294 auto light = std::make_shared<DirectionalLight>();
295 light->setIntensity(1.0);
296 scene->addLight(
"light", light);
300 #ifdef USE_TWO_HAPTIC_DEVICES 301 std::shared_ptr<DeviceClient> leftDeviceClient = hapticManager->makeDeviceClient(
"Default Device");
303 leftController->setDevice(leftDeviceClient);
304 leftController->setTranslationOffset(Vec3d(0.0, 0.1, -1.0));
306 std::shared_ptr<DeviceClient> rightDeviceClient = hapticManager->makeDeviceClient(
"Device2");
308 rightController->setDevice(rightDeviceClient);
309 rightController->setTranslationOffset(Vec3d(0.0, 0.1, -1.0));
311 connect<ButtonEvent>(rightDeviceClient, &DeviceClient::buttonStateChanged,
314 if (e->m_button == 1)
316 if (e->m_buttonState == BUTTON_PRESSED)
319 auto graspCapsule = std::dynamic_pointer_cast<
Capsule>(
320 rightToolObj->getVisualModel(1)->getGeometry());
321 rightNeedleGrasping->beginCellGrasp(graspCapsule);
322 rightThreadGrasping->beginCellGrasp(graspCapsule);
324 else if (e->m_buttonState == BUTTON_RELEASED)
326 rightNeedleGrasping->endGrasp();
327 rightThreadGrasping->endGrasp();
332 std::shared_ptr<DeviceClient> leftDeviceClient = hapticManager->makeDeviceClient();
334 leftController->setDevice(leftDeviceClient);
335 leftController->setTranslationOffset(Vec3d(0.0, 0.1, -1.0));
337 auto rightDeviceClient = std::make_shared<DummyClient>();
339 rightController->setDevice(rightDeviceClient);
341 connect<ButtonEvent>(leftDeviceClient, &DeviceClient::buttonStateChanged,
344 if (e->m_button == 1)
346 if (e->m_buttonState == BUTTON_PRESSED)
348 auto graspCapsule = std::dynamic_pointer_cast<
Capsule>(
349 leftToolObj->getVisualModel(1)->getGeometry());
350 leftNeedleGrasping->beginCellGrasp(graspCapsule);
351 leftThreadGrasping->beginCellGrasp(graspCapsule);
353 else if (e->m_buttonState == BUTTON_RELEASED)
355 leftNeedleGrasping->endGrasp();
356 leftThreadGrasping->endGrasp();
363 portHoleInteraction->setTool(rightToolObj);
364 portHoleInteraction->setPortHoleLocation(Vec3d(0.015, 0.092, -1.117));
365 auto sphere = std::make_shared<Sphere>(Vec3d(0.015, 0.092, -1.117), 0.01);
366 auto rightPortVisuals = rightToolObj->addComponent<
VisualModel>();
367 rightPortVisuals->setGeometry(sphere);
368 portHoleInteraction->setToolGeometry(rightToolObj->getCollidingGeometry());
369 portHoleInteraction->setCompliance(0.000001);
372 portHoleInteraction2->setTool(leftToolObj);
373 portHoleInteraction2->setPortHoleLocation(Vec3d(-0.065, 0.078, -1.127));
374 auto sphere2 = std::make_shared<Sphere>(Vec3d(-0.065, 0.078, -1.127), 0.01);
375 auto leftPortVisuals = leftToolObj->addComponent<
VisualModel>();
376 leftPortVisuals->setGeometry(sphere2);
377 portHoleInteraction2->setToolGeometry(leftToolObj->getCollidingGeometry());
378 portHoleInteraction2->setCompliance(0.000001);
383 auto viewer = std::make_shared<VTKViewer>();
384 viewer->setActiveScene(scene);
385 viewer->setDebugAxesLength(0.01, 0.01, 0.01);
388 auto sceneManager = std::make_shared<SceneManager>();
389 sceneManager->setActiveScene(scene);
390 sceneManager->pause();
392 auto driver = std::make_shared<SimulationManager>();
393 driver->addModule(viewer);
394 driver->addModule(sceneManager);
395 driver->addModule(hapticManager);
396 driver->setDesiredDt(0.001);
397 connect<Event>(driver, &SimulationManager::starting,
400 sceneManager->setMode(SceneManager::Mode::Debug);
401 viewer->setRenderingMode(Renderer::Mode::Debug);
405 std::shared_ptr<Entity> mouseAndKeyControls =
406 SimulationUtils::createDefaultSceneControl(driver);
407 auto instructText = mouseAndKeyControls->getComponent<
TextVisualModel>();
408 instructText->
setText(instructText->getText() +
409 "\nPress D to Switch to Laprascopic View" 410 "\nPress Haptic Device Button to Grasp");
411 scene->addSceneObject(mouseAndKeyControls);
413 #ifndef USE_TWO_HAPTIC_DEVICES 415 double dummyOffset = -0.07;
416 connect<Event>(sceneManager, &SceneManager::postUpdate,
419 std::shared_ptr<MouseDeviceClient> mouseDeviceClient = viewer->getMouseDevice();
420 const Vec2d& mousePos = mouseDeviceClient->getPos();
426 Vec3d a = Vec3d(0.0, 1.0, 0.0);
427 Vec3d b = a.cross(mousePlane->getNormal()).normalized();
428 a = b.cross(mousePlane->getNormal());
429 const double width = mousePlane->getWidth();
430 rightDeviceClient->setPosition(mousePlane->getPosition() +
431 a * width * (mousePos[1] - 0.5) +
432 b * width * (mousePos[0] - 0.5) +
433 geom->getOrientation().toRotationMatrix().col(1).normalized() *
436 connect<MouseEvent>(viewer->getMouseDevice(), &MouseDeviceClient::mouseScroll,
439 dummyOffset += e->m_scrollDx * 0.01;
441 connect<MouseEvent>(viewer->getMouseDevice(), &MouseDeviceClient::mouseButtonPress,
444 auto graspCapsule = std::dynamic_pointer_cast<
Capsule>(
445 rightToolObj->getVisualModel(1)->getGeometry());
446 rightNeedleGrasping->beginCellGrasp(graspCapsule);
447 rightThreadGrasping->beginCellGrasp(graspCapsule);
449 connect<MouseEvent>(viewer->getMouseDevice(), &MouseDeviceClient::mouseButtonRelease,
452 rightNeedleGrasping->endGrasp();
453 rightThreadGrasping->endGrasp();
456 connect<Event>(sceneManager, &SceneManager::preUpdate,
459 model->getConfig()->m_dt = sceneManager->getDt();
Base class for any analytical geometrical representation.
Container for pbd constraints.
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...
static std::shared_ptr< DeviceManager > makeDeviceManager()
Attempts to create a new DeviceManager by whichever is default If multiple haptic managers are built ...
std::shared_ptr< LineMesh > toLineGrid(const Vec3d &start, const Vec3d &dir, const double length, const int dim)
Creates a set of connected lines.
void setText(const std::string &text)
Text to be plotted.
Base class for all volume mesh types.
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...
A SceneBehaviour that can update via a lambda function.
virtual void addConstraint(std::shared_ptr< PbdConstraint > constraint)
Adds a constraint to the system, thread safe.
Renders text to the screen.
Physically based rendering.
Capsule geometry, default configuration is centered at origin with length running up and down the y a...
static LoggerG3 & startLogger()
Starts logger with default sinks, use getInstance to create a logger with no sinks.
Contains geometric, material, and render information.