iMSTK
Interactive Medical Simulation Toolkit
FemurObject.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 "FemurObject.h"
8 #include "imstkLevelSetModel.h"
9 #include "imstkLocalMarchingCubes.h"
10 #include "imstkMeshIO.h"
11 #include "imstkRenderMaterial.h"
12 #include "imstkSurfaceMesh.h"
13 #include "imstkTaskGraph.h"
14 #include "imstkVisualModel.h"
15 
16 FemurObject::FemurObject() : LevelSetDeformableObject("Femur"),
17  m_isoExtract(std::make_shared<LocalMarchingCubes>())
18 {
19  std::shared_ptr<ImageData> initLvlSetImage = MeshIO::read<ImageData>(iMSTK_DATA_ROOT "/legs/femurBoneSolid_SDF.nii")->cast(IMSTK_DOUBLE);
20  //const Vec3d& currSpacing = initLvlSetImage->getSpacing();
21 
22  // Note: Anistropic scaling would invalidate the SDF
23  initLvlSetImage->setOrigin(Vec3d(0.0, 0.8, 1.5));
24 
25  // Setup the Parameters
26  auto lvlSetConfig = std::make_shared<LevelSetModelConfig>();
27  lvlSetConfig->m_sparseUpdate = true;
28  lvlSetConfig->m_substeps = 15;
29 
30  // Too many chunks and you'll hit memory constraints quickly
31  // Too little chunks and the updates for a chunk will take too long
32  // The chunks must divide the image dimensions-1 (image dim-1 must be divisible by # chunks)
33  m_isoExtract->setInputImage(initLvlSetImage);
34  m_isoExtract->setIsoValue(0.0);
35  m_isoExtract->setNumberOfChunks(Vec3i(32, 9, 9));
36  m_isoExtract->update();
37 
38  if (m_useRandomChunkColors)
39  {
40  srand(static_cast<unsigned int>(time(NULL)));
41  }
42 
43  // Setup the Object
44  auto sdf = std::make_shared<SignedDistanceField>(initLvlSetImage);
45 
46  // Setup the Model
47  auto model = std::make_shared<LevelSetModel>();
48  model->setModelGeometry(sdf);
49  model->configure(lvlSetConfig);
50 
51  setPhysicsGeometry(sdf);
52  setCollidingGeometry(sdf);
53  setDynamicalModel(model);
54 
55  // Setup a custom task to forward the modified voxels of the level set model
56  // to the marching cubes before they're cleared
57  m_forwardModifiedVoxels = std::make_shared<TaskNode>(
58  std::bind(&FemurObject::updateModifiedVoxels, this), "Isosurface: SetModifiedVoxels");
59  m_taskGraph->addNode(m_forwardModifiedVoxels);
60 }
61 
62 bool
64 {
65  createVisualModels();
66  return true;
67 }
68 
69 void
71 {
72  // Update any chunks that contain a voxel which was set modified
73  m_isoExtract->update();
74 
75  // Create meshes for chunks if they now contain vertices (and weren't already generated)
76  // You could just create all the chunks, but this saves some memory for internal/empty ones
77  createVisualModels();
78 }
79 
80 void
82 {
83  const Vec3i& numChunks = m_isoExtract->getNumberOfChunks();
84  for (int i = 0; i < numChunks[0] * numChunks[1] * numChunks[2]; i++)
85  {
86  auto surfMesh = std::dynamic_pointer_cast<SurfaceMesh>(m_isoExtract->getOutput(i));
87  if (surfMesh->getNumVertices() > 0 && m_chunksGenerated.count(i) == 0)
88  {
89  auto surfMeshModel = std::make_shared<VisualModel>();
90  surfMeshModel->setGeometry(m_isoExtract->getOutput(i));
91  auto material = std::make_shared<RenderMaterial>();
92  material->setDisplayMode(RenderMaterial::DisplayMode::Surface);
93  material->setLineWidth(4.0);
94  if (m_useRandomChunkColors)
95  {
96  const double r = (rand() % 10000) / 10000.0;
97  const double g = (rand() % 10000) / 10000.0;
98  const double b = (rand() % 10000) / 10000.0;
99  material->setColor(Color(r, g, b));
100  }
101  else
102  {
103  material->setColor(Color::Bone);
104  }
105  //material->setOpacity(0.7);
106  surfMeshModel->setRenderMaterial(material);
107  addVisualModel(surfMeshModel);
108  m_chunksGenerated.insert(i);
109  }
110  }
111 }
112 
113 void
115 {
116  // Forward the level set's modified nodes to the isosurface extraction
117  for (auto i : getLevelSetModel()->getNodesToUpdate())
118  {
119  m_isoExtract->setModified(std::get<0>(i.second));
120  }
121 }
122 
123 void
124 FemurObject::initGraphEdges(std::shared_ptr<TaskNode> source, std::shared_ptr<TaskNode> sink)
125 {
126  // Copy, sum, and connect the model graph to nest within this graph
127  m_taskGraph->addEdge(source, getUpdateNode());
128 
129  m_dynamicalModel->initGraphEdges();
130  m_taskGraph->nestGraph(m_dynamicalModel->getTaskGraph(), getUpdateNode(), getUpdateGeometryNode());
131 
132  // The levelsetmodel produces a list of modified voxels, we forward that to the isosurface extraction
133  // filter to update only the modified chunks
134  m_taskGraph->addEdge(getLevelSetModel()->getGenerateVelocitiesEndNode(), m_forwardModifiedVoxels);
135  m_taskGraph->addEdge(m_forwardModifiedVoxels, getLevelSetModel()->getQuantityEvolveNode(0));
136 
137  m_taskGraph->addEdge(getUpdateGeometryNode(), sink);
138 }
bool initialize() override
Initialize the scene object.
Definition: FemurObject.cpp:63
Base class for scene objects that move and/or deform under position based dynamics formulation...
This filter extracts a contour SurfaceMesh from an image given an isovalue. Users should prefer imstk...
Represents a set of triangles & vertices via an array of Vec3d double vertices & Vec3i integer indice...
Color in RGB space.
Definition: imstkColor.h:24
void updateModifiedVoxels()
Forwards/copies the levelsets list of modified voxels to the isosurface extraction filters list of mo...
void createVisualModels()
Creates visual models for any chunk that has non-zero vertices and is not already generated...
Definition: FemurObject.cpp:81
void visualUpdate() override
Update the isosurface before rendering, the isosurface is not used for simulation so we can afford to...
Definition: FemurObject.cpp:70
void initGraphEdges()
Initializes the edges of the SceneObject&#39;s computational graph.