iMSTK
Interactive Medical Simulation Toolkit
imstkVTKHexahedralMeshRenderDelegate.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 "imstkVTKHexahedralMeshRenderDelegate.h"
8 #include "imstkHexahedralMesh.h"
9 #include "imstkVisualModel.h"
10 #include "imstkGeometryUtilities.h"
11 #include "imstkRenderMaterial.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 VTKHexahedralMeshRenderDelegate::VTKHexahedralMeshRenderDelegate() :
23  m_mesh(vtkSmartPointer<vtkUnstructuredGrid>::New()),
24  m_mappedVertexArray(vtkSmartPointer<vtkDoubleArray>::New())
25 {
26 }
27 
28 void
29 VTKHexahedralMeshRenderDelegate::init()
30 {
31  auto geometry = std::dynamic_pointer_cast<HexahedralMesh>(m_visualModel->getGeometry());
32  CHECK(geometry != nullptr) << "VTKHexahedralMeshRenderDelegate only works with HexahedralMesh geometry";
33  m_vertices = geometry->getVertexPositions();
34  m_indices = geometry->getCells();
35 
36  // Map vertices
37  {
38  m_mappedVertexArray = vtkDoubleArray::SafeDownCast(GeometryUtils::coupleVtkDataArray(m_vertices));
39  auto points = vtkSmartPointer<vtkPoints>::New();
40  points->SetNumberOfPoints(geometry->getNumVertices());
41  points->SetData(m_mappedVertexArray);
42  m_mesh->SetPoints(points);
43  }
44 
45  // Map vertex scalars if it has them
46  if (geometry->getVertexScalars() != nullptr)
47  {
48  m_mappedVertexScalarArray = GeometryUtils::coupleVtkDataArray(geometry->getVertexScalars());
49  m_mesh->GetPointData()->SetScalars(m_mappedVertexScalarArray);
50  }
51 
52  // Map indices to VTK cell data (copied, not coupled)
53  {
54  m_cellArray = vtkSmartPointer<vtkCellArray>::New();
55  vtkIdType cell[8];
56  for (const auto& t : *m_indices)
57  {
58  for (size_t i = 0; i < 8; ++i)
59  {
60  cell[i] = t[i];
61  }
62  m_cellArray->InsertNextCell(8, cell);
63  }
64  m_mesh->SetCells(VTK_HEXAHEDRON, m_cellArray);
65  }
66 
67  // When geometry is modified, update data source, mostly for when an entirely new array/buffer was set
68  queueConnect<Event>(geometry, &Geometry::modified,
69  std::static_pointer_cast<VTKHexahedralMeshRenderDelegate>(shared_from_this()),
70  &VTKHexahedralMeshRenderDelegate::geometryModified);
71 
72  // When the vertex buffer internals are modified, ie: a single or N elements
73  queueConnect<Event>(geometry->getVertexPositions(), &VecDataArray<double, 3>::modified,
74  std::static_pointer_cast<VTKHexahedralMeshRenderDelegate>(shared_from_this()),
75  &VTKHexahedralMeshRenderDelegate::vertexDataModified);
76 
77  // Setup mapper
78  {
79  vtkNew<vtkDataSetMapper> mapper;
80  mapper->SetInputData(m_mesh);
81  vtkNew<vtkActor> actor;
82  actor->SetMapper(mapper);
83  actor->SetUserTransform(m_transform);
84  m_actor = actor;
85  m_mapper = mapper;
86  }
87 
88  update();
90 }
91 
92 void
94 {
95  // Custom handling of events
96  std::shared_ptr<HexahedralMesh> geom = std::dynamic_pointer_cast<HexahedralMesh>(m_visualModel->getGeometry());
97  std::shared_ptr<VecDataArray<double, 3>> vertices = geom->getVertexPositions();
98 
99  // Only use the most recent event from respective sender
100  std::list<Command> cmds;
101  bool contains[4] = { false, false, false, false };
102  rforeachEvent([&](Command cmd)
103  {
104  if (cmd.m_event->m_sender == m_visualModel.get() && !contains[0])
105  {
106  cmds.push_back(cmd);
107  contains[0] = true;
108  }
109  else if (cmd.m_event->m_sender == m_material.get() && !contains[1])
110  {
111  cmds.push_back(cmd);
112  contains[1] = true;
113  }
114  else if (cmd.m_event->m_sender == geom.get() && !contains[2])
115  {
116  cmds.push_back(cmd);
117  contains[2] = true;
118  }
119  else if (cmd.m_event->m_sender == vertices.get() && !contains[3])
120  {
121  cmds.push_back(cmd);
122  contains[3] = true;
123  }
124  });
125 
126  // Now do each event in order recieved
127  for (std::list<Command>::reverse_iterator i = cmds.rbegin(); i != cmds.rend(); i++)
128  {
129  i->invoke();
130  }
131 }
132 
133 void
134 VTKHexahedralMeshRenderDelegate::geometryModified(Event* imstkNotUsed(e))
135 {
136  auto geometry = std::static_pointer_cast<HexahedralMesh>(m_visualModel->getGeometry());
137 
138  // Test if the vertex buffer changed
139  if (m_vertices != geometry->getVertexPositions())
140  {
141  //printf("Vertex data swapped\n");
142  m_vertices = geometry->getVertexPositions();
143  {
144  // Update the pointer of the coupled array
145  m_mappedVertexArray->SetNumberOfComponents(3);
146  m_mappedVertexArray->SetArray(reinterpret_cast<double*>(m_vertices->getPointer()), m_vertices->size() * 3, 1);
147  }
148  }
149  m_mappedVertexArray->Modified();
150 
151  // Test if the index buffer changed
152  if (m_indices != geometry->getCells())
153  {
154  //printf("Index data swapped\n");
155  m_indices = geometry->getCells();
156  {
157  // Copy cells
158  m_cellArray->Reset();
159  vtkIdType cell[8];
160  for (const auto& t : *m_indices)
161  {
162  for (size_t i = 0; i < 8; ++i)
163  {
164  cell[i] = t[i];
165  }
166  m_cellArray->InsertNextCell(8, cell);
167  }
168  m_mesh->SetCells(VTK_TETRA, m_cellArray);
169  m_cellArray->Modified();
170  }
171  }
172 }
173 
174 void
175 VTKHexahedralMeshRenderDelegate::vertexDataModified(Event* imstkNotUsed(e))
176 {
177  auto geometry = std::static_pointer_cast<HexahedralMesh>(m_visualModel->getGeometry());
178  m_vertices = geometry->getVertexPositions();
179  if (m_vertices->getVoidPointer() != m_mappedVertexArray->GetVoidPointer(0))
180  {
181  m_mappedVertexArray->SetNumberOfComponents(3);
182  m_mappedVertexArray->SetArray(reinterpret_cast<double*>(m_vertices->getPointer()), m_vertices->size() * 3, 1);
183  }
184  m_mappedVertexArray->Modified();
185 }
186 } // 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.
Hexahedral mesh class.
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)) ...
Base class for events which contain a type, priority, and data priority defaults to 0 and uses a grea...
Compound Geometry.
vtkSmartPointer< vtkDoubleArray > m_mappedVertexArray
Mapped array of vertices.
void updateRenderProperties() override
Updates the actor and mapper properties from the currently set VisualModel.
std::shared_ptr< VecDataArray< double, 3 > > getVertexPositions(DataType type=DataType::PostTransform) const
Returns the vector of current positions of the mesh vertices.
Stores everything needed to invoke an event A call may not be present, in which case invoke doesn&#39;t d...