7 #include "imstkCamera.h" 8 #include "imstkCapsule.h" 9 #include "imstkControllerForceText.h" 10 #include "imstkDirectionalLight.h" 11 #include "imstkGeometryUtilities.h" 12 #include "imstkKeyboardDeviceClient.h" 13 #include "imstkKeyboardSceneControl.h" 14 #include "imstkMouseDeviceClient.h" 15 #include "imstkMouseSceneControl.h" 16 #include "imstkObjectControllerGhost.h" 17 #include "imstkPbdModel.h" 18 #include "imstkPbdModelConfig.h" 19 #include "imstkPbdObject.h" 20 #include "imstkPbdObjectCollision.h" 21 #include "imstkPbdObjectController.h" 22 #include "imstkPbdRigidObjectGrasping.h" 23 #include "imstkPointwiseMap.h" 24 #include "imstkRenderMaterial.h" 25 #include "imstkScene.h" 26 #include "imstkSceneManager.h" 27 #include "imstkSimulationManager.h" 28 #include "imstkSimulationUtils.h" 29 #include "imstkVisualModel.h" 30 #include "imstkVTKViewer.h" 31 #include "imstkMeshIO.h" 33 #include "imstkImageData.h" 35 #ifdef iMSTK_USE_HAPTICS 36 #include "imstkDeviceManager.h" 37 #include "imstkDeviceManagerFactory.h" 39 #include "imstkDummyClient.h" 42 using namespace imstk;
47 std::shared_ptr<PbdObject>
48 makeGallBladder(
const std::string& name, std::shared_ptr<PbdModel> model)
51 auto tissueMesh = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT
"/Organs/Gallblader/gallblader.msh");
52 const Vec3d center = tissueMesh->getCenter();
53 tissueMesh->translate(-center, Geometry::TransformType::ApplyToData);
54 tissueMesh->scale(1.0, Geometry::TransformType::ApplyToData);
55 tissueMesh->rotate(Vec3d(0.0, 0.0, 1.0), 30.0 / 180.0 * 3.14, Geometry::TransformType::ApplyToData);
57 const Vec3d shift = { -0.0, 0.0, 0.0 };
58 tissueMesh->translate(shift, Geometry::TransformType::ApplyToData);
60 auto surfMesh = tissueMesh->extractSurfaceMesh();
63 auto material = std::make_shared<RenderMaterial>();
64 material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
65 material->setBackFaceCulling(
false);
66 material->setOpacity(0.5);
69 auto visualModel = std::make_shared<VisualModel>();
70 visualModel->setGeometry(surfMesh);
71 visualModel->setRenderMaterial(material);
74 auto tissueObj = std::make_shared<PbdObject>(name);
75 tissueObj->addVisualModel(visualModel);
77 tissueObj->setPhysicsGeometry(tissueMesh);
78 tissueObj->setCollidingGeometry(surfMesh);
79 tissueObj->setDynamicalModel(model);
81 tissueObj->setPhysicsToCollidingMap(std::make_shared<PointwiseMap>(tissueMesh, surfMesh));
84 tissueObj->getPbdBody()->uniformMassValue = 0.6 / tissueMesh->getNumVertices();
86 model->getConfig()->m_femParams->m_YoungModulus = 108000.0;
87 model->getConfig()->m_femParams->m_PoissonRatio = 0.4;
88 model->getConfig()->enableFemConstraint(PbdFemConstraint::MaterialType::NeoHookean);
89 model->getConfig()->setBodyDamping(tissueObj->getPbdBody()->bodyHandle, 0.01);
94 std::shared_ptr<VecDataArray<double, 3>> vertices = tissueMesh->getVertexPositions();
95 for (
int i = 0; i < tissueMesh->getNumVertices(); i++)
97 const Vec3d& pos = (*vertices)[i];
100 tissueObj->getPbdBody()->fixedNodeIds.push_back(i);
104 LOG(INFO) <<
"Per particle mass: " << tissueObj->getPbdBody()->uniformMassValue;
106 tissueObj->initialize();
114 static std::shared_ptr<PbdObject>
116 const std::string& name,
117 std::shared_ptr<PbdModel> model,
122 auto prismObj = std::make_shared<PbdObject>(name);
126 std::shared_ptr<SurfaceMesh> surfMesh = prismMesh->extractSurfaceMesh();
129 prismObj->setPhysicsGeometry(prismMesh);
130 prismObj->setCollidingGeometry(surfMesh);
131 prismObj->setVisualGeometry(surfMesh);
132 prismObj->getVisualModel(0)->getRenderMaterial()->setDisplayMode(RenderMaterial::DisplayMode::Wireframe);
133 prismObj->setDynamicalModel(model);
135 prismObj->getPbdBody()->uniformMassValue = 0.003;
137 prismObj->setPhysicsToCollidingMap(std::make_shared<PointwiseMap>(prismMesh, surfMesh));
147 model->getConfig()->m_femParams->m_YoungModulus = 6000.0;
148 model->getConfig()->m_femParams->m_PoissonRatio = 0.4;
149 model->getConfig()->enableFemConstraint(PbdFemConstraint::MaterialType::NeoHookean);
150 model->getConfig()->setBodyDamping(prismObj->getPbdBody()->bodyHandle, 0.001);
152 std::shared_ptr<VecDataArray<int, 3>> indicesPtr = surfMesh->getCells();
154 std::shared_ptr<VecDataArray<double, 3>> verticesPtr = surfMesh->getVertexPositions();
157 double avgArea = 0.0;
158 for (
int i = 0; i < surfMesh->getNumCells(); i++)
160 const Vec3i& cell = indices[i];
161 const Vec3d& p0 = verts[cell[0]];
162 const Vec3d& p1 = verts[cell[1]];
163 const Vec3d& p2 = verts[cell[2]];
164 avgArea += 0.5 * (p1 - p0).cross(p2 - p0).norm();
167 avgArea /= surfMesh->getNumCells();
168 LOG(INFO) <<
"Average Cell Area = " << avgArea;
169 LOG(INFO) <<
"Cell Characteristic Length = " << sqrt(avgArea);
170 LOG(INFO) <<
"Per node mass = " << prismObj->getPbdBody()->uniformMassValue;
173 std::shared_ptr<VecDataArray<double, 3>> vertices = prismMesh->getVertexPositions();
174 for (
int i = 0; i < prismMesh->getNumVertices(); i++)
176 const Vec3d& pos = (*vertices)[i];
177 if (pos[1] <= center[1] - size[1] * 0.5)
179 prismObj->getPbdBody()->fixedNodeIds.push_back(i);
189 static std::shared_ptr<PbdObject>
190 makeTissueObj(
const std::string& name,
191 std::shared_ptr<PbdModel> model,
198 std::shared_ptr<SurfaceMesh> surfMesh =
200 Vec2d(width, height), Vec2i(rowCount, colCount));
203 auto pbdObject = std::make_shared<PbdObject>(name);
205 pbdObject->setVisualGeometry(surfMesh);
206 pbdObject->getVisualModel(0)->getRenderMaterial()->setDisplayMode(RenderMaterial::DisplayMode::Wireframe);
207 pbdObject->setPhysicsGeometry(surfMesh);
208 pbdObject->setCollidingGeometry(surfMesh);
209 pbdObject->setDynamicalModel(model);
210 pbdObject->getPbdBody()->uniformMassValue = 0.003;
211 for (
int x = 0; x < rowCount; x++)
213 for (
int y = 0; y < colCount; y++)
215 if (x == 0 || y == 0 || y == colCount - 1)
217 pbdObject->getPbdBody()->fixedNodeIds.push_back(x * colCount + y);
222 std::shared_ptr<VecDataArray<int, 3>> indicesPtr = surfMesh->getCells();
224 std::shared_ptr<VecDataArray<double, 3>> verticesPtr = surfMesh->getVertexPositions();
227 double avgArea = 0.0;
228 for (
int i = 0; i < surfMesh->getNumCells(); i++)
230 const Vec3i& cell = indices[i];
231 const Vec3d& p0 = vertices[cell[0]];
232 const Vec3d& p1 = vertices[cell[1]];
233 const Vec3d& p2 = vertices[cell[2]];
234 avgArea += 0.5 * (p1 - p0).cross(p2 - p0).norm();
237 avgArea /= surfMesh->getNumCells();
238 LOG(INFO) <<
"Average Cell Area = " << avgArea;
239 LOG(INFO) <<
"Cell Characteristic Length = " << sqrt(avgArea);
240 LOG(INFO) <<
"Per node mass = " << pbdObject->getPbdBody()->uniformMassValue;
248 static std::shared_ptr<PbdObject>
249 makeCapsuleToolObj(std::shared_ptr<PbdModel> model)
251 double radius = 0.005;
255 auto toolGeometry = std::make_shared<Capsule>();
257 toolGeometry->setRadius(radius);
258 toolGeometry->setLength(length);
259 toolGeometry->setPosition(Vec3d(0.0, 0.0, 0.0));
260 toolGeometry->setOrientation(Quatd(0.707, 0.707, 0.0, 0.0));
262 LOG(INFO) <<
"Tool Radius = " << radius;
263 LOG(INFO) <<
"Tool mass = " << mass;
265 auto toolObj = std::make_shared<PbdObject>(
"Tool");
268 toolObj->setVisualGeometry(toolGeometry);
269 toolObj->setPhysicsGeometry(toolGeometry);
270 toolObj->setCollidingGeometry(toolGeometry);
271 toolObj->setDynamicalModel(model);
272 toolObj->getPbdBody()->setRigid(
273 Vec3d(0.04, 0.0, 0.0),
276 Mat3d::Identity() * 1.0);
278 toolObj->getVisualModel(0)->getRenderMaterial()->setOpacity(1.0);
282 controller->setControlledObject(toolObj);
283 controller->setHapticOffset(Vec3d(0.0, 0.0, -0.1));
284 controller->setTranslationScaling(1.0);
285 controller->setLinearKs(1000.0);
286 controller->setAngularKs(10000.0);
287 controller->setUseCritDamping(
true);
288 controller->setForceScaling(1.0);
289 controller->setSmoothingKernelSize(15);
290 controller->setUseForceSmoothening(
true);
294 controllerGhost->setController(controller);
310 auto scene = std::make_shared<Scene>(
"PbdHapticGrasping");
311 scene->getActiveCamera()->setPosition(0.00610397, 0.131126, 0.281497);
312 scene->getActiveCamera()->setFocalPoint(0.0, 0.0, 0.0);
313 scene->getActiveCamera()->setViewUp(0.00251247, 0.90946, -0.415783);
315 auto pbdModel = std::make_shared<PbdModel>();
316 std::shared_ptr<PbdModelConfig> pbdParams = pbdModel->getConfig();
317 pbdParams->m_gravity = Vec3d(0.0, 0.0, 0.0);
318 pbdParams->m_dt = 0.002;
319 pbdParams->m_iterations = 2;
320 pbdParams->m_linearDampingCoeff = 0.03;
328 Vec3d size = Vec3d(0.10, 0.08, 0.10);
329 Vec3i dim = Vec3i(18, 4, 18);
330 Vec3d center = Vec3d(0.0, -0.05, 0.0);
331 std::shared_ptr<PbdObject> pbdObj = makePbdObjCube(
"Cube", pbdModel, size, dim, center);
332 scene->addSceneObject(pbdObj);
339 std::shared_ptr<PbdObject> toolObj = makeCapsuleToolObj(pbdModel);
340 scene->addSceneObject(toolObj);
343 auto pbdToolCollision = std::make_shared<PbdObjectCollision>(pbdObj, toolObj);
344 pbdToolCollision->setRigidBodyCompliance(0.0001);
345 pbdToolCollision->setUseCorrectVelocity(
true);
346 scene->addInteraction(pbdToolCollision);
349 auto toolPicking = std::make_shared<PbdObjectGrasping>(pbdObj, toolObj);
350 toolPicking->setStiffness(0.3);
351 scene->addInteraction(toolPicking);
354 auto light = std::make_shared<DirectionalLight>();
355 light->setFocalPoint(Vec3d(5.0, -8.0, -5.0));
356 light->setIntensity(1.0);
357 scene->addLight(
"Light", light);
362 auto viewer = std::make_shared<VTKViewer>();
363 viewer->setActiveScene(scene);
364 viewer->setVtkLoggerMode(VTKViewer::VTKLoggerMode::MUTE);
365 viewer->setDebugAxesLength(0.01, 0.01, 0.01);
368 auto sceneManager = std::make_shared<SceneManager>();
369 sceneManager->setActiveScene(scene);
370 sceneManager->pause();
372 auto driver = std::make_shared<SimulationManager>();
373 driver->addModule(viewer);
374 driver->addModule(sceneManager);
375 driver->setDesiredDt(0.002);
378 controller->setPosition(Vec3d(0.0, 0.0, 0.0));
380 #ifdef iMSTK_USE_HAPTICS 383 if (hapticManager->getTypeName() ==
"HaplyDeviceManager")
385 controller->setTranslationOffset(Vec3d(2.0, 0.0, -2.0));
387 std::shared_ptr<DeviceClient> deviceClient = hapticManager->makeDeviceClient();
388 driver->addModule(hapticManager);
390 connect<ButtonEvent>(deviceClient, &DeviceClient::buttonStateChanged,
393 if (e->m_buttonState == BUTTON_PRESSED)
395 if (e->m_button == 1)
398 auto capsule = std::dynamic_pointer_cast<
Capsule>(toolObj->getCollidingGeometry());
399 auto dilatedCapsule = std::make_shared<Capsule>(*capsule);
400 dilatedCapsule->setRadius(capsule->getRadius() * 1.1);
401 toolPicking->beginVertexGrasp(dilatedCapsule);
402 pbdToolCollision->setEnabled(
false);
405 else if (e->m_buttonState == BUTTON_RELEASED)
407 if (e->m_button == 1)
409 toolPicking->endGrasp();
410 pbdToolCollision->setEnabled(
true);
415 auto deviceClient = std::make_shared<DummyClient>();
416 connect<Event>(sceneManager, &SceneManager::postUpdate,
419 const Vec2d mousePos = viewer->getMouseDevice()->getPos();
420 const Vec3d worldPos = Vec3d(mousePos[0] - 0.5, mousePos[1] - 0.5, 0.0) * 0.1;
422 deviceClient->setPosition(worldPos);
426 connect<Event>(viewer->getMouseDevice(), &MouseDeviceClient::mouseButtonPress,
429 toolPicking->beginVertexGrasp(std::dynamic_pointer_cast<Capsule>(toolObj->getCollidingGeometry()));
430 pbdToolCollision->setEnabled(
false);
432 connect<Event>(viewer->getMouseDevice(), &MouseDeviceClient::mouseButtonRelease,
435 toolPicking->endGrasp();
436 pbdToolCollision->setEnabled(
true);
441 connect<KeyEvent>(viewer->getKeyboardDevice(), &KeyboardDeviceClient::keyPress,
446 auto capsule = std::dynamic_pointer_cast<
Capsule>(toolObj->getCollidingGeometry());
447 auto dilatedCapsule = std::make_shared<Capsule>(*capsule);
448 dilatedCapsule->setRadius(capsule->getRadius() * 1.1);
449 toolPicking->beginVertexGrasp(dilatedCapsule);
450 pbdToolCollision->setEnabled(
false);
453 connect<KeyEvent>(viewer->getKeyboardDevice(), &KeyboardDeviceClient::keyRelease,
458 toolPicking->endGrasp();
459 pbdToolCollision->setEnabled(
true);
462 controller->setDevice(deviceClient);
465 std::shared_ptr<Entity> mouseAndKeyControls =
466 SimulationUtils::createDefaultSceneControl(driver);
471 controllerForceTxt->setCollision(pbdToolCollision);
473 scene->addSceneObject(mouseAndKeyControls);
475 connect<Event>(sceneManager, &SceneManager::preUpdate, [&](
Event*)
478 pbdModel->getConfig()->m_dt = sceneManager->getDt();
std::shared_ptr< SurfaceMesh > toTriangleGrid(const Vec3d ¢er, const Vec2d &size, const Vec2i &dim, const Quatd orientation=Quatd::Identity(), const double uvScale=1.0)
Produces a triangle grid on a plane given the imstkPlane.
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...
std::shared_ptr< TetrahedralMesh > toTetGrid(const Vec3d ¢er, const Vec3d &size, const Vec3i &divisions, const Quatd orientation=Quatd::Identity())
Produces a tetrahedral grid given the OrientedBox with the given divisions.
static std::shared_ptr< DeviceManager > makeDeviceManager()
Attempts to create a new DeviceManager by whichever is default If multiple haptic managers are built ...
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...
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.
void setController(std::shared_ptr< PbdObjectController > controller)
Get/Set the controller to display the device force of.
Displays virtual coupling force text in the top right.