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