iMSTK
Interactive Medical Simulation Toolkit
RbdSDFCollisionExample.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 "imstkCompositeImplicitGeometry.h"
9 #include "imstkDirectionalLight.h"
10 #include "imstkGeometryUtilities.h"
11 #include "imstkImplicitGeometryToImageData.h"
12 #include "imstkKeyboardDeviceClient.h"
13 #include "imstkKeyboardSceneControl.h"
14 #include "imstkMouseDeviceClient.h"
15 #include "imstkMouseSceneControl.h"
16 #include "imstkOrientedBox.h"
17 #include "imstkPlane.h"
18 #include "imstkRbdConstraint.h"
19 #include "imstkRenderMaterial.h"
20 #include "imstkRigidBodyModel2.h"
21 #include "imstkRigidObject2.h"
22 #include "imstkRigidObjectCollision.h"
23 #include "imstkScene.h"
24 #include "imstkSceneManager.h"
25 #include "imstkSimulationManager.h"
26 #include "imstkSimulationUtils.h"
27 #include "imstkSphere.h"
28 #include "imstkSurfaceMesh.h"
29 #include "imstkSurfaceMeshFlyingEdges.h"
30 #include "imstkSurfaceMeshSubdivide.h"
31 #include "imstkVisualModel.h"
32 #include "imstkVTKViewer.h"
33 
34 using namespace imstk;
35 
41 int
42 main()
43 {
44  // Write log to stdout and file
46 
47  auto scene = std::make_shared<Scene>("RbdSDFCollision");
48  auto cubeObj = std::make_shared<RigidObject2>("Cube");
49  {
50  // This model is shared among interacting rigid bodies
51  auto rbdModel = std::make_shared<RigidBodyModel2>();
52  rbdModel->getConfig()->m_maxNumIterations = 10;
53 
54  // Create the first rbd, plane floor
55  auto planeObj = std::make_shared<CollidingObject>("Plane");
56  {
57  // Subtract the sphere from the plane to make a crater
58  auto planeGeom = std::make_shared<Plane>();
59  planeGeom->setWidth(1.0);
60  auto sphereGeom = std::make_shared<Sphere>();
61  sphereGeom->setRadius(0.625);
62  sphereGeom->setPosition(0.0, 0.4, 0.0);
63  auto compGeom = std::make_shared<CompositeImplicitGeometry>();
64  compGeom->addImplicitGeometry(planeGeom, CompositeImplicitGeometry::GeometryBoolType::Union);
65  compGeom->addImplicitGeometry(sphereGeom, CompositeImplicitGeometry::GeometryBoolType::Difference);
66 
67  // Rasterize the SDF into an image
69  toImage.setInputGeometry(compGeom);
70  Vec6d bounds;
71  bounds[0] = -0.5;
72  bounds[1] = 0.5;
73  bounds[2] = -0.5;
74  bounds[3] = 0.5;
75  bounds[4] = -0.5;
76  bounds[5] = 0.5;
77  toImage.setBounds(bounds);
78  toImage.setDimensions(Vec3i(80, 80, 80));
79  toImage.update();
80 
81  // Extract surface
82  SurfaceMeshFlyingEdges toSurfMesh;
83  toSurfMesh.setInputImage(toImage.getOutputImage());
84  toSurfMesh.update();
85  toSurfMesh.getOutputMesh()->flipNormals();
86 
87  // Create the object
88  planeObj->setVisualGeometry(toSurfMesh.getOutputMesh());
89  planeObj->setCollidingGeometry(compGeom);
90 
91  scene->addSceneObject(planeObj);
92  }
93 
94  // Create surface mesh cube (so we can use pointset for point->implicit collision)
95  {
96  auto cubeGeom = std::make_shared<OrientedBox>(Vec3d::Zero(), Vec3d(0.0375, 0.075, 0.025));
97  std::shared_ptr<SurfaceMesh> surfMesh = GeometryUtils::toSurfaceMesh(cubeGeom);
98 
99  SurfaceMeshSubdivide subdivide;
100  subdivide.setInputMesh(surfMesh);
101  subdivide.setNumberOfSubdivisions(1);
102  subdivide.update();
103 
104  // Create the visual model
105  auto visualModel = std::make_shared<VisualModel>();
106  visualModel->setGeometry(subdivide.getOutputMesh());
107  auto material = std::make_shared<RenderMaterial>();
108  material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
109  material->setLineWidth(2.0);
110  material->setColor(Color::Orange);
111  visualModel->setRenderMaterial(material);
112 
113  // Create the cube rigid object
114  cubeObj->setDynamicalModel(rbdModel);
115  cubeObj->setPhysicsGeometry(subdivide.getOutputMesh());
116  cubeObj->setCollidingGeometry(subdivide.getOutputMesh());
117  cubeObj->addVisualModel(visualModel);
118  cubeObj->getRigidBody()->m_mass = 100.0;
119  cubeObj->getRigidBody()->m_initPos = Vec3d(0.0, 0.2, 0.0);
120  cubeObj->getRigidBody()->m_initOrientation = Quatd(Rotd(0.4, Vec3d(1.0, 0.0, 0.0)));
121  cubeObj->getRigidBody()->m_intertiaTensor = Mat3d::Identity();
122 
123  scene->addSceneObject(cubeObj);
124  }
125 
126  auto rbdInteraction = std::make_shared<RigidObjectCollision>(cubeObj, planeObj, "ImplicitGeometryToPointSetCD");
127  rbdInteraction->setFriction(0.0); // Don't use friction
128  rbdInteraction->setBaumgarteStabilization(0.05);
129  scene->addInteraction(rbdInteraction);
130 
131  // Camera
132  scene->getActiveCamera()->setPosition(0.0, 1.0, 1.0);
133 
134  // Light
135  auto light = std::make_shared<DirectionalLight>();
136  light->setIntensity(1.0);
137  scene->addLight("light", light);
138  }
139 
140  // Run the simulation
141  {
142  // Setup a viewer to render in its own thread
143  auto viewer = std::make_shared<VTKViewer>();
144  viewer->setActiveScene(scene);
145 
146  // Setup a scene manager to advance the scene in its own thread
147  auto sceneManager = std::make_shared<SceneManager>();
148  sceneManager->setActiveScene(scene);
149  sceneManager->pause();
150 
151  auto driver = std::make_shared<SimulationManager>();
152  driver->addModule(viewer);
153  driver->addModule(sceneManager);
154  driver->setDesiredDt(0.001);
155 
156  // Add default mouse and keyboard controls to the viewer
157  std::shared_ptr<Entity> mouseAndKeyControls =
158  SimulationUtils::createDefaultSceneControl(driver);
159  scene->addSceneObject(mouseAndKeyControls);
160 
161  LOG(INFO) << "Cube Controls:";
162  LOG(INFO) << "----------------------------------------------------------------------";
163  LOG(INFO) << " | i - forward movement";
164  LOG(INFO) << " | j - left movement";
165  LOG(INFO) << " | l - right movement";
166  LOG(INFO) << " | k - backwards movement";
167  LOG(INFO) << " | u - rotate left";
168  LOG(INFO) << " | o - rotate right";
169 
170  std::shared_ptr<KeyboardDeviceClient> keyDevice = viewer->getKeyboardDevice();
171 
172  const Vec3d dx = scene->getActiveCamera()->getPosition() - scene->getActiveCamera()->getFocalPoint();
173  const double speed = 200.0;
174  connect<Event>(sceneManager, &SceneManager::postUpdate, [&](Event*)
175  {
176  Vec3d extForce = Vec3d(0.0, 0.0, 0.0);
177  Vec3d extTorque = Vec3d(0.0, 0.0, 0.0);
178  // If w down, move forward
179  if (keyDevice->getButton('i') == KEY_PRESS)
180  {
181  extForce += Vec3d(0.0, 0.0, -1.0) * speed;
182  }
183  if (keyDevice->getButton('k') == KEY_PRESS)
184  {
185  extForce += Vec3d(0.0, 0.0, 1.0) * speed;
186  }
187  if (keyDevice->getButton('j') == KEY_PRESS)
188  {
189  extForce += Vec3d(-1.0, 0.0, 0.0) * speed;
190  }
191  if (keyDevice->getButton('l') == KEY_PRESS)
192  {
193  extForce += Vec3d(1.0, 0.0, 0.0) * speed;
194  }
195  if (keyDevice->getButton('u') == KEY_PRESS)
196  {
197  extTorque += Vec3d(0.0, 1.5, 0.0);
198  }
199  if (keyDevice->getButton('o') == KEY_PRESS)
200  {
201  extTorque += Vec3d(0.0, -1.5, 0.0);
202  }
203  *cubeObj->getRigidBody()->m_force = extForce;
204  *cubeObj->getRigidBody()->m_torque = extTorque;
205  scene->getActiveCamera()->setFocalPoint(cubeObj->getRigidBody()->getPosition());
206  scene->getActiveCamera()->setPosition(cubeObj->getRigidBody()->getPosition() + dx);
207  });
208  connect<Event>(sceneManager, &SceneManager::postUpdate, [&](Event*)
209  {
210  cubeObj->getRigidBodyModel2()->getConfig()->m_dt = sceneManager->getDt();
211  });
212 
213  driver->start();
214  }
215 
216  return 0;
217 }
Base class for events which contain a type, priority, and data priority defaults to 0 and uses a grea...
Compound Geometry.
This filter rasterizes an implicit function to image of specified dimensions and bounds.
void setInputGeometry(std::shared_ptr< ImplicitGeometry > inputGeometry)
Required input, port 0.
This filter extracts a single isocontour from an imstkImageData.
void update()
Do the actual algorithm.
void setInputImage(std::shared_ptr< ImageData > inputImage)
Required input, port 0.
std::shared_ptr< SurfaceMesh > toSurfaceMesh(std::shared_ptr< AnalyticalGeometry > geom)
Produces SurfaceMesh from an analytical geometry.
static LoggerG3 & startLogger()
Starts logger with default sinks, use getInstance to create a logger with no sinks.