iMSTK
Interactive Medical Simulation Toolkit
imstkVTKChartRenderDelegate.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 "imstkVTKChartRenderDelegate.h"
8 #include "imstkGeometryUtilities.h"
9 
10 #include <vtkAxis.h>
11 #include <vtkChartXY.h>
12 #include <vtkContextActor.h>
13 #include <vtkContextScene.h>
14 #include <vtkDataArray.h>
15 #include <vtkDataSetAttributes.h>
16 #include <vtkPlot.h>
17 #include <vtkTable.h>
18 
19 using namespace imstk;
20 
21 VTKChartRenderDelegate::VTKChartRenderDelegate() :
22  m_table(vtkSmartPointer<vtkTable>::New()),
23  m_chart(vtkSmartPointer<vtkChartXY>::New()),
24  m_chartActor(vtkSmartPointer<vtkContextActor>::New()),
25  m_contextScene(vtkSmartPointer<vtkContextScene>::New())
26 {
27 }
28 
29 void
30 VTKChartRenderDelegate::init()
31 {
32  auto chartVisualModel = std::dynamic_pointer_cast<ChartVisualModel>(m_visualModel);
33  CHECK(chartVisualModel != nullptr) << "VTKChartRenderDelegate only works with ChartVisualModel VisualModel";
34 
35  m_chart->SetAutoSize(false);
36  const Vec4d& bounds = chartVisualModel->getViewBounds();
37  m_chart->SetSize(vtkRectf(bounds[0], bounds[2], bounds[1], bounds[3]));
38 
39  m_contextScene->AddItem(m_chart);
40  m_chartActor->SetScene(m_contextScene);
41  m_actor = m_chartActor;
42 
43  processEvents();
44 }
45 
46 void
48 {
49  auto chartVisualModel = std::dynamic_pointer_cast<ChartVisualModel>(m_visualModel);
50  const std::vector<std::shared_ptr<Plot2d>>& plotsImstk = chartVisualModel->getPlots();
51 
52  // If we need to add/remove plots it's best to just to clear all the plots, re-add them
53  // So find the diffs
54 
55  // Search imstk plots for any plots this doesn't have yet (added)
56  std::vector<std::shared_ptr<Plot2d>> plotsToAdd;
57  std::vector<std::shared_ptr<Plot2d>> plotsToRemove;
58  for (auto plot : plotsImstk)
59  {
60  // If imstk has the plot but vtk does not
61  if (m_plots.count(plot) == 0)
62  {
63  // Add a new one mapped
64  plotsToAdd.push_back(plot);
65  }
66  }
67  // Search this plots for plots imstk doesn't have (removed)
68  for (auto pair : m_plots)
69  {
70  // If not found
71  if (std::find(plotsImstk.begin(), plotsImstk.end(), pair.first) == plotsImstk.end())
72  {
73  // Remove
74  plotsToRemove.push_back(pair.first);
75  }
76  }
77 
78  // If there are any diffs (plots added or removed)
79  if (plotsToAdd.size() > 0 || plotsToRemove.size() > 0)
80  {
81  m_chart->ClearPlots();
82 
83  for (auto plot : plotsToRemove)
84  {
85  m_plots.erase(plot);
86  }
87  for (auto plot : plotsToAdd)
88  {
89  m_plots[plot] = m_chart->AddPlot(vtkChart::LINE);
90  }
91  }
92  if (m_plots.size() == 0)
93  {
94  m_chart->ClearPlots();
95  return;
96  }
97 
98  m_chart->SetAutoSize(false);
99  const Vec4d& bounds = chartVisualModel->getViewBounds();
100  m_chart->SetSize(vtkRectf(bounds[0], bounds[2], bounds[1], bounds[3]));
101 
102  // Gather all the arrays and place them in a vtkTable
103  std::unordered_map<std::shared_ptr<AbstractDataArray>, size_t> m_arrayLocations;
104  for (auto pair : m_plots)
105  {
106  std::shared_ptr<Plot2d> plotImstk = pair.first;
107  if (m_arrayLocations.count(plotImstk->xVals) == 0)
108  {
109  const size_t i1 = m_arrayLocations.size();
110  m_arrayLocations[plotImstk->xVals] = i1;
111  }
112  if (m_arrayLocations.count(plotImstk->yVals) == 0)
113  {
114  const size_t i2 = m_arrayLocations.size();
115  m_arrayLocations[plotImstk->yVals] = i2;
116  }
117  }
118 
119  // Build the table with no particular order to the columns
120  m_table = vtkSmartPointer<vtkTable>::New();
121  for (auto arrayKeyValPair : m_arrayLocations)
122  {
123  vtkSmartPointer<vtkDataArray> arrVtk = GeometryUtils::copyToVtkDataArray(arrayKeyValPair.first);
124  const std::string arrName = "data" + std::to_string(arrayKeyValPair.second);
125  arrVtk->SetName(arrName.c_str());
126  m_table->AddColumn(arrVtk);
127  }
128 
129  Vec2d min = Vec2d(IMSTK_DOUBLE_MAX, IMSTK_DOUBLE_MAX);
130  Vec2d max = Vec2d(IMSTK_DOUBLE_MIN, IMSTK_DOUBLE_MIN);
131  for (auto pair : m_plots)
132  {
133  vtkPlot* plotVtk = pair.second;
134  std::shared_ptr<Plot2d> plotImstk = pair.first;
135 
136  const size_t xLocation = m_arrayLocations[plotImstk->xVals];
137  const size_t yLocation = m_arrayLocations[plotImstk->yVals];
138 
139  plotVtk->SetInputData(m_table, xLocation, yLocation);
140  const Color& color = plotImstk->lineColor;
141  plotVtk->SetColor(color.r * 255.0, color.g * 255.0, color.b * 255.0, color.a * 255.0);
142  plotVtk->SetWidth(plotImstk->lineWidth);
143 
144  double* rangeX = m_table->GetRowData()->GetArray(static_cast<int>(xLocation))->GetRange();
145  double* rangeY = m_table->GetRowData()->GetArray(static_cast<int>(yLocation))->GetRange();
146 
147  min[0] = std::min(min[0], rangeX[0]);
148  min[1] = std::min(min[1], rangeY[0]);
149 
150  max[0] = std::max(max[0], rangeX[1]);
151  max[1] = std::max(max[1], rangeY[1]);
152  }
153 
154  m_chart->GetAxis(1)->SetMinimum(min[0]);
155  m_chart->GetAxis(1)->SetMaximum(max[0]);
156 
157  m_chart->GetAxis(0)->SetMinimum(min[1]);
158  m_chart->GetAxis(0)->SetMaximum(max[1]);
159 }
Compound Geometry.
void processEvents() override
Update render delegate source based on the internal data.
Color in RGB space.
Definition: imstkColor.h:24
Class for graphing 2d charts, only supports 2d data.