Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
mitkEnhancedPointSetVtkMapper3D.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
14 
15 //#include <sstream>
16 #include <algorithm>
17 
18 #include "mitkDataNode.h"
19 #include "mitkLookupTables.h"
20 #include "mitkProperties.h"
21 
22 #include "mitkColorProperty.h"
23 //#include "mitkVtkPropRenderer.h"
24 
25 #include <vtkActor.h>
26 
27 #include <vtkAssembly.h>
28 #include <vtkProp3DCollection.h>
29 #include <vtkTubeFilter.h>
30 
31 #include <vtkConeSource.h>
32 #include <vtkCubeSource.h>
33 #include <vtkCylinderSource.h>
34 #include <vtkPolyDataMapper.h>
35 #include <vtkProperty.h>
36 #include <vtkSphereSource.h>
37 #include <vtkTransformPolyDataFilter.h>
38 
39 #include <vtkPolyDataAlgorithm.h>
40 
42 
44 {
45  return static_cast<const mitk::PointSet *>(GetDataNode()->GetData());
46 }
47 
49 {
50  m_Contour = vtkActor::New();
51  m_ContourSource = vtkTubeFilter::New();
52  m_PropAssembly = vtkAssembly::New();
53 }
54 
56 {
57  return m_PropAssembly;
58 }
59 
61 {
62  m_Contour->Delete();
63  m_ContourSource->Delete();
64  m_PropAssembly->Delete();
65 
66  // TODO: do cleanup correctly
67 
68  // Clean up all remaining actors and poly-data sources
69  // std::for_each(m_PointActors.begin(), m_PointActors.end(), &mitk::EnhancedPointSetVtkMapper3D::DeleteVtkObject);
70 
71  // std::for_each(m_SphereSources.begin(), m_SphereSources.end(),
72  // &mitk::EnhancedPointSetVtgkMapper3D::DeleteVtkObject);
73  // std::for_each(m_CubeSources.begin(), m_CubeSources.end(), &mitk::EnhancedPointSetVtkMapper3D::DeleteVtkObject);
74  // std::for_each(m_ConeSources.begin(), m_ConeSources.end(), &mitk::EnhancedPointSetVtkMapper3D::DeleteVtkObject);
75  // std::for_each(m_CylinderSources.begin(), m_CylinderSources.end(),
76  // &mitk::EnhancedPointSetVtkMapper3D::DeleteVtkObject);
77  //
78 }
79 
81 {
82  // get and update the PointSet
83  const mitk::PointSet *pointset = this->GetInput();
84  // pointset->Update();
85  int timestep = this->GetTimestep();
86 
87  mitk::PointSet::DataType *itkPointSet = pointset->GetPointSet(timestep);
88  mitk::PointSet::PointsContainer *points = itkPointSet->GetPoints();
89  mitk::PointSet::PointDataContainer *pointData = itkPointSet->GetPointData();
90 
91  assert(points->Size() == pointData->Size());
92 
95 
96  /* search removed points and delete the corresponding source/actor/mapper objects */
97  for (auto it = m_PointActors.begin(); it != m_PointActors.end();)
98  {
99  PointIdentifier id = it->first;
100  if (!points->IndexExists(id))
101  {
102  this->RemoveEntryFromSourceMaps(id);
103  m_PropAssembly->GetParts()->RemoveItem(it->second.first); // remove from prop assembly
104  if (it->second.first != nullptr)
105  it->second.first->Delete(); // Delete actor, which deletes mapper too (reference count)
106  auto er = it; // save iterator for deleting
107  ++it; // advance iterator to next object
108  m_PointActors.erase(
109  er); // erase element from map. This invalidates er, therefore we had to advance it before deletion.
110  }
111  else
112  ++it;
113  }
114 
115  /* iterate over each point in the pointset and create corresponding vtk objects */
116  for (pIt = points->Begin(), pdIt = pointData->Begin(); pIt != itkPointSet->GetPoints()->End(); ++pIt, ++pdIt)
117  {
118  PointIdentifier pointID = pIt->Index();
119  assert(pointID == pdIt->Index());
120 
121  mitk::PointSet::PointDataType data = pdIt->Value();
122 
123  auto aIt = m_PointActors.find(pointID); // Does an actor exist for the point?
124 
125  /* Create/Update sources for the point */
126  vtkActor *a = nullptr;
127  bool newPoint = (aIt == m_PointActors.end()); // current point is new
128  bool specChanged = (!newPoint && data.pointSpec != aIt->second.second); // point spec of current point has changed
129 
130  if (newPoint) // point did not exist before, we have to create vtk objects for it
131  { // create actor and mapper for the new point
132  a = vtkActor::New();
133  vtkPolyDataMapper *m = vtkPolyDataMapper::New();
134  a->SetMapper(m);
135  m->UnRegister(nullptr);
136  aIt = m_PointActors.insert(std::make_pair(pointID, std::make_pair(a, data.pointSpec)))
137  .first; // insert element and update actormap iterator to point to new element
138  m_PropAssembly->AddPart(a);
139  }
140  else
141  {
142  a = aIt->second.first;
143  if (specChanged) // point exists, but point spec has changed
144  {
145  this->RemoveEntryFromSourceMaps(pointID);
146  }
147  }
148  if (newPoint || specChanged) // new point OR existing point but point spec changed
149  {
150  vtkPolyDataAlgorithm *source = nullptr; // works only in VTK 5+
151  switch (data.pointSpec) // add to new map
152  { // TODO: look up representation in a representationlookuptable
153  case PTSTART: // cube
154  m_CubeSources[pointID] = vtkCubeSource::New();
155  source = m_CubeSources[pointID];
156  break;
157  case PTCORNER: // cone
158  m_ConeSources[pointID] = vtkConeSource::New();
159  source = m_ConeSources[pointID];
160  break;
161  case PTEDGE: // cylinder
162  m_CylinderSources[pointID] = vtkCylinderSource::New();
163  source = m_CylinderSources[pointID];
164  break;
165  case PTUNDEFINED: // sphere
166  case PTEND:
167  default:
168  m_SphereSources[pointID] = vtkSphereSource::New();
169  source = m_SphereSources[pointID];
170  break;
171  }
172  auto *m = dynamic_cast<vtkPolyDataMapper *>(a->GetMapper());
173  assert(m != nullptr);
174  m->SetInputConnection(source->GetOutputPort());
175  aIt->second.second = data.pointSpec; // update point spec in actormap
176  }
177  } // for each point
178 }
179 
181  vtkActor * /*actor*/)
182 {
183  this->UpdateVtkObjects();
184 
185  /* iterate over all points in pointset and apply properties to corresponding vtk objects */
186  // get and update the PointSet
187  const mitk::PointSet *pointset = this->GetInput();
188  int timestep = this->GetTimestep();
189  mitk::PointSet::DataType *itkPointSet = pointset->GetPointSet(timestep);
190  mitk::PointSet::PointsContainer *points = itkPointSet->GetPoints();
191  mitk::PointSet::PointDataContainer *pointData = itkPointSet->GetPointData();
192  assert(points->Size() == pointData->Size());
195  mitk::DataNode *n = this->GetDataNode();
196  assert(n != nullptr);
197 
198  for (pIt = points->Begin(), pdIt = pointData->Begin(); pIt != itkPointSet->GetPoints()->End();
199  ++pIt, ++pdIt) // for each point in the pointset
200  {
201  PointIdentifier pointID = pIt->Index();
202  assert(pointID == pdIt->Index());
203 
204  mitk::PointSet::PointDataType data = pdIt->Value();
205 
206  auto aIt = m_PointActors.find(pointID); // Does an actor exist for the point?
207  assert(aIt != m_PointActors.end()); // UpdateVtkObjects() must ensure that actor exists
208 
209  vtkActor *a = aIt->second.first;
210  assert(a != nullptr);
211 
212  /* update properties */
213  // visibility
214  bool pointVisibility = true;
215  bool visValueFound = false;
216  mitk::BaseProperty *visProp = n->GetProperty("visibility", renderer);
217  auto *visLTProp = dynamic_cast<mitk::BoolLookupTableProperty *>(visProp);
218  if (visLTProp != nullptr)
219  {
220  mitk::BoolLookupTable visLookupTable = visLTProp->GetValue();
221  // if (visLookupTable != nullptr)
222  //{
223  try
224  {
225  pointVisibility = visLookupTable.GetTableValue(pointID);
226  visValueFound = true;
227  }
228  catch (...)
229  {
230  }
231  //}
232  }
233  if (visValueFound == false)
234  {
235  pointVisibility = n->IsVisible(renderer, "show points"); // use BoolProperty instead
236  }
237  a->SetVisibility(pointVisibility);
238 
239  // opacity
240  float opacity = 1.0;
241  bool opValueFound = false;
242  mitk::BaseProperty *opProp = n->GetProperty("opacity", renderer);
243  auto *opLTProp = dynamic_cast<mitk::FloatLookupTableProperty *>(opProp);
244  if (opLTProp != nullptr)
245  {
246  mitk::FloatLookupTable opLookupTable = opLTProp->GetValue();
247  // if (opLookupTable != nullptr)
248  //{
249  try
250  {
251  opacity = opLookupTable.GetTableValue(pointID);
252  opValueFound = true;
253  }
254  catch (...)
255  {
256  }
257  //}
258  }
259  if (opValueFound == false)
260  {
261  n->GetOpacity(opacity, renderer);
262  }
263  a->GetProperty()->SetOpacity(opacity);
265 
266  // pointsize & point position
267  float pointSize = 1.0;
268  n->GetFloatProperty("pointsize", pointSize, renderer);
269  switch (data.pointSpec)
270  { // TODO: look up representation in a representationlookuptable
271  case PTSTART: // cube
272  m_CubeSources[pointID]->SetXLength(pointSize);
273  m_CubeSources[pointID]->SetYLength(pointSize);
274  m_CubeSources[pointID]->SetZLength(pointSize);
275  // m_CubeSources[pointID]->SetCenter(pos[0], pos[1], pos[2]);
276  break;
277  case PTCORNER: // cone
278  m_ConeSources[pointID]->SetRadius(pointSize / 2);
279  m_ConeSources[pointID]->SetHeight(pointSize);
280  m_ConeSources[pointID]->SetResolution(2); // two crossed triangles. Maybe introduce an extra property for
281  // m_ConeSources[pointID]->SetCenter(pos[0], pos[1], pos[2]);
282  break;
283  case PTEDGE: // cylinder
284  m_CylinderSources[pointID]->SetRadius(pointSize / 2);
285  m_CylinderSources[pointID]->SetHeight(pointSize);
286  m_CylinderSources[pointID]->CappingOn();
287  m_CylinderSources[pointID]->SetResolution(6);
288  // m_CylinderSources[pointID]->SetCenter(pos[0], pos[1], pos[2]);
289  break;
290  case PTUNDEFINED: // sphere
291  case PTEND:
292  default:
293  m_SphereSources[pointID]->SetRadius(pointSize / 2);
294  m_SphereSources[pointID]->SetThetaResolution(10);
295  m_SphereSources[pointID]->SetPhiResolution(10);
296  // m_SphereSources[pointID]->SetCenter(pos[0], pos[1], pos[2]);
297  break;
298  }
299 
300  // set position
301  mitk::Point3D pos = pIt->Value();
302  aIt->second.first->SetPosition(pos[0], pos[1], pos[2]);
303 
304  // selectedcolor & color
305  float color[3];
306  if (data.selected)
307  {
308  if (!n->GetColor(color, renderer, "selectedcolor"))
309  n->GetColor(color, renderer);
310  }
311  else
312  {
313  mitk::BaseProperty *a = n->GetProperty("colorLookupTable", renderer);
314  auto *b = dynamic_cast<mitk::LookupTableProperty *>(a);
315  if (b != nullptr)
316  {
317  mitk::LookupTable::Pointer c = b->GetLookupTable();
318  vtkLookupTable *d = c->GetVtkLookupTable();
319  double *e = d->GetTableValue(pointID);
320  color[0] = e[0];
321  color[1] = e[1];
322  color[2] = e[2];
323  }
324  else
325  {
326  if (!n->GetColor(color, renderer, "unselectedcolor"))
327  n->GetColor(color, renderer);
328  }
329  }
330 
331  // TODO: What about "color" property? 2D Mapper only uses unselected and selected color properties
332  a->GetProperty()->SetColor(color[0], color[1], color[2]);
333 
334  // TODO: label property
335  }
336  // TODO test different pointSpec
337  // TODO "line width" "show contour" "contourcolor" "contoursize" "close contour" "show label", "label"
338  // TODO "show points" vs "visibility" - is visibility evaluated at all? in a superclass maybe?
339  // TODO create lookup tables for all properties that should be evaluated per point. also create editor widgets for
340  // these lookup tables!
341  // TODO check if property changes and pointset changes are reflected in the render window immediately.
342  // TODO check behavior with large PointSets
343  // TODO check for memory leaks on adding/deleting points
344 }
345 
347 {
348  BaseLocalStorage *ls = m_LSH.GetLocalStorage(renderer);
349  bool needGenerateData = ls->IsGenerateDataRequired(renderer, this, GetDataNode());
350 
351  if (needGenerateData)
352  {
353  ls->UpdateGenerateDataTime();
354  this->UpdateVtkObjects();
355  }
356 
357  ApplyColorAndOpacityProperties(renderer, nullptr);
358 }
359 
361 {
362  // TODO: apply new transform if time step changed
363 
364  // vtkLinearTransform * vtktransform =
365  // this->GetDataNode()->GetVtkTransform(this->GetTimestep());
366 
367  // m_SelectedActor->SetUserTransform(vtktransform);
368  // m_UnselectedActor->SetUserTransform(vtktransform);
369  // m_ContourActor->SetUserTransform(vtktransform);
370 }
371 
373  mitk::BaseRenderer *renderer,
374  bool overwrite)
375 {
376  node->AddProperty("line width", mitk::IntProperty::New(2), renderer, overwrite);
377  node->AddProperty("pointsize", mitk::FloatProperty::New(1.0), renderer, overwrite);
378  node->AddProperty(
379  "selectedcolor", mitk::ColorProperty::New(1.0f, 1.0f, 0.0f), renderer, overwrite); // yellow for selected
380  node->AddProperty(
381  "unselectedcolor", mitk::ColorProperty::New(0.5f, 1.0f, 0.5f), renderer, overwrite); // middle green for unselected
382  node->AddProperty("color", mitk::ColorProperty::New(1.0f, 0.0f, 0.0f), renderer, overwrite); // red as standard
383  node->AddProperty("show contour", mitk::BoolProperty::New(false), renderer, overwrite);
384  node->AddProperty("contourcolor", mitk::ColorProperty::New(1.0f, 0.0f, 0.0f), renderer, overwrite);
385  node->AddProperty("contoursize", mitk::FloatProperty::New(0.5), renderer, overwrite);
386  node->AddProperty("show points", mitk::BoolProperty::New(true), renderer, overwrite);
387  node->AddProperty("show label", mitk::BoolProperty::New(false), renderer, overwrite);
388  node->AddProperty("label", mitk::StringProperty::New("P"), renderer, overwrite);
389  node->AddProperty("opacity", mitk::FloatProperty::New(1.0), renderer, overwrite);
390  Superclass::SetDefaultProperties(node, renderer, overwrite);
391 }
392 
394 {
395  if (o != nullptr)
396  o->Delete();
397 }
398 
400 {
401  auto aIt = m_PointActors.find(pointID);
402  if (aIt == m_PointActors.end())
403  return;
404 
405  switch (aIt->second.second) // erase in old map
406  { // TODO: look up representation in a representationlookuptable
407  case PTSTART: // cube
408  m_CubeSources[pointID]->Delete();
409  m_CubeSources.erase(pointID);
410  break;
411 
412  case PTCORNER: // cone
413  m_ConeSources[pointID]->Delete();
414  m_ConeSources.erase(pointID);
415  break;
416 
417  case PTEDGE: // cylinder
418  m_CylinderSources[pointID]->Delete();
419  m_CylinderSources.erase(pointID);
420  break;
421 
422  case PTUNDEFINED: // sphere
423  case PTEND:
424  default:
425  m_SphereSources[pointID]->Delete();
426  m_SphereSources.erase(pointID);
427  break;
428  }
429 }
#define ls
Definition: MitkMCxyz.cpp:57
mitk::BaseProperty * GetProperty(const char *propertyKey, const mitk::BaseRenderer *renderer=nullptr, bool fallBackOnDataProperties=true) const
Get the property (instance of BaseProperty) with key propertyKey from the PropertyList of the rendere...
MeshType DataType
Definition: mitkPointSet.h:131
DataType::PointsContainerIterator PointsIterator
Definition: mitkPointSet.h:135
L * GetLocalStorage(mitk::BaseRenderer *forRenderer)
Retrieves a LocalStorage for a specific BaseRenderer.
DataType::PointDataContainer PointDataContainer
Definition: mitkPointSet.h:137
bool IsGenerateDataRequired(mitk::BaseRenderer *renderer, mitk::Mapper *mapper, mitk::DataNode *dataNode) const
Definition: mitkMapper.cpp:119
virtual DataNode * GetDataNode() const
Get the DataNode containing the data to map. Method only returns valid DataNode Pointer if the mapper...
Definition: mitkMapper.cpp:31
static Pointer New()
bool GetFloatProperty(const char *propertyKey, float &floatValue, const mitk::BaseRenderer *renderer=nullptr) const
Convenience access method for float properties (instances of FloatProperty)
Organizes the rendering process.
struct for data of a point
Definition: mitkPointSet.h:93
bool GetOpacity(float &opacity, const mitk::BaseRenderer *renderer, const char *propertyKey="opacity") const
Convenience access method for opacity properties (instances of FloatProperty)
vtkProp * GetVtkProp(mitk::BaseRenderer *renderer) override
void GenerateDataForRenderer(mitk::BaseRenderer *renderer) override
Generate the data needed for rendering into renderer.
DataType::PointIdentifier PointIdentifier
Definition: mitkPointSet.h:133
static Pointer New()
BaseData * GetData() const
Get the data object (instance of BaseData, e.g., an Image) managed by this DataNode.
Abstract base class for properties.
void AddProperty(const char *propertyKey, BaseProperty *property, const mitk::BaseRenderer *renderer=nullptr, bool overwrite=false)
Add the property (instance of BaseProperty) if it does not exist (or always ifoverwrite istrue) with ...
bool IsVisible(const mitk::BaseRenderer *renderer, const char *propertyKey="visible", bool defaultIsOn=true) const
Convenience access method for visibility properties (instances of BoolProperty). Return value is the ...
Definition: mitkDataNode.h:462
The LookupTableProperty class Property to associate mitk::LookupTable to an mitk::DataNode.
Data structure which stores a set of points. Superclass of mitk::Mesh.
Definition: mitkPointSet.h:75
bool GetColor(float rgb[3], const mitk::BaseRenderer *renderer=nullptr, const char *propertyKey="color") const
Convenience access method for color properties (instances of ColorProperty)
ValueType GetTableValue(IdentifierType id) const
mitk::PointSet::PointIdentifier PointIdentifier
void RemoveEntryFromSourceMaps(mitk::PointSet::PointIdentifier pointID)
virtual DataType::Pointer GetPointSet(int t=0) const
returns the pointset
void ApplyColorAndOpacityProperties(mitk::BaseRenderer *renderer, vtkActor *actor) override
Apply color and opacity properties read from the PropertyList. Called by mapper subclasses.
static void SetDefaultProperties(mitk::DataNode *node, mitk::BaseRenderer *renderer=nullptr, bool overwrite=false)
static Pointer New()
DataType::PointsContainer PointsContainer
Definition: mitkPointSet.h:134
static Pointer New()
int GetTimestep() const
Returns the current time step as calculated from the renderer.
Definition: mitkMapper.h:147
LocalStorageHandler< BaseLocalStorage > m_LSH
specializations of GenericLookupTable
DataType::PointDataContainerIterator PointDataIterator
Definition: mitkPointSet.h:138
static Pointer New()
Class for nodes of the DataTree.
Definition: mitkDataNode.h:57
void UpdateVtkTransform(mitk::BaseRenderer *renderer) override
Set the vtkTransform of the m_Prop3D for the current time step of renderer.