7 #include "imstkCamera.h" 8 #include "imstkDeviceManager.h" 9 #include "imstkDeviceManagerFactory.h" 10 #include "imstkDirectionalLight.h" 11 #include "imstkGeometryUtilities.h" 12 #include "imstkIsometricMap.h" 13 #include "imstkKeyboardDeviceClient.h" 14 #include "imstkKeyboardSceneControl.h" 15 #include "imstkMeshIO.h" 16 #include "imstkMouseDeviceClient.h" 17 #include "imstkMouseSceneControl.h" 18 #include "imstkNeedle.h" 19 #include "imstkPbdModel.h" 20 #include "imstkPbdModelConfig.h" 21 #include "imstkPbdObject.h" 22 #include "imstkPointwiseMap.h" 23 #include "imstkPuncturable.h" 24 #include "imstkRbdConstraint.h" 25 #include "imstkRenderMaterial.h" 26 #include "imstkScene.h" 27 #include "imstkSceneManager.h" 28 #include "imstkSimulationManager.h" 29 #include "imstkSimulationUtils.h" 30 #include "imstkVisualModel.h" 31 #include "imstkVTKViewer.h" 32 #include "imstkNeedleInteraction.h" 33 #include "imstkPbdObjectController.h" 34 #include "imstkLoggerSynchronous.h" 36 #include "imstkObjectControllerGhost.h" 37 #include "imstkCapsule.h" 38 #include "imstkPbdRigidObjectGrasping.h" 40 #include "imstkPbdDistanceConstraint.h" 42 using namespace imstk;
47 std::shared_ptr<PbdObject>
48 createTissue(std::shared_ptr<PbdModel> model)
51 std::shared_ptr<TetrahedralMesh> tetMesh = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT
"Tissues/tissue_hole.vtk");
52 CHECK(tetMesh !=
nullptr) <<
"Could not read mesh from file.";
54 std::shared_ptr<SurfaceMesh> surfMesh = tetMesh->extractSurfaceMesh();
56 const int numVerts = tetMesh->getNumVertices();
58 tetMesh->rotate(Vec3d(0.0, 0.0, 1.0), -PI_2, Geometry::TransformType::ApplyToData);
59 tetMesh->rotate(Vec3d(1.0, 0.0, 0.0), -PI_2 / 1.0, Geometry::TransformType::ApplyToData);
61 surfMesh->rotate(Vec3d(0.0, 0.0, 1.0), -PI_2, Geometry::TransformType::ApplyToData);
62 surfMesh->rotate(Vec3d(1.0, 0.0, 0.0), -PI_2 / 1.0, Geometry::TransformType::ApplyToData);
64 tetMesh->scale(0.02, Geometry::TransformType::ApplyToData);
65 surfMesh->scale(0.02, Geometry::TransformType::ApplyToData);
68 tetMesh->scale(Vec3d(1.0, squish, 1.0), Geometry::TransformType::ApplyToData);
69 surfMesh->scale(Vec3d(1.0, squish, 1.0), Geometry::TransformType::ApplyToData);
71 surfMesh->computeVertexNormals();
72 surfMesh->computeTrianglesNormals();
75 auto pbdObject = std::make_shared<PbdObject>(
"meshHole");
76 pbdObject->setVisualGeometry(surfMesh);
77 pbdObject->getVisualModel(0)->getRenderMaterial()->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);;
78 pbdObject->setPhysicsGeometry(tetMesh);
79 pbdObject->setCollidingGeometry(surfMesh);
80 pbdObject->setPhysicsToCollidingMap(std::make_shared<PointwiseMap>(tetMesh, surfMesh));
81 pbdObject->setDynamicalModel(model);
83 pbdObject->getPbdBody()->uniformMassValue = mass / numVerts;
84 std::cout <<
"Tissue nodal mass = " << mass / numVerts <<
"\n";
88 std::cout <<
"Tissue body index = " << pbdObject->getPbdBody()->bodyHandle <<
"\n";
90 model->getConfig()->m_femParams->m_YoungModulus = 8000.0;
91 model->getConfig()->m_femParams->m_PoissonRatio = 0.2;
92 model->getConfig()->enableFemConstraint(PbdFemConstraint::MaterialType::NeoHookean, pbdObject->getPbdBody()->bodyHandle);
93 model->getConfig()->setBodyDamping(pbdObject->getPbdBody()->bodyHandle, 0.2);
96 std::vector<int> fixedNodes;
97 std::cout <<
"Num Verts = " << numVerts <<
"\n";
98 for (
int i = 0; i < numVerts; i++)
100 const Vec3d& position = tetMesh->getVertexPosition(i);
101 if (std::fabs(0.0281968 - std::fabs(position[0])) <= 1E-4)
103 fixedNodes.push_back(i);
108 const int bodyId = pbdObject->getPbdBody()->bodyHandle;
109 for (
int nodeId = 0; nodeId < fixedNodes.size(); nodeId++)
111 const auto& position = tetMesh->getVertexPositions()->at(fixedNodes[nodeId]);
113 const PbdParticleId& p0 = model->addVirtualParticle(position, 0.0, Vec3d::Zero(),
true);
116 auto boundConstraint = std::make_shared<PbdDistanceConstraint>();
117 double restLength = 0.0;
118 double stiffness = 10.0;
119 boundConstraint->initConstraint(restLength, p0, p1, stiffness);
120 model->getConstraints()->addConstraint(boundConstraint);
129 static std::shared_ptr<PbdObject>
130 makeCapsuleToolObj(std::shared_ptr<PbdModel> model)
132 double radius = 0.002;
136 auto toolGeometry = std::make_shared<Capsule>();
138 toolGeometry->setRadius(radius);
139 toolGeometry->setLength(length);
140 toolGeometry->setPosition(Vec3d(0.0, 0.0, 0.0));
141 toolGeometry->setOrientation(Quatd(0.707, 0.707, 0.0, 0.0));
143 LOG(INFO) <<
"Tool Radius = " << radius;
144 LOG(INFO) <<
"Tool mass = " << mass;
146 auto toolObj = std::make_shared<PbdObject>(
"Tool");
149 toolObj->setVisualGeometry(toolGeometry);
150 toolObj->setPhysicsGeometry(toolGeometry);
151 toolObj->setCollidingGeometry(toolGeometry);
152 toolObj->setDynamicalModel(model);
153 toolObj->getPbdBody()->setRigid(
154 Vec3d(0.04, 0.0, 0.0),
157 Mat3d::Identity() * 1.0);
159 toolObj->getVisualModel(0)->getRenderMaterial()->setOpacity(1.0);
163 controller->setControlledObject(toolObj);
164 controller->setHapticOffset(Vec3d(0.0, 0.0, -0.1));
165 controller->setTranslationScaling(1.0);
166 controller->setLinearKs(50.0);
167 controller->setAngularKs(1000.0);
168 controller->setUseCritDamping(
true);
169 controller->setForceScaling(1.0);
170 controller->setSmoothingKernelSize(15);
171 controller->setUseForceSmoothening(
true);
175 controllerGhost->setController(controller);
180 static std::shared_ptr<CollidingObject>
181 makeCollidingCapsule()
183 double radius = 0.009;
184 double length = 0.05;
186 auto capsuleGeometry = std::make_shared<Capsule>();
188 capsuleGeometry->setRadius(radius);
189 capsuleGeometry->setLength(length);
190 capsuleGeometry->setPosition(Vec3d(0.0, 0.0, -0.02));
191 capsuleGeometry->setOrientation(Quatd(0.0, 0.0, 0.0, 0.0));
193 auto capsuleObject = std::make_shared<CollidingObject>(
"Esophagus");
195 capsuleObject->setCollidingGeometry(capsuleGeometry);
196 capsuleObject->setVisualGeometry(capsuleGeometry);
198 return capsuleObject;
204 static std::shared_ptr<PbdObject>
206 const std::string& name,
207 const Vec3d& pos,
const Vec3d& dir,
const int numVerts,
208 const double stringLength,
209 std::shared_ptr<PbdModel> model)
212 std::shared_ptr<LineMesh> stringMesh =
215 double segLength = (stringMesh->getVertexPositions()->at(0) - stringMesh->getVertexPositions()->at(1)).norm();
216 std::cout <<
"Segment length = " << segLength <<
"\n";
217 std::cout <<
"Critical length = " << 0.0016 <<
"\n";
219 const Vec3d shift = Vec3d(0.0, 0.05, 0.0);
220 stringMesh->translate(shift, Geometry::TransformType::ApplyToData);
223 auto material = std::make_shared<RenderMaterial>();
224 material->setBackFaceCulling(
false);
225 material->setColor(Color::Red);
226 material->setLineWidth(2.0);
227 material->setPointSize(3.0);
228 material->setDisplayMode(RenderMaterial::DisplayMode::Wireframe);
230 auto visualModel = std::make_shared<VisualModel>();
231 visualModel->setGeometry(stringMesh);
232 visualModel->setRenderMaterial(material);
235 auto stringObj = std::make_shared<PbdObject>(name);
236 stringObj->addVisualModel(visualModel);
237 stringObj->setPhysicsGeometry(stringMesh);
238 stringObj->setCollidingGeometry(stringMesh);
239 stringObj->setDynamicalModel(model);
241 stringObj->getPbdBody()->uniformMassValue = 0.00125;
242 model->getConfig()->enableConstraint(PbdModelConfig::ConstraintGenType::Distance, 1E12, stringObj->getPbdBody()->bodyHandle);
243 model->getConfig()->enableBendConstraint(100, 1,
true, stringObj->getPbdBody()->bodyHandle);
244 model->getConfig()->setBodyDamping(stringObj->getPbdBody()->bodyHandle, 0.05);
255 static std::shared_ptr<PbdObject>
256 makeNeedleObj(std::shared_ptr<PbdModel> model)
258 auto needleObj = std::make_shared<PbdObject>();
259 auto sutureMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT
"/Surgical Instruments/Needles/c6_suture.stl");
260 auto sutureLineMesh = MeshIO::read<LineMesh>(iMSTK_DATA_ROOT
"/Surgical Instruments/Needles/c6_suture_hull.vtk");
262 const Mat4d rot = mat4dRotation(Rotd(-PI_2, Vec3d(0.0, 1.0, 0.0))) *
263 mat4dRotation(Rotd(-0.6, Vec3d(1.0, 0.0, 0.0)));
265 const Vec3d center = sutureLineMesh->getCenter();
266 sutureMesh->translate(-center, Geometry::TransformType::ApplyToData);
267 sutureLineMesh->translate(-center, Geometry::TransformType::ApplyToData);
269 const Vec3d shift = Vec3d(0.0, 0.05, -0.1);
271 sutureMesh->transform(rot, Geometry::TransformType::ApplyToData);
272 sutureMesh->translate(shift, Geometry::TransformType::ApplyToData);
274 sutureLineMesh->transform(rot, Geometry::TransformType::ApplyToData);
275 sutureLineMesh->translate(shift, Geometry::TransformType::ApplyToData);
277 needleObj->setVisualGeometry(sutureMesh);
279 needleObj->setCollidingGeometry(sutureLineMesh);
280 needleObj->setPhysicsGeometry(sutureLineMesh);
281 needleObj->setPhysicsToVisualMap(std::make_shared<IsometricMap>(sutureLineMesh, sutureMesh));
283 needleObj->getVisualModel(0)->getRenderMaterial()->setColor(
Color(0.9, 0.9, 0.9));
285 needleObj->getVisualModel(0)->getRenderMaterial()->setRoughness(0.5);
286 needleObj->getVisualModel(0)->getRenderMaterial()->setMetalness(1.0);
288 needleObj->setDynamicalModel(model);
289 needleObj->getPbdBody()->setRigid(Vec3d(0, 0, 0.1), 0.1, Quatd::Identity(), Mat3d::Identity() * 0.00012);
293 needleObj->addComponent<
Needle>();
309 auto scene = std::make_shared<Scene>(
"DynamicSuture");
311 scene->getActiveCamera()->setPosition(0.001, 0.1, 0.145);
312 scene->getActiveCamera()->setFocalPoint(0.000, 0.025, 0.035);
313 scene->getActiveCamera()->setViewUp(0.0, 0.83, -0.55);
315 auto light = std::make_shared<DirectionalLight>();
316 light->setFocalPoint(Vec3d(5.0, -8.0, -5.0));
317 light->setIntensity(1.0);
318 scene->addLight(
"Light", light);
321 auto pbdModel = std::make_shared<PbdModel>();
322 auto pbdParams = std::make_shared<PbdModelConfig>();
323 pbdParams->m_doPartitioning =
false;
324 pbdParams->m_gravity = Vec3d(0.0, 0.0, 0.0);
325 pbdParams->m_dt = 0.001;
326 pbdParams->m_iterations = 5;
327 pbdParams->m_doPartitioning =
false;
328 pbdModel->configure(pbdParams);
331 std::shared_ptr<PbdObject> tissueHole = createTissue(pbdModel);
332 scene->addSceneObject(tissueHole);
335 auto esophagus = makeCollidingCapsule();
336 scene->addSceneObject(esophagus);
339 std::shared_ptr<PbdObject> needleObj = makeNeedleObj(pbdModel);
340 scene->addSceneObject(needleObj);
343 const double stringLength = 0.15;
344 const int stringVertexCount = 65;
345 std::shared_ptr<PbdObject> sutureThreadObj =
346 makePbdString(
"SutureThread", Vec3d(0.0, 0.0, 0.018), Vec3d(0.0, 0.0, 1.0),
347 stringVertexCount, stringLength, pbdModel);
348 scene->addSceneObject(sutureThreadObj);
351 std::shared_ptr<PbdObject> toolObj = makeCapsuleToolObj(pbdModel);
352 scene->addSceneObject(toolObj);
355 auto needleGrasp = std::make_shared<PbdObjectGrasping>(needleObj, toolObj);
356 needleGrasp->setStiffness(0.3);
357 scene->addInteraction(needleGrasp);
359 auto threadGrasp = std::make_shared<PbdObjectGrasping>(sutureThreadObj, toolObj);
360 threadGrasp->setStiffness(0.3);
361 scene->addInteraction(threadGrasp);
364 auto pbdToolCollision = std::make_shared<PbdObjectCollision>(tissueHole, toolObj);
365 pbdToolCollision->setRigidBodyCompliance(0.0001);
366 pbdToolCollision->setUseCorrectVelocity(
true);
367 scene->addInteraction(pbdToolCollision);
370 auto esophagusTissueCollision = std::make_shared<PbdObjectCollision>(tissueHole, esophagus);
371 esophagusTissueCollision->setRigidBodyCompliance(0.0001);
372 esophagusTissueCollision->setUseCorrectVelocity(
true);
373 scene->addInteraction(esophagusTissueCollision);
375 auto esophagusToolCollision = std::make_shared<PbdObjectCollision>(toolObj, esophagus);
376 esophagusToolCollision->setRigidBodyCompliance(0.0001);
377 esophagusToolCollision->setUseCorrectVelocity(
true);
378 scene->addInteraction(esophagusToolCollision);
381 auto sutureInteraction = std::make_shared<NeedleInteraction>(tissueHole, needleObj, sutureThreadObj);
382 scene->addInteraction(sutureInteraction);
385 auto interactionCCDThread = std::make_shared<PbdObjectCollision>(sutureThreadObj, sutureThreadObj);
387 interactionCCDThread->setDeformableStiffnessA(0.1);
388 interactionCCDThread->setDeformableStiffnessB(0.1);
389 scene->addInteraction(interactionCCDThread);
393 auto viewer = std::make_shared<VTKViewer>();
394 viewer->setActiveScene(scene);
395 viewer->setDebugAxesLength(0.01, 0.01, 0.01);
398 auto sceneManager = std::make_shared<SceneManager>();
399 sceneManager->setActiveScene(scene);
400 sceneManager->pause();
403 auto driver = std::make_shared<SimulationManager>();
404 driver->addModule(viewer);
405 driver->addModule(sceneManager);
406 driver->setDesiredDt(0.005);
408 #ifdef iMSTK_USE_HAPTICS 411 std::shared_ptr<DeviceClient> deviceClient = hapticManager->makeDeviceClient();
412 driver->addModule(hapticManager);
415 controller->setDevice(deviceClient);
417 connect<ButtonEvent>(deviceClient, &DeviceClient::buttonStateChanged,
420 if (e->m_buttonState == BUTTON_PRESSED)
422 if (e->m_button == 1)
425 auto capsule = std::dynamic_pointer_cast<
Capsule>(toolObj->getCollidingGeometry());
426 auto dilatedCapsule = std::make_shared<Capsule>(*capsule);
427 dilatedCapsule->setRadius(capsule->getRadius() * 1.1);
428 needleGrasp->beginCellGrasp(dilatedCapsule);
429 threadGrasp->beginCellGrasp(dilatedCapsule);
431 std::cout <<
"Grasp\n";
434 else if (e->m_buttonState == BUTTON_RELEASED)
436 if (e->m_button == 1)
438 needleGrasp->endGrasp();
439 threadGrasp->endGrasp();
445 auto deviceClient = std::make_shared<DummyClient>();
446 connect<Event>(sceneManager, &SceneManager::postUpdate,
449 const Vec2d mousePos = viewer->getMouseDevice()->getPos();
450 const Vec3d worldPos = Vec3d(mousePos[0] - 0.5, mousePos[1] - 0.5, 0.0) * 0.1;
452 deviceClient->setPosition(worldPos);
456 connect<Event>(viewer->getMouseDevice(), &MouseDeviceClient::mouseButtonPress,
459 toolPicking->beginVertexGrasp(std::dynamic_pointer_cast<Capsule>(toolObj->getCollidingGeometry()));
460 pbdToolCollision->setEnabled(
false);
462 connect<Event>(viewer->getMouseDevice(), &MouseDeviceClient::mouseButtonRelease,
465 toolPicking->endGrasp();
466 pbdToolCollision->setEnabled(
true);
471 connect<Event>(sceneManager, &SceneManager::preUpdate,
474 sutureThreadObj->getPbdModel()->getConfig()->m_dt = sceneManager->getDt();
478 std::shared_ptr<Entity> mouseAndKeyControls =
479 SimulationUtils::createDefaultSceneControl(driver);
480 scene->addSceneObject(mouseAndKeyControls);
482 connect<KeyEvent>(viewer->getKeyboardDevice(), &KeyboardDeviceClient::keyPress,
488 sutureInteraction->stitch();
void initialize()
Initialize the component, called at a later time after all component construction is complete...
Base class for events which contain a type, priority, and data priority defaults to 0 and uses a grea...
std::pair< int, int > PbdParticleId
Index pair that refers to a particle in a PbdState. Index 0 is the body id, Index 1 is the particle i...
This class uses the provided device to control the provided rigid object via virtual coupling...
Place this on an object to make it puncturable by a needle. This allows puncturables to know they've ...
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.
Base for all needles in imstk it supports global puncture state, per object puncture state...
Provides the information of a key event (press, release, & which key)
A behaviour that renders a second copy of the controlled object at a lower opacity in the physical po...
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.