7 #include "imstkCamera.h" 8 #include "imstkDeviceManager.h" 9 #include "imstkDeviceManagerFactory.h" 10 #include "imstkDirectionalLight.h" 11 #include "imstkKeyboardDeviceClient.h" 12 #include "imstkMeshIO.h" 13 #include "imstkMouseDeviceClient.h" 14 #include "imstkMouseSceneControl.h" 15 #include "imstkObjectControllerGhost.h" 16 #include "imstkOrientedBox.h" 17 #include "imstkPbdModel.h" 18 #include "imstkPbdModelConfig.h" 19 #include "imstkPbdObject.h" 20 #include "imstkPbdObjectCollision.h" 21 #include "imstkPbdObjectController.h" 22 #include "imstkPlane.h" 23 #include "imstkPointwiseMap.h" 24 #include "imstkRenderMaterial.h" 25 #include "imstkScene.h" 26 #include "imstkSceneManager.h" 27 #include "imstkSimulationManager.h" 28 #include "imstkVisualModel.h" 30 #include "imstkPbdDistanceConstraint.h" 31 #include "imstkPbdRigidObjectGrasping.h" 33 #include "imstkCapsule.h" 35 #ifdef iMSTK_USE_RENDERING_VTK 36 #include "imstkKeyboardSceneControl.h" 37 #include "imstkSimulationUtils.h" 38 #include "imstkVTKViewer.h" 39 #include "imstkVTKRenderer.h" 42 using namespace imstk;
47 std::shared_ptr<PbdObject>
48 makeOrgan(
const std::string& name, std::shared_ptr<PbdModel> model)
53 auto tissueMesh = MeshIO::read<TetrahedralMesh>(
"./stomach.msh");
54 const Vec3d center = tissueMesh->getCenter();
55 tissueMesh->translate(-center, Geometry::TransformType::ApplyToData);
56 tissueMesh->scale(1.0, Geometry::TransformType::ApplyToData);
57 tissueMesh->rotate(Vec3d(0.0, 0.0, 1.0), 30.0 / 180.0 * 3.14, Geometry::TransformType::ApplyToData);
59 const Vec3d shift = { 0.0, 0.01, 0.0 };
60 tissueMesh->translate(shift, Geometry::TransformType::ApplyToData);
62 auto surfMesh = tissueMesh->extractSurfaceMesh();
65 auto material = std::make_shared<RenderMaterial>();
66 material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
67 material->setBackFaceCulling(
false);
68 material->setOpacity(0.5);
71 auto visualModel = std::make_shared<VisualModel>();
72 visualModel->setGeometry(surfMesh);
73 visualModel->setRenderMaterial(material);
76 auto tissueObj = std::make_shared<PbdObject>(name);
77 tissueObj->addVisualModel(visualModel);
79 tissueObj->setPhysicsGeometry(tissueMesh);
80 tissueObj->setCollidingGeometry(surfMesh);
81 tissueObj->setDynamicalModel(model);
83 tissueObj->setPhysicsToCollidingMap(std::make_shared<PointwiseMap>(tissueMesh, surfMesh));
87 tissueObj->getPbdBody()->uniformMassValue = 0.6 / tissueMesh->getNumVertices();
89 model->getConfig()->m_femParams->m_YoungModulus = 108000.0;
90 model->getConfig()->m_femParams->m_PoissonRatio = 0.4;
91 model->getConfig()->enableFemConstraint(PbdFemConstraint::MaterialType::NeoHookean);
92 model->getConfig()->setBodyDamping(tissueObj->getPbdBody()->bodyHandle, 0.01);
96 Vec3d boxPos = { 0.0, 0.0, 0.1 };
97 Vec3d boxSize = { 0.1, 0.1, 0.15 };
100 std::shared_ptr<VecDataArray<double, 3>> vertices = tissueMesh->getVertexPositions();
101 for (
int i = 0; i < tissueMesh->getNumVertices(); i++)
103 const Vec3d& pos = (*vertices)[i];
104 if (pos[0] < boxPos[0] + (boxSize[0] / 2.0) && pos[0] > boxPos[0] - (boxSize[0] / 2.0)
105 && pos[1] < boxPos[1] + (boxSize[1] / 2.0) && pos[1] > boxPos[1] - (boxSize[1] / 2.0)
106 && pos[2] < boxPos[2] + (boxSize[2] / 2.0) && pos[2] > boxPos[2] - (boxSize[2] / 2.0))
108 auto newPt = model->addVirtualParticle(pos, 0, Vec3d::Zero(),
true);
110 PbdParticleId vertex = { tissueObj->getPbdBody()->bodyHandle, i };
111 auto constraint = std::make_shared<PbdDistanceConstraint>();
112 constraint->initConstraint(0, newPt, vertex, 10.0);
114 model->getConstraints()->addConstraint(constraint);
118 LOG(INFO) <<
"Per particle mass: " << tissueObj->getPbdBody()->uniformMassValue;
120 tissueObj->initialize();
125 std::shared_ptr<PbdObject>
126 makeTool(std::shared_ptr<DeviceClient> deviceClient)
129 auto rbdObj = std::make_shared<PbdObject>();
130 auto model = std::make_shared<PbdModel>();
131 model->getConfig()->m_dt = 0.001;
132 model->getConfig()->m_gravity = Vec3d::Zero();
133 rbdObj->setDynamicalModel(model);
134 rbdObj->getPbdBody()->setRigid(
135 Vec3d(0.0, 0.05, 0.0),
138 Mat3d::Identity() * 100000000.0);
140 auto surfMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT
"/Surgical Instruments/Scissors/Metzenbaum Scissors/Metz_Scissors.stl");
141 rbdObj->setCollidingGeometry(surfMesh);
142 rbdObj->setVisualGeometry(surfMesh);
143 rbdObj->setPhysicsGeometry(surfMesh);
145 std::shared_ptr<RenderMaterial> mat = rbdObj->getVisualModel(0)->getRenderMaterial();
147 mat->setRoughness(0.5);
148 mat->setMetalness(1.0);
149 mat->setIsDynamicMesh(
false);
153 controller->setControlledObject(rbdObj);
154 controller->setDevice(deviceClient);
155 controller->setTranslationOffset(Vec3d(0.0, 0.05, 0.0));
156 controller->setLinearKs(50000.0);
157 controller->setAngularKs(1000000000000.0);
158 controller->setTranslationScaling(1.0);
159 controller->setForceScaling(0.005);
160 controller->setSmoothingKernelSize(10);
161 controller->setUseForceSmoothening(
true);
162 controller->setUseCritDamping(
true);
166 controllerGhost->setController(controller);
173 static std::shared_ptr<PbdObject>
174 makeCapsuleToolObj(std::shared_ptr<PbdModel> model, std::shared_ptr<DeviceClient> deviceClient,
double shiftX)
176 double radius = 0.005;
180 auto toolGeometry = std::make_shared<Capsule>();
182 toolGeometry->setRadius(radius);
183 toolGeometry->setLength(length);
184 toolGeometry->setPosition(Vec3d(shiftX, 0.0, 0.0));
185 toolGeometry->setOrientation(Quatd(0.707, 0.707, 0.0, 0.0));
187 LOG(INFO) <<
"Tool Radius = " << radius;
188 LOG(INFO) <<
"Tool mass = " << mass;
190 auto toolObj = std::make_shared<PbdObject>(
"Tool");
193 toolObj->setVisualGeometry(toolGeometry);
194 toolObj->setPhysicsGeometry(toolGeometry);
195 toolObj->setCollidingGeometry(toolGeometry);
196 toolObj->setDynamicalModel(model);
197 toolObj->getPbdBody()->setRigid(
198 Vec3d(0.04, 0.0, 0.0),
201 Mat3d::Identity() * 1.0);
203 toolObj->getVisualModel(0)->getRenderMaterial()->setOpacity(1.0);
207 controller->setControlledObject(toolObj);
208 controller->setDevice(deviceClient);
209 controller->setHapticOffset(Vec3d(0.0, 0.0, -0.1));
210 controller->setTranslationScaling(1.0);
211 controller->setLinearKs(1000.0);
212 controller->setAngularKs(10000.0);
213 controller->setUseCritDamping(
true);
214 controller->setForceScaling(1.0);
215 controller->setSmoothingKernelSize(15);
216 controller->setUseForceSmoothening(
true);
220 controllerGhost->setController(controller);
231 main(
int argc,
char* argv[])
236 std::string arg(argv[1]);
237 std::cout <<
"Device count: " << arg << std::endl;
238 deviceCount = std::min(2, std::max(0, std::stoi(arg)));
246 std::vector<std::string> deviceName = {
"Right Device",
"Left Device" };
247 std::vector<std::shared_ptr<DeviceClient>> deviceClients;
249 auto pbdModel = std::make_shared<PbdModel>();
250 std::shared_ptr<PbdModelConfig> pbdParams = pbdModel->getConfig();
251 pbdParams->m_gravity = Vec3d(0.0, -1.0, 0.0);
252 pbdParams->m_dt = 0.002;
253 pbdParams->m_iterations = 1;
254 pbdParams->m_linearDampingCoeff = 0.03;
256 for (
int i = 0; i < deviceCount; i++)
258 deviceClients.push_back(hapticManager->makeDeviceClient(deviceName[i]));
262 auto scene = std::make_shared<Scene>(
"VirtualCoupling");
263 scene->getActiveCamera()->setPosition(Vec3d(0.0, 0.2, 0.35));
264 scene->getActiveCamera()->setFocalPoint(Vec3d(0.0, 0.0, 0.0));
265 scene->getActiveCamera()->setViewUp(Vec3d(0.0, 1.0, 0.0));
267 std::shared_ptr<CollidingObject> obstacleObjs[] =
269 std::make_shared<CollidingObject>(
"Plane"),
274 auto plane = std::make_shared<Plane>();
275 plane->setWidth(0.4);
276 obstacleObjs[0]->setVisualGeometry(plane);
277 obstacleObjs[0]->setCollidingGeometry(plane);
280 std::shared_ptr<PbdObject> stomach = makeOrgan(
"Stomach", pbdModel);
281 scene->addSceneObject(stomach);
283 for (
auto obj : obstacleObjs)
285 obj->getVisualModel(0)->getRenderMaterial()->setIsDynamicMesh(
false);
286 scene->addSceneObject(obj);
289 std::vector<std::shared_ptr<PbdObject>> toolObjs;
291 for (
int i = 0; i < deviceCount; i++)
294 auto tool = makeCapsuleToolObj(pbdModel, deviceClients[i], 0.1 + ((
double)i / 10.0));
295 scene->addSceneObject(tool);
297 toolObjs.push_back(tool);
311 for (
auto tool : toolObjs)
313 scene->addInteraction(std::make_shared<PbdObjectCollision>(stomach, tool));
317 for (
auto obj : obstacleObjs)
319 scene->addInteraction(std::make_shared<PbdObjectCollision>(stomach, obj));
322 std::vector<std::shared_ptr<PbdObjectGrasping>> grasping;
324 for (
auto tool : toolObjs)
326 auto grasp = std::make_shared<PbdObjectGrasping>(stomach, tool);
327 grasping.push_back(grasp);
328 scene->addInteraction(grasp);
332 auto light = std::make_shared<DirectionalLight>();
333 light->setFocalPoint(Vec3d(5.0, -8.0, -5.0));
334 light->setIntensity(1.0);
335 scene->addLight(
"light0", light);
340 auto sceneManager = std::make_shared<SceneManager>();
341 sceneManager->setActiveScene(scene);
342 sceneManager->setPaused(
true);
344 auto driver = std::make_shared<SimulationManager>();
345 driver->addModule(hapticManager);
346 #ifdef iMSTK_USE_RENDERING_VTK 348 auto viewer = std::make_shared<VTKViewer>();
349 viewer->setActiveScene(scene);
350 viewer->setDebugAxesLength(0.1, 0.1, 0.1);
352 driver->addModule(viewer);
354 driver->addModule(sceneManager);
355 driver->setDesiredDt(0.001);
357 connect<Event>(sceneManager, &SceneManager::preUpdate, [&](
Event*)
359 for (
auto tool : toolObjs)
361 tool->getPbdModel()->getConfig()->m_dt = driver->getDt();
366 connect<ButtonEvent>(deviceClients[0], &DeviceClient::buttonStateChanged,
369 if (e->m_buttonState == BUTTON_PRESSED)
371 if (e->m_button == 1)
374 auto capsule = std::dynamic_pointer_cast<
Capsule>(toolObjs[0]->getCollidingGeometry());
375 auto dilatedCapsule = std::make_shared<Capsule>(*capsule);
376 dilatedCapsule->setRadius(capsule->getRadius() * 1.1);
377 grasping[0]->beginVertexGrasp(std::dynamic_pointer_cast<Capsule>(dilatedCapsule));
380 else if (e->m_buttonState == BUTTON_RELEASED)
382 if (e->m_button == 1)
384 grasping[0]->endGrasp();
390 #ifdef iMSTK_USE_RENDERING_VTK 392 std::shared_ptr<Entity> mouseAndKeyControls =
393 SimulationUtils::createDefaultSceneControl(driver);
394 scene->addSceneObject(mouseAndKeyControls);
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...
static std::shared_ptr< DeviceManager > makeDeviceManager()
Attempts to create a new DeviceManager by whichever is default If multiple haptic managers are built ...
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.