iMSTK
Interactive Medical Simulation Toolkit
imstkVTKImageDataRenderDelegate.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 "imstkVTKImageDataRenderDelegate.h"
8 #include "imstkGeometryUtilities.h"
9 #include "imstkImageData.h"
10 #include "imstkRenderMaterial.h"
11 #include "imstkVisualModel.h"
12 
13 #include <vtkGPUVolumeRayCastMapper.h>
14 #include <vtkImageData.h>
15 #include <vtkPointData.h>
16 #include <vtkDataArray.h>
17 #include <vtkVolume.h>
18 #include <vtkTransform.h>
19 
20 namespace imstk
21 {
22 VTKImageDataRenderDelegate::VTKImageDataRenderDelegate() :
23  m_scalarArray(nullptr),
24  m_imageDataVtk(nullptr)
25 {
26 }
27 
28 void
29 VTKImageDataRenderDelegate::init()
30 {
31  auto imageData = std::dynamic_pointer_cast<ImageData>(m_visualModel->getGeometry());
32  CHECK(imageData != nullptr) << "VTKImageDataRenderDelegate only works with ImageData geometry";
33  m_scalarArray = imageData->getScalars();
34 
35  // Couple the imstkImageData with vtkImageData
36  m_imageDataVtk = GeometryUtils::coupleVtkImageData(imageData);
37 
38  // When the image is modified
39  queueConnect<Event>(imageData, &ImageData::modified,
40  std::static_pointer_cast<VTKImageDataRenderDelegate>(shared_from_this()),
42 
43  // When the image scalars are modified
44  queueConnect<Event>(imageData->getScalars(), &AbstractDataArray::modified,
45  std::static_pointer_cast<VTKImageDataRenderDelegate>(shared_from_this()),
47 
48  // Setup mapper
49  {
50  vtkNew<vtkGPUVolumeRayCastMapper> mapper;
51  mapper->SetInputData(m_imageDataVtk);
52  vtkNew<vtkVolume> volume;
53  volume->SetMapper(mapper);
54  volume->SetUserTransform(m_transform);
55  m_mapper = mapper;
56  m_actor = volume;
57  }
58 
59  update();
61 }
62 
63 void
65 {
66  // This handler chooses and executes the latest event from each respective sender
67  std::shared_ptr<ImageData> geom = std::dynamic_pointer_cast<ImageData>(m_visualModel->getGeometry());
68 
69  // Only use the most recent event from respective sender
70  std::list<Command> cmds;
71  bool contains[4] = { false, false, false, false };
72  rforeachEvent([&](Command cmd)
73  {
74  if (cmd.m_event->m_sender == m_visualModel.get() && !contains[0])
75  {
76  cmds.push_back(cmd);
77  contains[0] = true;
78  }
79  else if (cmd.m_event->m_sender == m_material.get() && !contains[1])
80  {
81  cmds.push_back(cmd);
82  contains[1] = true;
83  }
84  else if (cmd.m_event->m_sender == geom.get() && !contains[2])
85  {
86  cmds.push_back(cmd);
87  contains[2] = true;
88  }
89  else if (cmd.m_event->m_sender == geom->getScalars().get() && !contains[3])
90  {
91  cmds.push_back(cmd);
92  contains[3] = true;
93  }
94  });
95  // Now do each event in order recieved
96  for (std::list<Command>::reverse_iterator i = cmds.rbegin(); i != cmds.rend(); i++)
97  {
98  i->invoke();
99  }
100 }
101 
102 void
104 {
105  auto imageData = std::static_pointer_cast<ImageData>(m_visualModel->getGeometry());
106  vtkSmartPointer<vtkGPUVolumeRayCastMapper> volumeMapper = vtkGPUVolumeRayCastMapper::SafeDownCast(m_mapper);
107 
108  // If the user swapped scalars on us
109  if (m_scalarArray != imageData->getScalars())
110  {
111  // Update our handle
112  m_scalarArray = imageData->getScalars();
113 
114  // Update vtk data array pointer
115  m_imageDataVtk->GetPointData()->GetScalars()->SetVoidArray(m_scalarArray->getVoidPointer(), m_scalarArray->size(), 1);
116 
117  // Update information
118  // \todo: Can't handle type changes or number of component changes
119  const Vec3i& dim = imageData->getDimensions();
120  m_imageDataVtk->SetDimensions(dim.data());
121  m_imageDataVtk->SetExtent(0, dim[0] - 1, 0, dim[1] - 1, 0, dim[2] - 1);
122  const Vec3d vtkOrigin = imageData->getOrigin() + imageData->getSpacing() * 0.5;
123  m_imageDataVtk->SetOrigin(vtkOrigin.data());
124  m_imageDataVtk->SetSpacing(imageData->getSpacing().data());
125  }
126  volumeMapper->GetInput()->Modified();
127 }
128 
129 void
131 {
132  auto geometry = std::static_pointer_cast<ImageData>(m_visualModel->getGeometry());
133  vtkSmartPointer<vtkGPUVolumeRayCastMapper> volumeMapper = vtkGPUVolumeRayCastMapper::SafeDownCast(m_mapper);
134  m_scalarArray = geometry->getScalars();
135 
136  // If pointer changed, update the one vtk is viewing
137  if (m_scalarArray->getVoidPointer() != m_imageDataVtk->GetPointData()->GetScalars()->GetVoidPointer(0))
138  {
139  m_imageDataVtk->GetPointData()->GetScalars()->SetVoidArray(m_scalarArray->getVoidPointer(), m_scalarArray->size(), 1);
140  }
141  volumeMapper->GetInput()->Modified();
142 }
143 } // 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.
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 updateRenderProperties() override
Updates the actor and mapper properties from the currently set VisualModel.
void imageDataModified(Event *e)
Callback for when the image is modified.
void processEvents() override
Update render delegate source based on the internal data.
void imageScalarsModified(Event *e)
Callback for when the image scalars are modified.
Class to represent 1, 2, or 3D image data (i.e. structured points)
Stores everything needed to invoke an event A call may not be present, in which case invoke doesn&#39;t d...