Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
mitkUnstructuredGridMapper2D.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 #include <mitkGL.h>
15 
17 #include "mitkBaseRenderer.h"
18 #include "mitkColorProperty.h"
19 #include "mitkPlaneGeometry.h"
20 #include "mitkProperties.h"
21 #include "mitkTransferFunction.h"
23 #include "mitkUnstructuredGrid.h"
24 #include "mitkVtkMapper3D.h"
26 
27 #include <vtkAbstractMapper3D.h>
28 #include <vtkAbstractVolumeMapper.h>
29 #include <vtkAssembly.h>
30 #include <vtkCellArray.h>
31 #include <vtkCellData.h>
32 #include <vtkColorTransferFunction.h>
33 #include <vtkLinearTransform.h>
34 #include <vtkLookupTable.h>
35 #include <vtkPiecewiseFunction.h>
36 #include <vtkPlane.h>
37 #include <vtkPointData.h>
38 #include <vtkProp3DCollection.h>
39 #include <vtkScalarsToColors.h>
40 #include <vtkUnstructuredGrid.h>
41 #include <vtkVolume.h>
42 #include <vtkVolumeProperty.h>
43 
44 #include "vtkPointSetSlicer.h"
45 
47 {
49  bool needGenerateData = ls->IsGenerateDataRequired(renderer, this, GetDataNode());
50 
51  if (needGenerateData)
52  {
54 
56  if (node.IsNull())
57  return;
58 
59  if (!node->GetProperty(m_ScalarMode, "scalar mode"))
60  {
62  }
63 
64  if (!node->GetProperty(m_ScalarVisibility, "scalar visibility"))
65  {
67  }
68 
69  if (!node->GetProperty(m_Outline, "outline polygons"))
70  {
72  }
73 
74  if (!node->GetProperty(m_Color, "color"))
75  {
76  m_Color = mitk::ColorProperty::New(1.0f, 1.0f, 1.0f);
77  }
78 
79  if (!node->GetProperty(m_LineWidth, "line width"))
80  {
82  }
83  }
85  assert(input);
86 
87  input->Update();
88 
89  if (m_VtkPointSet)
90  m_VtkPointSet->UnRegister(nullptr);
91  m_VtkPointSet = this->GetVtkPointSet(renderer, this->GetTimestep());
92  assert(m_VtkPointSet);
93  m_VtkPointSet->Register(nullptr);
94 
95  if (m_ScalarVisibility->GetValue())
96  {
99  node->GetProperty(transferFuncProp, "TransferFunction", renderer);
100  if (transferFuncProp.IsNotNull())
101  {
102  mitk::TransferFunction::Pointer tf = transferFuncProp->GetValue();
103  if (m_ScalarsToColors)
104  m_ScalarsToColors->UnRegister(nullptr);
105  m_ScalarsToColors = static_cast<vtkScalarsToColors *>(tf->GetColorTransferFunction());
106  m_ScalarsToColors->Register(nullptr);
107 
108  if (m_ScalarsToOpacity)
109  m_ScalarsToOpacity->UnRegister(nullptr);
110  m_ScalarsToOpacity = tf->GetScalarOpacityFunction();
111  m_ScalarsToOpacity->Register(nullptr);
112  }
113  else
114  {
115  if (m_ScalarsToColors)
116  m_ScalarsToColors->UnRegister(nullptr);
117  m_ScalarsToColors = this->GetVtkLUT(renderer);
118  assert(m_ScalarsToColors);
119  m_ScalarsToColors->Register(nullptr);
120 
121  float opacity;
122  node->GetOpacity(opacity, renderer);
123  if (m_ScalarsToOpacity)
124  m_ScalarsToOpacity->UnRegister(nullptr);
125  m_ScalarsToOpacity = vtkPiecewiseFunction::New();
126  double range[2];
127  m_VtkPointSet->GetScalarRange(range);
128  m_ScalarsToOpacity->AddSegment(range[0], opacity, range[1], opacity);
129  }
130  }
131 }
132 
134 {
135  bool visible = true;
136  GetDataNode()->GetVisibility(visible, renderer, "visible");
137  if (!visible)
138  return;
139 
140  vtkLinearTransform *vtktransform = GetDataNode()->GetVtkTransform();
141  vtkLinearTransform *inversetransform = vtktransform->GetLinearInverse();
142 
143  PlaneGeometry::ConstPointer worldGeometry = renderer->GetCurrentWorldPlaneGeometry();
144  PlaneGeometry::ConstPointer worldPlaneGeometry = dynamic_cast<const PlaneGeometry *>(worldGeometry.GetPointer());
145 
146  Point3D point;
147  Vector3D normal;
148 
149  if (worldPlaneGeometry.IsNotNull())
150  {
151  // set up vtkPlane according to worldGeometry
152  point = worldPlaneGeometry->GetOrigin();
153  normal = worldPlaneGeometry->GetNormal();
154  normal.Normalize();
155  m_Plane->SetTransform((vtkAbstractTransform *)nullptr);
156  }
157  else
158  {
159  //@FIXME: does not work correctly. Does m_Plane->SetTransform really transforms a "plane plane" into a "curved
160  //plane"?
161  return;
162  AbstractTransformGeometry::ConstPointer worldAbstractGeometry =
163  dynamic_cast<const AbstractTransformGeometry *>(renderer->GetCurrentWorldPlaneGeometry());
164  if (worldAbstractGeometry.IsNotNull())
165  {
166  // set up vtkPlane according to worldGeometry
167  point = worldAbstractGeometry->GetParametricBoundingBox()->GetMinimum();
168  FillVector3D(normal, 0, 0, 1);
169  m_Plane->SetTransform(worldAbstractGeometry->GetVtkAbstractTransform()->GetInverse());
170  }
171  else
172  return;
173  }
174 
175  double vp[3], vnormal[3];
176 
177  vnl2vtk(point.GetVnlVector(), vp);
178  vnl2vtk(normal.GetVnlVector(), vnormal);
179 
180  // normally, we would need to transform the surface and cut the transformed surface with the cutter.
181  // This might be quite slow. Thus, the idea is, to perform an inverse transform of the plane instead.
182  //@todo It probably does not work for scaling operations yet:scaling operations have to be
183  // dealed with after the cut is performed by scaling the contour.
184  inversetransform->TransformPoint(vp, vp);
185  inversetransform->TransformNormalAtPoint(vp, vnormal, vnormal);
186 
187  m_Plane->SetOrigin(vp);
188  m_Plane->SetNormal(vnormal);
189 
190  // set data into cutter
191  m_Slicer->SetInputData(m_VtkPointSet);
192  // m_Cutter->GenerateCutScalarsOff();
193  // m_Cutter->SetSortByToSortByCell();
194 
195  // calculate the cut
196  m_Slicer->Update();
197 
198  // apply color and opacity read from the PropertyList
200 
201  // traverse the cut contour
202  vtkPolyData *contour = m_Slicer->GetOutput();
203 
204  vtkPoints *vpoints = contour->GetPoints();
205  vtkCellArray *vlines = contour->GetLines();
206  vtkCellArray *vpolys = contour->GetPolys();
207  vtkPointData *vpointdata = contour->GetPointData();
208  vtkDataArray *vscalars = vpointdata->GetScalars();
209 
210  vtkCellData *vcelldata = contour->GetCellData();
211  vtkDataArray *vcellscalars = vcelldata->GetScalars();
212 
213  const int numberOfLines = contour->GetNumberOfLines();
214  const int numberOfPolys = contour->GetNumberOfPolys();
215 
216  const bool useCellData = m_ScalarMode->GetVtkScalarMode() == VTK_SCALAR_MODE_DEFAULT ||
217  m_ScalarMode->GetVtkScalarMode() == VTK_SCALAR_MODE_USE_CELL_DATA;
218  const bool usePointData = m_ScalarMode->GetVtkScalarMode() == VTK_SCALAR_MODE_USE_POINT_DATA;
219 
220  Point3D p;
221  Point2D p2d;
222 
223  vlines->InitTraversal();
224  vpolys->InitTraversal();
225 
226  mitk::Color outlineColor = m_Color->GetColor();
227 
228  glLineWidth((float)m_LineWidth->GetValue());
229 
230  for (int i = 0; i < numberOfLines; ++i)
231  {
232  vtkIdType *cell(nullptr);
233  vtkIdType cellSize(0);
234 
235  vlines->GetNextCell(cellSize, cell);
236 
237  float rgba[4] = {outlineColor[0], outlineColor[1], outlineColor[2], 1.0f};
238  if (m_ScalarVisibility->GetValue() && vcellscalars)
239  {
240  if (useCellData)
241  { // color each cell according to cell data
242  double scalar = vcellscalars->GetComponent(i, 0);
243  double rgb[3] = {1.0f, 1.0f, 1.0f};
244  m_ScalarsToColors->GetColor(scalar, rgb);
245  rgba[0] = (float)rgb[0];
246  rgba[1] = (float)rgb[1];
247  rgba[2] = (float)rgb[2];
248  rgba[3] = (float)m_ScalarsToOpacity->GetValue(scalar);
249  }
250  else if (usePointData)
251  {
252  double scalar = vscalars->GetComponent(i, 0);
253  double rgb[3] = {1.0f, 1.0f, 1.0f};
254  m_ScalarsToColors->GetColor(scalar, rgb);
255  rgba[0] = (float)rgb[0];
256  rgba[1] = (float)rgb[1];
257  rgba[2] = (float)rgb[2];
258  rgba[3] = (float)m_ScalarsToOpacity->GetValue(scalar);
259  }
260  }
261 
262  glColor4fv(rgba);
263 
264  glBegin(GL_LINE_LOOP);
265  for (int j = 0; j < cellSize; ++j)
266  {
267  vpoints->GetPoint(cell[j], vp);
268  // take transformation via vtktransform into account
269  vtktransform->TransformPoint(vp, vp);
270 
271  vtk2itk(vp, p);
272 
273  // convert 3D point (in mm) to display coordinates (units )
274  renderer->WorldToDisplay(p, p2d);
275 
276  // convert display coordinates ( (0,0) is top-left ) in GL coordinates ( (0,0) is bottom-left )
277  // p2d[1]=toGL-p2d[1];
278 
279  // add the current vertex to the line
280  glVertex2f(p2d[0], p2d[1]);
281  }
282  glEnd();
283  }
284 
285  bool polyOutline = m_Outline->GetValue();
286  bool scalarVisibility = m_ScalarVisibility->GetValue();
287 
288  // cache the transformed points
289  // a fixed size array is way faster than 'new'
290  // slices through 3d cells usually do not generated
291  // polygons with more than 6 vertices
292  const int maxPolySize = 10;
293  auto *cachedPoints = new Point2D[maxPolySize * numberOfPolys];
294 
295  glEnable(GL_BLEND);
296  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
297 
298  // only draw polygons if there are cell scalars
299  // or the outline property is set to true
300  if (scalarVisibility && vcellscalars)
301  {
302  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
303 
304  for (int i = 0; i < numberOfPolys; ++i)
305  {
306  vtkIdType *cell(nullptr);
307  vtkIdType cellSize(0);
308 
309  vpolys->GetNextCell(cellSize, cell);
310 
311  float rgba[4] = {1.0f, 1.0f, 1.0f, 0};
312  if (scalarVisibility && vcellscalars)
313  {
314  if (useCellData)
315  { // color each cell according to cell data
316  double scalar = vcellscalars->GetComponent(i + numberOfLines, 0);
317  double rgb[3] = {1.0f, 1.0f, 1.0f};
318  m_ScalarsToColors->GetColor(scalar, rgb);
319  rgba[0] = (float)rgb[0];
320  rgba[1] = (float)rgb[1];
321  rgba[2] = (float)rgb[2];
322  rgba[3] = (float)m_ScalarsToOpacity->GetValue(scalar);
323  }
324  else if (usePointData)
325  {
326  double scalar = vscalars->GetComponent(i, 0);
327  double rgb[3] = {1.0f, 1.0f, 1.0f};
328  m_ScalarsToColors->GetColor(scalar, rgb);
329  rgba[0] = (float)rgb[0];
330  rgba[1] = (float)rgb[1];
331  rgba[2] = (float)rgb[2];
332  rgba[3] = (float)m_ScalarsToOpacity->GetValue(scalar);
333  }
334  }
335  glColor4fv(rgba);
336 
337  glBegin(GL_POLYGON);
338  for (int j = 0; j < cellSize; ++j)
339  {
340  vpoints->GetPoint(cell[j], vp);
341  // take transformation via vtktransform into account
342  vtktransform->TransformPoint(vp, vp);
343 
344  vtk2itk(vp, p);
345 
346  // convert 3D point (in mm) to display coordinates (units )
347  renderer->WorldToDisplay(p, p2d);
348 
349  // convert display coordinates ( (0,0) is top-left ) in GL coordinates ( (0,0) is bottom-left )
350  // p2d[1]=toGL-p2d[1];
351 
352  cachedPoints[i * 10 + j][0] = p2d[0];
353  cachedPoints[i * 10 + j][1] = p2d[1];
354 
355  // add the current vertex to the line
356  glVertex2f(p2d[0], p2d[1]);
357  }
358  glEnd();
359  }
360 
361  if (polyOutline)
362  {
363  vpolys->InitTraversal();
364 
365  glColor4f(outlineColor[0], outlineColor[1], outlineColor[2], 1.0f);
366  glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
367  for (int i = 0; i < numberOfPolys; ++i)
368  {
369  vtkIdType *cell(nullptr);
370  vtkIdType cellSize(0);
371 
372  vpolys->GetNextCell(cellSize, cell);
373 
374  glBegin(GL_POLYGON);
375  // glPolygonOffset(1.0, 1.0);
376  for (int j = 0; j < cellSize; ++j)
377  {
378  // add the current vertex to the line
379  glVertex2f(cachedPoints[i * 10 + j][0], cachedPoints[i * 10 + j][1]);
380  }
381  glEnd();
382  }
383  }
384  }
385  glDisable(GL_BLEND);
386  delete[] cachedPoints;
387 }
388 
390 {
391  // MITK_INFO << "GETVTKABSTRACTMAPPER3D\n";
393  if (node.IsNull())
394  return nullptr;
395 
396  mitk::VtkMapper::Pointer mitkMapper = dynamic_cast<mitk::VtkMapper *>(node->GetMapper(2));
397  if (mitkMapper.IsNull())
398  {
399  return nullptr;
400  }
401 
402  mitkMapper->Update(renderer);
403 
404  auto *assembly = dynamic_cast<vtkAssembly *>(mitkMapper->GetVtkProp(renderer));
405  if (assembly)
406  {
407  vtkProp3DCollection *collection = assembly->GetParts();
408  collection->InitTraversal();
409  vtkProp3D *prop3d = nullptr;
410  do
411  {
412  prop3d = collection->GetNextProp3D();
413  auto *actor = dynamic_cast<vtkActor *>(prop3d);
414  if (actor)
415  {
416  return dynamic_cast<vtkAbstractMapper3D *>(actor->GetMapper());
417  }
418 
419  auto *volume = dynamic_cast<vtkVolume *>(prop3d);
420  if (volume)
421  {
422  return dynamic_cast<vtkAbstractMapper3D *>(volume->GetMapper());
423  }
424  } while (prop3d != collection->GetLastProp3D());
425  }
426  else
427  {
428  auto *actor = dynamic_cast<vtkActor *>(mitkMapper->GetVtkProp(renderer));
429  if (actor)
430  {
431  return dynamic_cast<vtkAbstractMapper3D *>(actor->GetMapper());
432  }
433 
434  auto *volume = dynamic_cast<vtkVolume *>(mitkMapper->GetVtkProp(renderer));
435  if (volume)
436  {
437  return dynamic_cast<vtkAbstractMapper3D *>(volume->GetMapper());
438  }
439  }
440  return nullptr;
441 }
442 
444 {
445  // MITK_INFO << "GETVTKPOINTSET\n";
446  vtkAbstractMapper3D *abstractMapper = GetVtkAbstractMapper3D(renderer);
447  if (abstractMapper == nullptr)
448  {
449  // try to get data from the node
451  if (node.IsNull())
452  return nullptr;
453  mitk::BaseData::Pointer data = node->GetData();
454  mitk::UnstructuredGrid::Pointer grid = dynamic_cast<mitk::UnstructuredGrid *>(data.GetPointer());
455  if (!grid.IsNull())
456  return static_cast<vtkPointSet *>(grid->GetVtkUnstructuredGrid(time));
457 
458  return nullptr;
459  }
460  else
461  {
462  auto *mapper = dynamic_cast<vtkMapper *>(abstractMapper);
463  if (mapper)
464  {
465  return dynamic_cast<vtkPointSet *>(mapper->GetInput());
466  }
467  auto *volMapper = dynamic_cast<vtkAbstractVolumeMapper *>(abstractMapper);
468  if (volMapper)
469  {
470  return dynamic_cast<vtkPointSet *>(volMapper->GetDataSetInput());
471  }
472  }
473 
474  return nullptr;
475 }
476 
478 {
479  // MITK_INFO << "GETVTKLUT\n";
480  auto *mapper = dynamic_cast<vtkMapper *>(GetVtkAbstractMapper3D(renderer));
481  if (mapper)
482  return mapper->GetLookupTable();
483  else
484  {
486  if (node.IsNull())
487  return nullptr;
488 
489  mitk::VtkMapper::Pointer mitkMapper = dynamic_cast<mitk::VtkMapper *>(node->GetMapper(2));
490  if (mitkMapper.IsNull())
491  {
492  // MITK_INFO << "mitkMapper is null\n";
493  return nullptr;
494  }
495 
496  mitkMapper->Update(renderer);
497 
498  auto *volume = dynamic_cast<vtkVolume *>(mitkMapper->GetVtkProp(renderer));
499  if (volume)
500  {
501  // MITK_INFO << "found volume prop\n";
502  return static_cast<vtkScalarsToColors *>(volume->GetProperty()->GetRGBTransferFunction());
503  }
504 
505  auto *assembly = dynamic_cast<vtkAssembly *>(mitkMapper->GetVtkProp(renderer));
506  if (assembly)
507  {
508  // MITK_INFO << "found assembly prop\n";
510  node->GetProperty(transferFuncProp, "TransferFunction", nullptr);
511  if (transferFuncProp.IsNotNull())
512  {
513  MITK_INFO << "return colortransferfunction\n";
514  return static_cast<vtkScalarsToColors *>(transferFuncProp->GetValue()->GetColorTransferFunction());
515  }
516  }
517  return nullptr;
518  }
519 }
520 
522 {
523  return (GetVtkPointSet(renderer, this->GetTimestep()) != nullptr);
524 }
525 
527 {
528  m_Plane = vtkPlane::New();
530 
532 
533  m_ScalarsToColors = nullptr;
534  m_ScalarsToOpacity = nullptr;
535  m_VtkPointSet = nullptr;
536 
537  // m_LUT = vtkLookupTable::New();
538  // m_LUT->SetTableRange( 0, 255 );
539  // m_LUT->SetNumberOfColors( 255 );
540  // m_LUT->SetRampToLinear ();
541  // m_LUT->Build();
542 }
543 
545 {
546  m_Slicer->Delete();
547  m_Plane->Delete();
548 
549  if (m_ScalarsToOpacity != nullptr)
550  m_ScalarsToOpacity->UnRegister(nullptr);
551  if (m_ScalarsToColors != nullptr)
552  m_ScalarsToColors->UnRegister(nullptr);
553  if (m_VtkPointSet != nullptr)
554  m_VtkPointSet->UnRegister(nullptr);
555 }
#define ls
Definition: MitkMCxyz.cpp:57
L * GetLocalStorage(mitk::BaseRenderer *forRenderer)
Retrieves a LocalStorage for a specific BaseRenderer.
Base class for mapper specific rendering ressources.
Definition: mitkMapper.h:193
void GenerateDataForRenderer(BaseRenderer *) override
Generate the data needed for rendering into renderer.
#define MITK_INFO
Definition: mitkLogMacros.h:18
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
virtual void SetSlicePlane(vtkPlane *)
LocalStorageHandler< BaseLocalStorage > m_LSH
static Pointer New()
Organizes the rendering process.
mitk::BoolProperty::Pointer m_ScalarVisibility
virtual const PlaneGeometry * GetCurrentWorldPlaneGeometry()
Get the current 2D-worldgeometry (m_CurrentWorldPlaneGeometry) used for 2D-rendering.
virtual vtkScalarsToColors * GetVtkLUT(BaseRenderer *renderer)
Base class of all Vtk Mappers in order to display primitives by exploiting Vtk functionality.
Definition: mitkVtkMapper.h:48
void WorldToDisplay(const Point3D &worldIndex, Point2D &displayPoint) const
This method converts a 3D world index to the display point using the geometry of the renderWindow...
void FillVector3D(Tout &out, mitk::ScalarType x, mitk::ScalarType y, mitk::ScalarType z)
Definition: mitkArray.h:106
static Pointer New()
mitk::ColorProperty::Pointer m_Color
BaseData * GetData() const
Get the data object (instance of BaseData, e.g., an Image) managed by this DataNode.
mitk::VtkScalarModeProperty::Pointer m_ScalarMode
virtual vtkAbstractMapper3D * GetVtkAbstractMapper3D(BaseRenderer *renderer)
void vnl2vtk(const vnl_vector< Tin > &in, Tout *out)
void ApplyColorAndOpacityProperties(mitk::BaseRenderer *renderer, vtkActor *actor=nullptr) override
Apply color and opacity properties read from the PropertyList. The actor is not used in the GLMappers...
bool GetVisibility(bool &visible, const mitk::BaseRenderer *renderer, const char *propertyKey="visible") const
Convenience access method for visibility properties (instances of BoolProperty with property-key "vis...
Definition: mitkDataNode.h:422
void vtk2itk(const Tin &in, Tout &out)
Describes a geometry defined by an vtkAbstractTransform and a plane.
vtkLinearTransform * GetVtkTransform(int t=0) const
Get the transformation applied prior to displaying the data as a vtkTransform.
itk::RGBPixel< float > Color
Color Standard RGB color typedef (float)
static Pointer New()
static vtkPointSetSlicer * New()
virtual bool IsConvertibleToVtkPointSet(BaseRenderer *renderer)
int GetTimestep() const
Returns the current time step as calculated from the renderer.
Definition: mitkMapper.h:147
virtual vtkPointSet * GetVtkPointSet(BaseRenderer *renderer, int time=0)
Class for storing unstructured grids (vtkUnstructuredGrid)
Describes a two-dimensional, rectangular plane.
void Paint(mitk::BaseRenderer *renderer) override