iMSTK
Interactive Medical Simulation Toolkit
imstkVTKTetrahedralMeshRenderDelegate.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 "imstkVTKTetrahedralMeshRenderDelegate.h"
8 #include "imstkTetrahedralMesh.h"
9 #include "imstkVisualModel.h"
10 #include "imstkRenderMaterial.h"
11 #include "imstkGeometryUtilities.h"
12 
13 #include <vtkActor.h>
14 #include <vtkDataSetMapper.h>
15 #include <vtkDoubleArray.h>
16 #include <vtkUnstructuredGrid.h>
17 #include <vtkPointData.h>
18 #include <vtkTransform.h>
19 
20 namespace imstk
21 {
22 VTKTetrahedralMeshRenderDelegate::VTKTetrahedralMeshRenderDelegate() :
23  m_mesh(vtkSmartPointer<vtkUnstructuredGrid>::New()),
24  m_mappedVertexArray(vtkSmartPointer<vtkDoubleArray>::New()),
25  m_cellArray(vtkSmartPointer<vtkCellArray>::New())
26 {
27 }
28 
29 void
30 VTKTetrahedralMeshRenderDelegate::init()
31 {
32  auto geometry = std::dynamic_pointer_cast<TetrahedralMesh>(m_visualModel->getGeometry());
33  CHECK(geometry != nullptr) << "VTKTetrahedralMeshRenderDelegate only works with TetrahedralMesh geometry";
34 
35  // Create vtkUnstructuredGrid vtkPoints
36  m_mappedVertexArray->SetNumberOfComponents(3);
37  auto points = vtkSmartPointer<vtkPoints>::New();
38  points->SetNumberOfPoints(0);
39  points->SetData(m_mappedVertexArray);
40  m_mesh->SetPoints(points);
41 
42  setVertexBuffer(geometry->getVertexPositions());
43 
44  setIndexBuffer(geometry->getCells());
45  m_mesh->SetCells(VTK_TETRA, m_cellArray);
46 
47  // Map vertex scalars if it has them
48  if (geometry->getVertexScalars() != nullptr)
49  {
50  m_mappedVertexScalarArray = GeometryUtils::coupleVtkDataArray(geometry->getVertexScalars());
51  m_mesh->GetPointData()->SetScalars(m_mappedVertexScalarArray);
52  }
53 
54  // When geometry is modified, update data source, mostly for when an entirely new array/buffer was set
55  queueConnect<Event>(geometry, &Geometry::modified,
56  std::static_pointer_cast<VTKTetrahedralMeshRenderDelegate>(shared_from_this()),
58 
59  // Setup the mapper
60  {
61  vtkNew<vtkDataSetMapper> mapper;
62  mapper->SetInputData(m_mesh);
63  vtkNew<vtkActor> actor;
64  actor->SetMapper(mapper);
65  actor->SetUserTransform(m_transform);
66  m_actor = actor;
67  m_mapper = mapper;
68  }
69 
70  update();
72 }
73 
74 void
76 {
77  // Custom handling of events
78  std::shared_ptr<TetrahedralMesh> geom = std::dynamic_pointer_cast<TetrahedralMesh>(m_visualModel->getGeometry());
79  std::shared_ptr<VecDataArray<double, 3>> vertices = geom->getVertexPositions();
80  std::shared_ptr<VecDataArray<int, 4>> indices = geom->getCells();
81 
82  // Only use the most recent event from respective sender
83  std::array<Command, 5> cmds;
84  std::array<bool, 5> contains = { false, false, false, false, false };
85  rforeachEvent([&](Command cmd)
86  {
87  if (cmd.m_event->m_sender == m_visualModel.get() && !contains[0])
88  {
89  cmds[0] = cmd;
90  contains[0] = true;
91  }
92  else if (cmd.m_event->m_sender == m_material.get() && !contains[1])
93  {
94  cmds[1] = cmd;
95  contains[1] = true;
96  }
97  else if (cmd.m_event->m_sender == geom.get() && !contains[2])
98  {
99  cmds[2] = cmd;
100  contains[2] = true;
101  }
102  else if (cmd.m_event->m_sender == vertices.get() && !contains[3])
103  {
104  cmds[3] = cmd;
105  contains[3] = true;
106  }
107  else if (cmd.m_event->m_sender == indices.get() && !contains[4])
108  {
109  cmds[4] = cmd;
110  contains[4] = true;
111  }
112  });
113 
114  cmds[0].invoke();
115  cmds[1].invoke();
116  cmds[3].invoke();
117  cmds[4].invoke();
118  cmds[2].invoke(); // Process geometry changes last
119 }
120 
121 void
123 {
124  auto geometry = std::static_pointer_cast<TetrahedralMesh>(m_visualModel->getGeometry());
125  setVertexBuffer(geometry->getVertexPositions());
126 }
127 
128 void
129 VTKTetrahedralMeshRenderDelegate::indexDataModified(Event* imstkNotUsed(e))
130 {
131  auto geometry = std::static_pointer_cast<TetrahedralMesh>(m_visualModel->getGeometry());
132  setIndexBuffer(geometry->getCells());
133 }
134 
135 void
137 {
138  auto geometry = std::static_pointer_cast<TetrahedralMesh>(m_visualModel->getGeometry());
139 
140  // If the vertices were reallocated
141  if (m_vertices != geometry->getVertexPositions())
142  {
143  setVertexBuffer(geometry->getVertexPositions());
144  }
145 
146  // Assume vertices are always changed
147  m_mappedVertexArray->Modified();
148 
149  // Only update index buffer when reallocated
150  if (m_indices != geometry->getCells())
151  {
152  setIndexBuffer(geometry->getCells());
153  }
154 }
155 
156 void
157 VTKTetrahedralMeshRenderDelegate::setVertexBuffer(std::shared_ptr<VecDataArray<double, 3>> vertices)
158 {
159  // If the buffer changed
160  if (m_vertices != vertices)
161  {
162  // If previous buffer exist
163  if (m_vertices != nullptr)
164  {
165  // stop observing its changes
166  disconnect(m_vertices,
167  std::static_pointer_cast<VTKTetrahedralMeshRenderDelegate>(shared_from_this()),
169  }
170  // Set new buffer and observe
171  m_vertices = vertices;
172  queueConnect<Event>(m_vertices, &VecDataArray<double, 3>::modified,
173  std::static_pointer_cast<VTKTetrahedralMeshRenderDelegate>(shared_from_this()),
175  }
176 
177  // Couple the buffer
178  m_mappedVertexArray->SetNumberOfComponents(3);
179  m_mappedVertexArray->SetArray(reinterpret_cast<double*>(m_vertices->getPointer()), m_vertices->size() * 3, 1);
180  m_mappedVertexArray->Modified();
181  m_mesh->GetPoints()->SetNumberOfPoints(m_vertices->size());
182 }
183 
184 void
185 VTKTetrahedralMeshRenderDelegate::setIndexBuffer(std::shared_ptr<VecDataArray<int, 4>> indices)
186 {
187  // If the buffer changed
188  if (m_indices != indices)
189  {
190  // If previous buffer exist
191  if (m_indices != nullptr)
192  {
193  // stop observing its changes
194  disconnect(m_indices,
195  std::static_pointer_cast<VTKTetrahedralMeshRenderDelegate>(shared_from_this()),
197  }
198  // Set new buffer and observe
199  m_indices = indices;
200  queueConnect<Event>(m_indices, &VecDataArray<int, 4>::modified,
201  std::static_pointer_cast<VTKTetrahedralMeshRenderDelegate>(shared_from_this()),
202  &VTKTetrahedralMeshRenderDelegate::indexDataModified);
203  }
204 
205  // Copy the buffer
206  m_cellArray->Reset();
207  vtkIdType cell[4];
208  for (const auto& t : *m_indices)
209  {
210  for (size_t i = 0; i < 4; i++)
211  {
212  cell[i] = t[i];
213  }
214  m_cellArray->InsertNextCell(4, cell);
215  }
216  m_mesh->SetCells(VTK_TETRA, m_cellArray);
217  m_cellArray->Modified();
218  m_mesh->Modified();
219 }
220 } // namespace imstk
void rforeachEvent(std::function< void(Command cmd)> func)
thread safe reverse loop over all event commands, one can implement a custom handler ...
void update()
Update render delegate.
friend void disconnect(std::shared_ptr< EventObject >, std::shared_ptr< EventObject >, std::string(*)())
Remove an observer from the sender.
vtkSmartPointer< vtkDataArray > coupleVtkDataArray(std::shared_ptr< AbstractDataArray > imstkArray)
Coupling functions, these create vtk data objects that point to our data objects thus no copying is d...
std::shared_ptr< VisualModel > m_visualModel
imstk visual model (contains data (geometry) and render specification (render material)) ...
vtkSmartPointer< vtkDataArray > m_mappedVertexArray
Mapped array of vertices.
Base class for events which contain a type, priority, and data priority defaults to 0 and uses a grea...
Compound Geometry.
void processEvents() override
Process handling of messages recieved.
Represents a set of tetrahedrons & vertices via an array of Vec3d double vertices & Vec4i integer ind...
void geometryModified(Event *e)
Callback for when geometry is modified.
std::shared_ptr< VecDataArray< double, 3 > > getVertexPositions(DataType type=DataType::PostTransform) const
Returns the vector of current positions of the mesh vertices.
void updateRenderProperties() override
Updates the actor and mapper properties from the currently set VisualModel.
void vertexDataModified(Event *e)
Callback for when vertex values are modified.
Delegates rendering of TetrahedralMesh to VTK from VisualModel.
Stores everything needed to invoke an event A call may not be present, in which case invoke doesn&#39;t d...