iMSTK
Interactive Medical Simulation Toolkit
imstkVTKVertexLabelRenderDelegate.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 "imstkVTKVertexLabelRenderDelegate.h"
8 #include "imstkGeometryUtilities.h"
9 #include "imstkPointSet.h"
10 #include "imstkRenderMaterial.h"
11 #include "imstkVertexLabelVisualModel.h"
12 
13 #include <vtkActor2D.h>
14 #include <vtkDoubleArray.h>
15 #include <vtkLabeledDataMapper.h>
16 #include <vtkPolyData.h>
17 #include <vtkTextProperty.h>
18 
19 namespace imstk
20 {
21 VTKVertexLabelRenderDelegate::VTKVertexLabelRenderDelegate() :
22  m_polydata(vtkSmartPointer<vtkPolyData>::New()),
23  m_mappedVertexArray(vtkSmartPointer<vtkDoubleArray>::New())
24 {
25 }
26 
27 void
28 VTKVertexLabelRenderDelegate::init()
29 {
30  auto vertexLabelVisualModel = std::dynamic_pointer_cast<VertexLabelVisualModel>(m_visualModel);
31  m_geometry = std::dynamic_pointer_cast<PointSet>(m_visualModel->getGeometry());
32  CHECK(m_geometry != nullptr) << "VTKVertexLabelRenderDelegate only works with PointSet geometry";
33 
34  // Get our own handles to these in case the geometry changes them
35  m_vertices = m_geometry->getVertexPositions();
36 
37  // Map vertices to VTK point data
38  if (m_vertices != nullptr)
39  {
40  m_mappedVertexArray = vtkDoubleArray::SafeDownCast(GeometryUtils::coupleVtkDataArray(m_vertices));
41  auto points = vtkSmartPointer<vtkPoints>::New();
42  points->SetNumberOfPoints(m_geometry->getNumVertices());
43  points->SetData(m_mappedVertexArray);
44  m_polydata->SetPoints(points);
45  }
46 
47  // When geometry is modified, update data source, mostly for when an entirely new array/buffer was set
48  queueConnect<Event>(m_geometry, &Geometry::modified,
49  std::static_pointer_cast<VTKVertexLabelRenderDelegate>(shared_from_this()),
51 
52  // When the vertex buffer internals are modified, ie: a single or N elements
53  queueConnect<Event>(m_geometry->getVertexPositions(), &VecDataArray<double, 3>::modified,
54  std::static_pointer_cast<VTKVertexLabelRenderDelegate>(shared_from_this()),
56 
57  // Setup mapper
58  // \todo: Replace with vtkFastLabelMapper on next VTK upgrade
59  {
60  vtkNew<vtkLabeledDataMapper> mapper;
61  mapper->SetInputData(m_polydata);
62  mapper->SetLabelModeToLabelIds();
63 
64  vtkNew<vtkActor2D> actor;
65  actor->SetMapper(mapper);
66  m_mapper = mapper;
67  m_actor = actor;
68  }
69 
70  update();
72 }
73 
74 void
76 {
77  // Custom handling of events
78  std::shared_ptr<VecDataArray<double, 3>> verticesPtr = m_geometry->getVertexPositions();
79 
80  // Only use the most recent event from respective sender
81  std::array<Command, 5> cmds;
82  std::array<bool, 5> contains = { false, false, false, false, false };
83  rforeachEvent([&](Command cmd)
84  {
85  if (cmd.m_event->m_sender == m_visualModel.get() && !contains[0])
86  {
87  cmds[0] = cmd;
88  contains[0] = true;
89  }
90  else if (cmd.m_event->m_sender == m_material.get() && !contains[1])
91  {
92  cmds[1] = cmd;
93  contains[1] = true;
94  }
95  else if (cmd.m_event->m_sender == m_geometry.get() && !contains[2])
96  {
97  cmds[2] = cmd;
98  contains[2] = true;
99  }
100  else if (cmd.m_event->m_sender == verticesPtr.get() && !contains[3])
101  {
102  cmds[3] = cmd;
103  contains[3] = true;
104  }
105  });
106 
107  // Now do all the commands
108  cmds[0].invoke(); // Update VisualModel
109  cmds[1].invoke(); // Update RenderMaterial
110  cmds[3].invoke(); // Update vertices
111  cmds[2].invoke(); // Update geometry as a whole
112 }
113 
114 void
116 {
117  auto visualModel = std::dynamic_pointer_cast<VertexLabelVisualModel>(m_visualModel);
118  auto labelMapper = vtkLabeledDataMapper::SafeDownCast(m_mapper);
119 
120  labelMapper->SetLabelFormat(visualModel->getFormat().c_str());
121 
122  const Color& color = visualModel->getTextColor();
123  labelMapper->GetLabelTextProperty()->SetColor(color.r, color.g, color.b);
124  labelMapper->GetLabelTextProperty()->SetFontSize(visualModel->getFontSize());
125  labelMapper->GetLabelTextProperty()->SetShadow(false);
126 }
127 
128 void
130 {
131  setVertexBuffer(m_geometry->getVertexPositions());
132 }
133 
134 void
136 {
137  // If the vertices were reallocated
138  if (m_vertices != m_geometry->getVertexPositions())
139  {
140  setVertexBuffer(m_geometry->getVertexPositions());
141  }
142 
143  // Assume vertices are always changed
144  m_mappedVertexArray->Modified();
145 }
146 
147 void
148 VTKVertexLabelRenderDelegate::setVertexBuffer(std::shared_ptr<VecDataArray<double, 3>> vertices)
149 {
150  // If the buffer changed
151  if (m_vertices != vertices)
152  {
153  // If previous buffer exist
154  if (m_vertices != nullptr)
155  {
156  // stop observing its changes
157  disconnect(m_vertices,
158  std::static_pointer_cast<VTKVertexLabelRenderDelegate>(shared_from_this()),
160  }
161  // Set new buffer and observe
162  m_vertices = vertices;
163  queueConnect<Event>(m_vertices, &VecDataArray<double, 3>::modified,
164  std::static_pointer_cast<VTKVertexLabelRenderDelegate>(shared_from_this()),
166  }
167 
168  // Couple the buffer
169  m_mappedVertexArray->SetNumberOfComponents(3);
170  m_mappedVertexArray->SetArray(reinterpret_cast<double*>(m_vertices->getPointer()), m_vertices->size() * 3, 1);
171  m_mappedVertexArray->Modified();
172  m_polydata->GetPoints()->SetNumberOfPoints(m_vertices->size());
173 }
174 } // 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.
void updateRenderProperties() override
Updates the actor and mapper properties from the currently set VisualModel.
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)) ...
Base class for events which contain a type, priority, and data priority defaults to 0 and uses a grea...
Compound Geometry.
void geometryModified(Event *e)
Callback for when geometry changes.
void updateRenderProperties() override
Updates the actor and mapper properties from the currently set VisualModel.
Delegates rendering of text per PointSet vertex to VTK from VisualModel.
void processEvents() override
Update polydata source based on the mesh geometry.
Color in RGB space.
Definition: imstkColor.h:24
void vertexDataModified(Event *e)
Callback for when vertex data changes.
Given a PointSet geometry it will render labels for each vertex with numberings.
Stores everything needed to invoke an event A call may not be present, in which case invoke doesn&#39;t d...