Medical Imaging Interaction Toolkit  2018.4.99-3e3f1a6e
Medical Imaging Interaction Toolkit
mitkImageVtkMapper2D.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 
13 // MITK
15 #include <mitkDataNode.h>
16 #include <mitkImageSliceSelector.h>
19 #include <mitkPixelType.h>
20 #include <mitkPlaneGeometry.h>
21 #include <mitkProperties.h>
22 #include <mitkPropertyNameHelper.h>
25 
26 //#include <mitkTransferFunction.h>
28 #include "mitkPlaneClipping.h"
30 
31 // MITK Rendering
32 #include "mitkImageVtkMapper2D.h"
36 
37 // VTK
38 #include <vtkCamera.h>
39 #include <vtkCellArray.h>
40 #include <vtkColorTransferFunction.h>
41 #include <vtkGeneralTransform.h>
42 #include <vtkImageChangeInformation.h>
43 #include <vtkImageData.h>
44 #include <vtkImageExtractComponents.h>
45 #include <vtkImageReslice.h>
46 #include <vtkLookupTable.h>
47 #include <vtkMatrix4x4.h>
48 #include <vtkPlaneSource.h>
49 #include <vtkPoints.h>
50 #include <vtkPolyDataMapper.h>
51 #include <vtkProperty.h>
52 #include <vtkTransform.h>
53 
54 // ITK
55 #include <itkRGBAPixel.h>
57 
59 {
60 }
61 
63 {
64  // The 3D RW Mapper (PlaneGeometryDataVtkMapper3D) is listening to this event,
65  // in order to delete the images from the 3D RW.
66  this->InvokeEvent(itk::DeleteEvent());
67 }
68 
69 // set the two points defining the textured plane according to the dimension and spacing
70 void mitk::ImageVtkMapper2D::GeneratePlane(mitk::BaseRenderer *renderer, double planeBounds[6])
71 {
72  LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer);
73 
74  float depth = this->CalculateLayerDepth(renderer);
75  // Set the origin to (xMin; yMin; depth) of the plane. This is necessary for obtaining the correct
76  // plane size in crosshair rotation and swivel mode.
77  localStorage->m_Plane->SetOrigin(planeBounds[0], planeBounds[2], depth);
78  // These two points define the axes of the plane in combination with the origin.
79  // Point 1 is the x-axis and point 2 the y-axis.
80  // Each plane is transformed according to the view (axial, coronal and saggital) afterwards.
81  localStorage->m_Plane->SetPoint1(planeBounds[1], planeBounds[2], depth); // P1: (xMax, yMin, depth)
82  localStorage->m_Plane->SetPoint2(planeBounds[0], planeBounds[3], depth); // P2: (xMin, yMax, depth)
83 }
84 
86 {
87  // get the clipping range to check how deep into z direction we can render images
88  double maxRange = renderer->GetVtkRenderer()->GetActiveCamera()->GetClippingRange()[1];
89 
90  // Due to a VTK bug, we cannot use the whole clipping range. /100 is empirically determined
91  float depth = -maxRange * 0.01; // divide by 100
92  int layer = 0;
93  GetDataNode()->GetIntProperty("layer", layer, renderer);
94  // add the layer property for each image to render images with a higher layer on top of the others
95  depth += layer * 10; //*10: keep some room for each image (e.g. for ODFs in between)
96  if (depth > 0.0f)
97  {
98  depth = 0.0f;
99  MITK_WARN << "Layer value exceeds clipping range. Set to minimum instead.";
100  }
101  return depth;
102 }
103 
105 {
106  return static_cast<const mitk::Image *>(GetDataNode()->GetData());
107 }
108 
110 {
111  // return the actor corresponding to the renderer
112  return m_LSH.GetLocalStorage(renderer)->m_Actors;
113 }
114 
116 {
117  LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer);
118 
119  auto *image = const_cast<mitk::Image *>(this->GetInput());
120  mitk::DataNode *datanode = this->GetDataNode();
121  if (nullptr == image || !image->IsInitialized())
122  {
123  return;
124  }
125 
126  // check if there is a valid worldGeometry
127  const PlaneGeometry *worldGeometry = renderer->GetCurrentWorldPlaneGeometry();
128  if (nullptr == worldGeometry || !worldGeometry->IsValid() || !worldGeometry->HasReferenceGeometry())
129  {
130  return;
131  }
132 
133  image->Update();
134 
135  // early out if there is no intersection of the current rendering geometry
136  // and the geometry of the image that is to be rendered.
137  if (!RenderingGeometryIntersectsImage(worldGeometry, image->GetSlicedGeometry()))
138  {
139  // set image to nullptr, to clear the texture in 3D, because
140  // the latest image is used there if the plane is out of the geometry
141  // see bug-13275
142  localStorage->m_ReslicedImage = nullptr;
143  localStorage->m_Mapper->SetInputData(localStorage->m_EmptyPolyData);
144  return;
145  }
146 
147  // set main input for ExtractSliceFilter
148  localStorage->m_Reslicer->SetInput(image);
149  localStorage->m_Reslicer->SetWorldGeometry(worldGeometry);
150  localStorage->m_Reslicer->SetTimeStep(this->GetTimestep());
151 
152  // set the transformation of the image to adapt reslice axis
153  localStorage->m_Reslicer->SetResliceTransformByGeometry(
154  image->GetTimeGeometry()->GetGeometryForTimeStep(this->GetTimestep()));
155 
156  // is the geometry of the slice based on the input image or the worldgeometry?
157  bool inPlaneResampleExtentByGeometry = false;
158  datanode->GetBoolProperty("in plane resample extent by geometry", inPlaneResampleExtentByGeometry, renderer);
159  localStorage->m_Reslicer->SetInPlaneResampleExtentByGeometry(inPlaneResampleExtentByGeometry);
160 
161  // Initialize the interpolation mode for resampling; switch to nearest
162  // neighbor if the input image is too small.
163  if ((image->GetDimension() >= 3) && (image->GetDimension(2) > 1))
164  {
165  VtkResliceInterpolationProperty *resliceInterpolationProperty;
166  datanode->GetProperty(resliceInterpolationProperty, "reslice interpolation", renderer);
167 
168  int interpolationMode = VTK_RESLICE_NEAREST;
169  if (resliceInterpolationProperty != nullptr)
170  {
171  interpolationMode = resliceInterpolationProperty->GetInterpolation();
172  }
173 
174  switch (interpolationMode)
175  {
176  case VTK_RESLICE_NEAREST:
177  localStorage->m_Reslicer->SetInterpolationMode(ExtractSliceFilter::RESLICE_NEAREST);
178  break;
179  case VTK_RESLICE_LINEAR:
180  localStorage->m_Reslicer->SetInterpolationMode(ExtractSliceFilter::RESLICE_LINEAR);
181  break;
182  case VTK_RESLICE_CUBIC:
183  localStorage->m_Reslicer->SetInterpolationMode(ExtractSliceFilter::RESLICE_CUBIC);
184  break;
185  }
186  }
187  else
188  {
189  localStorage->m_Reslicer->SetInterpolationMode(ExtractSliceFilter::RESLICE_NEAREST);
190  }
191 
192  // set the vtk output property to true, makes sure that no unneeded mitk image convertion
193  // is done.
194  localStorage->m_Reslicer->SetVtkOutputRequest(true);
195 
196  // Thickslicing
197  int thickSlicesMode = 0;
198  int thickSlicesNum = 1;
199  // Thick slices parameters
200  if (image->GetPixelType().GetNumberOfComponents() == 1) // for now only single component are allowed
201  {
202  DataNode *dn = renderer->GetCurrentWorldPlaneGeometryNode();
203  if (dn)
204  {
205  ResliceMethodProperty *resliceMethodEnumProperty = nullptr;
206 
207  if (dn->GetProperty(resliceMethodEnumProperty, "reslice.thickslices", renderer) && resliceMethodEnumProperty)
208  thickSlicesMode = resliceMethodEnumProperty->GetValueAsId();
209 
210  IntProperty *intProperty = nullptr;
211  if (dn->GetProperty(intProperty, "reslice.thickslices.num", renderer) && intProperty)
212  {
213  thickSlicesNum = intProperty->GetValue();
214  if (thickSlicesNum < 1)
215  thickSlicesNum = 1;
216  }
217  }
218  else
219  {
220  MITK_WARN << "no associated widget plane data tree node found";
221  }
222  }
223 
224  const auto *planeGeometry = dynamic_cast<const PlaneGeometry *>(worldGeometry);
225 
226  if (thickSlicesMode > 0)
227  {
228  double dataZSpacing = 1.0;
229 
230  Vector3D normInIndex, normal;
231 
232  const auto *abstractGeometry =
233  dynamic_cast<const AbstractTransformGeometry *>(worldGeometry);
234  if (abstractGeometry != nullptr)
235  normal = abstractGeometry->GetPlane()->GetNormal();
236  else
237  {
238  if (planeGeometry != nullptr)
239  {
240  normal = planeGeometry->GetNormal();
241  }
242  else
243  return; // no fitting geometry set
244  }
245  normal.Normalize();
246 
247  image->GetTimeGeometry()->GetGeometryForTimeStep(this->GetTimestep())->WorldToIndex(normal, normInIndex);
248 
249  dataZSpacing = 1.0 / normInIndex.GetNorm();
250 
251  localStorage->m_Reslicer->SetOutputDimensionality(3);
252  localStorage->m_Reslicer->SetOutputSpacingZDirection(dataZSpacing);
253  localStorage->m_Reslicer->SetOutputExtentZDirection(-thickSlicesNum, 0 + thickSlicesNum);
254 
255  // Do the reslicing. Modified() is called to make sure that the reslicer is
256  // executed even though the input geometry information did not change; this
257  // is necessary when the input /em data, but not the /em geometry changes.
258  localStorage->m_TSFilter->SetThickSliceMode(thickSlicesMode - 1);
259  localStorage->m_TSFilter->SetInputData(localStorage->m_Reslicer->GetVtkOutput());
260 
261  // vtkFilter=>mitkFilter=>vtkFilter update mechanism will fail without calling manually
262  localStorage->m_Reslicer->Modified();
263  localStorage->m_Reslicer->Update();
264 
265  localStorage->m_TSFilter->Modified();
266  localStorage->m_TSFilter->Update();
267  localStorage->m_ReslicedImage = localStorage->m_TSFilter->GetOutput();
268  }
269  else
270  {
271  // this is needed when thick mode was enable bevore. These variable have to be reset to default values
272  localStorage->m_Reslicer->SetOutputDimensionality(2);
273  localStorage->m_Reslicer->SetOutputSpacingZDirection(1.0);
274  localStorage->m_Reslicer->SetOutputExtentZDirection(0, 0);
275 
276  localStorage->m_Reslicer->Modified();
277  // start the pipeline with updating the largest possible, needed if the geometry of the input has changed
278  localStorage->m_Reslicer->UpdateLargestPossibleRegion();
279  localStorage->m_ReslicedImage = localStorage->m_Reslicer->GetVtkOutput();
280  }
281 
282  // Bounds information for reslicing (only reuqired if reference geometry
283  // is present)
284  // this used for generating a vtkPLaneSource with the right size
285  double sliceBounds[6];
286  for (auto &sliceBound : sliceBounds)
287  {
288  sliceBound = 0.0;
289  }
290  localStorage->m_Reslicer->GetClippedPlaneBounds(sliceBounds);
291 
292  // get the spacing of the slice
293  localStorage->m_mmPerPixel = localStorage->m_Reslicer->GetOutputSpacing();
294 
295  // calculate minimum bounding rect of IMAGE in texture
296  {
297  double textureClippingBounds[6];
298  for (auto &textureClippingBound : textureClippingBounds)
299  {
300  textureClippingBound = 0.0;
301  }
302  // Calculate the actual bounds of the transformed plane clipped by the
303  // dataset bounding box; this is required for drawing the texture at the
304  // correct position during 3D mapping.
305  mitk::PlaneClipping::CalculateClippedPlaneBounds(image->GetGeometry(), planeGeometry, textureClippingBounds);
306 
307  textureClippingBounds[0] = static_cast<int>(textureClippingBounds[0] / localStorage->m_mmPerPixel[0] + 0.5);
308  textureClippingBounds[1] = static_cast<int>(textureClippingBounds[1] / localStorage->m_mmPerPixel[0] + 0.5);
309  textureClippingBounds[2] = static_cast<int>(textureClippingBounds[2] / localStorage->m_mmPerPixel[1] + 0.5);
310  textureClippingBounds[3] = static_cast<int>(textureClippingBounds[3] / localStorage->m_mmPerPixel[1] + 0.5);
311 
312  // clipping bounds for cutting the image
313  localStorage->m_LevelWindowFilter->SetClippingBounds(textureClippingBounds);
314  }
315 
316  // get the number of scalar components to distinguish between different image types
317  int numberOfComponents = localStorage->m_ReslicedImage->GetNumberOfScalarComponents();
318  // get the binary property
319  bool binary = false;
320  bool binaryOutline = false;
321  datanode->GetBoolProperty("binary", binary, renderer);
322  if (binary) // binary image
323  {
324  datanode->GetBoolProperty("outline binary", binaryOutline, renderer);
325  if (binaryOutline) // contour rendering
326  {
327  // get pixel type of vtk image
328  itk::ImageIOBase::IOComponentType componentType = static_cast<itk::ImageIOBase::IOComponentType>(image->GetPixelType().GetComponentType());
329  switch (componentType)
330  {
331  case itk::ImageIOBase::UCHAR:
332  // generate contours/outlines
333  localStorage->m_OutlinePolyData = CreateOutlinePolyData<unsigned char>(renderer);
334  break;
335  case itk::ImageIOBase::USHORT:
336  // generate contours/outlines
337  localStorage->m_OutlinePolyData = CreateOutlinePolyData<unsigned short>(renderer);
338  break;
339  default:
340  binaryOutline = false;
341  this->ApplyLookuptable(renderer);
342  MITK_WARN << "Type of all binary images should be unsigned char or unsigned short. Outline does not work on other pixel types!";
343  }
344  if (binaryOutline) // binary outline is still true --> add outline
345  {
346  float binaryOutlineWidth = 1.0;
347  if (datanode->GetFloatProperty("outline width", binaryOutlineWidth, renderer))
348  {
349  if (localStorage->m_Actors->GetNumberOfPaths() > 1)
350  {
351  float binaryOutlineShadowWidth = 1.5;
352  datanode->GetFloatProperty("outline shadow width", binaryOutlineShadowWidth, renderer);
353 
354  dynamic_cast<vtkActor *>(localStorage->m_Actors->GetParts()->GetItemAsObject(0))
355  ->GetProperty()
356  ->SetLineWidth(binaryOutlineWidth * binaryOutlineShadowWidth);
357  }
358  localStorage->m_Actor->GetProperty()->SetLineWidth(binaryOutlineWidth);
359  }
360  }
361  }
362  else // standard binary image
363  {
364  if (numberOfComponents != 1)
365  {
366  MITK_ERROR << "Rendering Error: Binary Images with more then 1 component are not supported!";
367  }
368  }
369  }
370 
371  this->ApplyOpacity(renderer);
372  this->ApplyRenderingMode(renderer);
373 
374  // do not use a VTK lookup table (we do that ourselves in m_LevelWindowFilter)
375  localStorage->m_Texture->SetColorModeToDirectScalars();
376 
377  int displayedComponent = 0;
378 
379  if (datanode->GetIntProperty("Image.Displayed Component", displayedComponent, renderer) && numberOfComponents > 1)
380  {
381  localStorage->m_VectorComponentExtractor->SetComponents(displayedComponent);
382  localStorage->m_VectorComponentExtractor->SetInputData(localStorage->m_ReslicedImage);
383 
384  localStorage->m_LevelWindowFilter->SetInputConnection(localStorage->m_VectorComponentExtractor->GetOutputPort(0));
385  }
386  else
387  {
388  // connect the input with the levelwindow filter
389  localStorage->m_LevelWindowFilter->SetInputData(localStorage->m_ReslicedImage);
390  }
391 
392  // check for texture interpolation property
393  bool textureInterpolation = false;
394  GetDataNode()->GetBoolProperty("texture interpolation", textureInterpolation, renderer);
395 
396  // set the interpolation modus according to the property
397  localStorage->m_Texture->SetInterpolate(textureInterpolation);
398 
399  // connect the texture with the output of the levelwindow filter
400  localStorage->m_Texture->SetInputConnection(localStorage->m_LevelWindowFilter->GetOutputPort());
401 
402  this->TransformActor(renderer);
403 
404  auto *contourShadowActor = dynamic_cast<vtkActor *>(localStorage->m_Actors->GetParts()->GetItemAsObject(0));
405 
406  if (binary && binaryOutline) // connect the mapper with the polyData which contains the lines
407  {
408  // We need the contour for the binary outline property as actor
409  localStorage->m_Mapper->SetInputData(localStorage->m_OutlinePolyData);
410  localStorage->m_Actor->SetTexture(nullptr); // no texture for contours
411 
412  bool binaryOutlineShadow = false;
413  datanode->GetBoolProperty("outline binary shadow", binaryOutlineShadow, renderer);
414  if (binaryOutlineShadow)
415  {
416  contourShadowActor->SetVisibility(true);
417  }
418  else
419  {
420  contourShadowActor->SetVisibility(false);
421  }
422  }
423  else
424  { // Connect the mapper with the input texture. This is the standard case.
425  // setup the textured plane
426  this->GeneratePlane(renderer, sliceBounds);
427  // set the plane as input for the mapper
428  localStorage->m_Mapper->SetInputConnection(localStorage->m_Plane->GetOutputPort());
429  // set the texture for the actor
430 
431  localStorage->m_Actor->SetTexture(localStorage->m_Texture);
432  contourShadowActor->SetVisibility(false);
433  }
434 
435  // We have been modified => save this for next Update()
436  localStorage->m_LastUpdateTime.Modified();
437 }
438 
440 {
441  LocalStorage *localStorage = this->GetLocalStorage(renderer);
442 
443  LevelWindow levelWindow;
444  this->GetDataNode()->GetLevelWindow(levelWindow, renderer, "levelwindow");
445  localStorage->m_LevelWindowFilter->GetLookupTable()->SetRange(levelWindow.GetLowerWindowBound(),
446  levelWindow.GetUpperWindowBound());
447 
448  mitk::LevelWindow opacLevelWindow;
449  if (this->GetDataNode()->GetLevelWindow(opacLevelWindow, renderer, "opaclevelwindow"))
450  {
451  // pass the opaque level window to the filter
452  localStorage->m_LevelWindowFilter->SetMinOpacity(opacLevelWindow.GetLowerWindowBound());
453  localStorage->m_LevelWindowFilter->SetMaxOpacity(opacLevelWindow.GetUpperWindowBound());
454  }
455  else
456  {
457  // no opaque level window
458  localStorage->m_LevelWindowFilter->SetMinOpacity(0.0);
459  localStorage->m_LevelWindowFilter->SetMaxOpacity(255.0);
460  }
461 }
462 
464 {
465  LocalStorage *localStorage = this->GetLocalStorage(renderer);
466 
467  float rgb[3] = {1.0f, 1.0f, 1.0f};
468 
469  // check for color prop and use it for rendering if it exists
470  // binary image hovering & binary image selection
471  bool hover = false;
472  bool selected = false;
473  bool binary = false;
474  GetDataNode()->GetBoolProperty("binaryimage.ishovering", hover, renderer);
475  GetDataNode()->GetBoolProperty("selected", selected, renderer);
476  GetDataNode()->GetBoolProperty("binary", binary, renderer);
477  if (binary && hover && !selected)
478  {
479  mitk::ColorProperty::Pointer colorprop =
480  dynamic_cast<mitk::ColorProperty *>(GetDataNode()->GetProperty("binaryimage.hoveringcolor", renderer));
481  if (colorprop.IsNotNull())
482  {
483  memcpy(rgb, colorprop->GetColor().GetDataPointer(), 3 * sizeof(float));
484  }
485  else
486  {
487  GetDataNode()->GetColor(rgb, renderer, "color");
488  }
489  }
490  if (binary && selected)
491  {
492  mitk::ColorProperty::Pointer colorprop =
493  dynamic_cast<mitk::ColorProperty *>(GetDataNode()->GetProperty("binaryimage.selectedcolor", renderer));
494  if (colorprop.IsNotNull())
495  {
496  memcpy(rgb, colorprop->GetColor().GetDataPointer(), 3 * sizeof(float));
497  }
498  else
499  {
500  GetDataNode()->GetColor(rgb, renderer, "color");
501  }
502  }
503  if (!binary || (!hover && !selected))
504  {
505  GetDataNode()->GetColor(rgb, renderer, "color");
506  }
507 
508  double rgbConv[3] = {(double)rgb[0], (double)rgb[1], (double)rgb[2]}; // conversion to double for VTK
509  dynamic_cast<vtkActor *>(localStorage->m_Actors->GetParts()->GetItemAsObject(0))->GetProperty()->SetColor(rgbConv);
510  localStorage->m_Actor->GetProperty()->SetColor(rgbConv);
511 
512  if (localStorage->m_Actors->GetParts()->GetNumberOfItems() > 1)
513  {
514  float rgb[3] = {1.0f, 1.0f, 1.0f};
515  mitk::ColorProperty::Pointer colorprop =
516  dynamic_cast<mitk::ColorProperty *>(GetDataNode()->GetProperty("outline binary shadow color", renderer));
517  if (colorprop.IsNotNull())
518  {
519  memcpy(rgb, colorprop->GetColor().GetDataPointer(), 3 * sizeof(float));
520  }
521  double rgbConv[3] = {(double)rgb[0], (double)rgb[1], (double)rgb[2]}; // conversion to double for VTK
522  dynamic_cast<vtkActor *>(localStorage->m_Actors->GetParts()->GetItemAsObject(0))->GetProperty()->SetColor(rgbConv);
523  }
524 }
525 
527 {
528  LocalStorage *localStorage = this->GetLocalStorage(renderer);
529  float opacity = 1.0f;
530  // check for opacity prop and use it for rendering if it exists
531  GetDataNode()->GetOpacity(opacity, renderer, "opacity");
532  // set the opacity according to the properties
533  localStorage->m_Actor->GetProperty()->SetOpacity(opacity);
534  if (localStorage->m_Actors->GetParts()->GetNumberOfItems() > 1)
535  {
536  dynamic_cast<vtkActor *>(localStorage->m_Actors->GetParts()->GetItemAsObject(0))
537  ->GetProperty()
538  ->SetOpacity(opacity);
539  }
540 }
541 
543 {
544  LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer);
545 
546  bool binary = false;
547  this->GetDataNode()->GetBoolProperty("binary", binary, renderer);
548  if (binary) // is it a binary image?
549  {
550  // for binary images, we always use our default LuT and map every value to (0,1)
551  // the opacity of 0 will always be 0.0. We never a apply a LuT/TfF nor a level window.
552  localStorage->m_LevelWindowFilter->SetLookupTable(localStorage->m_BinaryLookupTable);
553  }
554  else
555  {
556  // all other image types can make use of the rendering mode
559  dynamic_cast<mitk::RenderingModeProperty *>(this->GetDataNode()->GetProperty("Image Rendering.Mode", renderer));
560  if (mode.IsNotNull())
561  {
562  renderingMode = mode->GetRenderingMode();
563  }
564  switch (renderingMode)
565  {
567  MITK_DEBUG << "'Image Rendering.Mode' = LevelWindow_LookupTable_Color";
568  this->ApplyLookuptable(renderer);
569  this->ApplyLevelWindow(renderer);
570  break;
572  MITK_DEBUG << "'Image Rendering.Mode' = LevelWindow_ColorTransferFunction_Color";
573  this->ApplyColorTransferFunction(renderer);
574  this->ApplyLevelWindow(renderer);
575  break;
577  MITK_DEBUG << "'Image Rendering.Mode' = LookupTable_Color";
578  this->ApplyLookuptable(renderer);
579  break;
581  MITK_DEBUG << "'Image Rendering.Mode' = ColorTransferFunction_Color";
582  this->ApplyColorTransferFunction(renderer);
583  break;
584  default:
585  MITK_ERROR << "No valid 'Image Rendering.Mode' set. Using LOOKUPTABLE_LEVELWINDOW_COLOR instead.";
586  this->ApplyLookuptable(renderer);
587  this->ApplyLevelWindow(renderer);
588  break;
589  }
590  }
591  // we apply color for all images (including binaries).
592  this->ApplyColor(renderer);
593 }
594 
596 {
597  LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer);
598  vtkLookupTable *usedLookupTable = localStorage->m_ColorLookupTable;
599 
600  // If lookup table or transferfunction use is requested...
601  mitk::LookupTableProperty::Pointer lookupTableProp =
602  dynamic_cast<mitk::LookupTableProperty *>(this->GetDataNode()->GetProperty("LookupTable", renderer));
603 
604  if (lookupTableProp.IsNotNull()) // is a lookuptable set?
605  {
606  usedLookupTable = lookupTableProp->GetLookupTable()->GetVtkLookupTable();
607  }
608  else
609  {
610  //"Image Rendering.Mode was set to use a lookup table but there is no property 'LookupTable'.
611  // A default (rainbow) lookup table will be used.
612  // Here have to do nothing. Warning for the user has been removed, due to unwanted console output
613  // in every interation of the rendering.
614  }
615  localStorage->m_LevelWindowFilter->SetLookupTable(usedLookupTable);
616 }
617 
619 {
620  mitk::TransferFunctionProperty::Pointer transferFunctionProp = dynamic_cast<mitk::TransferFunctionProperty *>(
621  this->GetDataNode()->GetProperty("Image Rendering.Transfer Function", renderer));
622 
623  if (transferFunctionProp.IsNull())
624  {
625  MITK_ERROR << "'Image Rendering.Mode'' was set to use a color transfer function but there is no property 'Image "
626  "Rendering.Transfer Function'. Nothing will be done.";
627  return;
628  }
629  LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer);
630  // pass the transfer function to our level window filter
631  localStorage->m_LevelWindowFilter->SetLookupTable(transferFunctionProp->GetValue()->GetColorTransferFunction());
632  localStorage->m_LevelWindowFilter->SetOpacityPiecewiseFunction(
633  transferFunctionProp->GetValue()->GetScalarOpacityFunction());
634 }
635 
637 {
638  bool visible = true;
639  GetDataNode()->GetVisibility(visible, renderer, "visible");
640 
641  if (!visible)
642  {
643  return;
644  }
645 
646  auto *data = const_cast<mitk::Image *>(this->GetInput());
647  if (data == nullptr)
648  {
649  return;
650  }
651 
652  // Calculate time step of the input data for the specified renderer (integer value)
653  this->CalculateTimeStep(renderer);
654 
655  // Check if time step is valid
656  const TimeGeometry *dataTimeGeometry = data->GetTimeGeometry();
657  if ((dataTimeGeometry == nullptr) || (dataTimeGeometry->CountTimeSteps() == 0) ||
658  (!dataTimeGeometry->IsValidTimeStep(this->GetTimestep())))
659  {
660  return;
661  }
662 
663  const DataNode *node = this->GetDataNode();
664  data->UpdateOutputInformation();
665  LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer);
666 
667  // check if something important has changed and we need to rerender
668  if ((localStorage->m_LastUpdateTime < node->GetMTime()) ||
669  (localStorage->m_LastUpdateTime < data->GetPipelineMTime()) ||
670  (localStorage->m_LastUpdateTime < renderer->GetCurrentWorldPlaneGeometryUpdateTime()) ||
671  (localStorage->m_LastUpdateTime < renderer->GetCurrentWorldPlaneGeometry()->GetMTime()) ||
672  (localStorage->m_LastUpdateTime < node->GetPropertyList()->GetMTime()) ||
673  (localStorage->m_LastUpdateTime < node->GetPropertyList(renderer)->GetMTime()) ||
674  (localStorage->m_LastUpdateTime < data->GetPropertyList()->GetMTime()))
675  {
676  this->GenerateDataForRenderer(renderer);
677  }
678 
679  // since we have checked that nothing important has changed, we can set
680  // m_LastUpdateTime to the current time
681  localStorage->m_LastUpdateTime.Modified();
682 }
683 
685 {
686  mitk::Image::Pointer image = dynamic_cast<mitk::Image *>(node->GetData());
687 
688  // Properties common for both images and segmentations
689  node->AddProperty("depthOffset", mitk::FloatProperty::New(0.0), renderer, overwrite);
690  node->AddProperty("outline binary", mitk::BoolProperty::New(false), renderer, overwrite);
691  node->AddProperty("outline width", mitk::FloatProperty::New(1.0), renderer, overwrite);
692  node->AddProperty("outline binary shadow", mitk::BoolProperty::New(false), renderer, overwrite);
693  node->AddProperty("outline binary shadow color", ColorProperty::New(0.0, 0.0, 0.0), renderer, overwrite);
694  node->AddProperty("outline shadow width", mitk::FloatProperty::New(1.5), renderer, overwrite);
695  if (image->IsRotated())
696  node->AddProperty("reslice interpolation", mitk::VtkResliceInterpolationProperty::New(VTK_RESLICE_CUBIC));
697  else
698  node->AddProperty("reslice interpolation", mitk::VtkResliceInterpolationProperty::New());
699  node->AddProperty("texture interpolation", mitk::BoolProperty::New(false));
700  node->AddProperty("in plane resample extent by geometry", mitk::BoolProperty::New(false));
701  node->AddProperty("bounding box", mitk::BoolProperty::New(false));
702 
704  node->AddProperty("Image Rendering.Mode", renderingModeProperty);
705 
706  // Set default grayscale look-up table
708  mitkLut->SetType(mitk::LookupTable::GRAYSCALE);
710  mitkLutProp->SetLookupTable(mitkLut);
711  node->SetProperty("LookupTable", mitkLutProp, renderer);
712 
713  std::string photometricInterpretation; // DICOM tag telling us how pixel values should be displayed
714  if (node->GetStringProperty("dicom.pixel.PhotometricInterpretation", photometricInterpretation))
715  {
716  // modality provided by DICOM or other reader
717  if (photometricInterpretation.find("MONOCHROME1") != std::string::npos) // meaning: display MINIMUM pixels as WHITE
718  {
719  // Set inverse grayscale look-up table
720  mitkLut->SetType(mitk::LookupTable::INVERSE_GRAYSCALE);
721  mitkLutProp->SetLookupTable(mitkLut);
722  node->SetProperty("LookupTable", mitkLutProp, renderer);
723  renderingModeProperty->SetValue(mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR); // USE lookuptable
724  }
725  // Otherwise do nothing - the default grayscale look-up table has already been set
726  }
727 
728  bool isBinaryImage(false);
729  if (!node->GetBoolProperty("binary", isBinaryImage) && image->GetPixelType().GetNumberOfComponents() == 1)
730  {
731  // ok, property is not set, use heuristic to determine if this
732  // is a binary image
733  mitk::Image::Pointer centralSliceImage;
734  ScalarType minValue = 0.0;
735  ScalarType maxValue = 0.0;
736  ScalarType min2ndValue = 0.0;
737  ScalarType max2ndValue = 0.0;
739 
740  sliceSelector->SetInput(image);
741  sliceSelector->SetSliceNr(image->GetDimension(2) / 2);
742  sliceSelector->SetTimeNr(image->GetDimension(3) / 2);
743  sliceSelector->SetChannelNr(image->GetDimension(4) / 2);
744  sliceSelector->Update();
745  centralSliceImage = sliceSelector->GetOutput();
746  if (centralSliceImage.IsNotNull() && centralSliceImage->IsInitialized())
747  {
748  minValue = centralSliceImage->GetStatistics()->GetScalarValueMin();
749  maxValue = centralSliceImage->GetStatistics()->GetScalarValueMax();
750  min2ndValue = centralSliceImage->GetStatistics()->GetScalarValue2ndMin();
751  max2ndValue = centralSliceImage->GetStatistics()->GetScalarValue2ndMax();
752  }
753  if ((maxValue == min2ndValue && minValue == max2ndValue) || minValue == maxValue)
754  {
755  // centralSlice is strange, lets look at all data
756  minValue = image->GetStatistics()->GetScalarValueMin();
757  maxValue = image->GetStatistics()->GetScalarValueMaxNoRecompute();
758  min2ndValue = image->GetStatistics()->GetScalarValue2ndMinNoRecompute();
759  max2ndValue = image->GetStatistics()->GetScalarValue2ndMaxNoRecompute();
760  }
761  isBinaryImage = (maxValue == min2ndValue && minValue == max2ndValue);
762  }
763 
764  std::string className = image->GetNameOfClass();
765  if (className != "TensorImage" && className != "OdfImage" && className != "ShImage")
766  {
767  PixelType pixelType = image->GetPixelType();
768  size_t numComponents = pixelType.GetNumberOfComponents();
769 
770  if ((pixelType.GetPixelType() == itk::ImageIOBase::VECTOR && numComponents > 1) || numComponents == 2 ||
771  numComponents > 4)
772  {
773  node->AddProperty("Image.Displayed Component", mitk::IntProperty::New(0), renderer, overwrite);
774  }
775  }
776 
777  // some more properties specific for a binary...
778  if (isBinaryImage)
779  {
780  node->AddProperty("opacity", mitk::FloatProperty::New(0.3f), renderer, overwrite);
781  node->AddProperty("color", ColorProperty::New(1.0, 0.0, 0.0), renderer, overwrite);
782  node->AddProperty("binaryimage.selectedcolor", ColorProperty::New(1.0, 0.0, 0.0), renderer, overwrite);
783  node->AddProperty("binaryimage.selectedannotationcolor", ColorProperty::New(1.0, 0.0, 0.0), renderer, overwrite);
784  node->AddProperty("binaryimage.hoveringcolor", ColorProperty::New(1.0, 0.0, 0.0), renderer, overwrite);
785  node->AddProperty("binaryimage.hoveringannotationcolor", ColorProperty::New(1.0, 0.0, 0.0), renderer, overwrite);
786  node->AddProperty("binary", mitk::BoolProperty::New(true), renderer, overwrite);
787  node->AddProperty("layer", mitk::IntProperty::New(10), renderer, overwrite);
788  }
789  else //...or image type object
790  {
791  node->AddProperty("opacity", mitk::FloatProperty::New(1.0f), renderer, overwrite);
792  node->AddProperty("color", ColorProperty::New(1.0, 1.0, 1.0), renderer, overwrite);
793  node->AddProperty("binary", mitk::BoolProperty::New(false), renderer, overwrite);
794  node->AddProperty("layer", mitk::IntProperty::New(0), renderer, overwrite);
795  }
796 
797  if (image.IsNotNull() && image->IsInitialized())
798  {
799  if ((overwrite) || (node->GetProperty("levelwindow", renderer) == nullptr))
800  {
801  /* initialize level/window from DICOM tags */
802  mitk::LevelWindow contrast;
803 
804  std::string sLevel = "";
805  std::string sWindow = "";
807  0x0028, 0x1050, "dicom.voilut.WindowCenter", image->GetPropertyList(), sLevel) &&
809  0x0028, 0x1051, "dicom.voilut.WindowWidth", image->GetPropertyList(), sWindow))
810  {
811  float level = atof(sLevel.c_str());
812  float window = atof(sWindow.c_str());
813 
814  std::string sSmallestPixelValueInSeries;
815  std::string sLargestPixelValueInSeries;
816 
818  0x0108,
819  "dicom.series.SmallestPixelValueInSeries",
820  image->GetPropertyList(),
821  sSmallestPixelValueInSeries) &&
823  0x0109,
824  "dicom.series.LargestPixelValueInSeries",
825  image->GetPropertyList(),
826  sLargestPixelValueInSeries))
827  {
828  float smallestPixelValueInSeries = atof(sSmallestPixelValueInSeries.c_str());
829  float largestPixelValueInSeries = atof(sLargestPixelValueInSeries.c_str());
830  contrast.SetRangeMinMax(smallestPixelValueInSeries - 1,
831  largestPixelValueInSeries + 1); // why not a little buffer?
832  // might remedy some l/w widget challenges
833  }
834  else
835  {
836  contrast.SetAuto(static_cast<mitk::Image *>(node->GetData()), false, true); // fallback
837  }
838  contrast.SetLevelWindow(level, window, true);
839  }
840  else
841  {
842  contrast.SetAuto(static_cast<mitk::Image *>(node->GetData()), false, true); // fallback
843  }
844 
845  node->SetProperty("levelwindow", LevelWindowProperty::New(contrast), renderer);
846  }
847 
848  if (((overwrite) || (node->GetProperty("opaclevelwindow", renderer) == nullptr)) &&
849  (image->GetPixelType().GetPixelType() == itk::ImageIOBase::RGBA) &&
850  (image->GetPixelType().GetComponentType() == itk::ImageIOBase::UCHAR))
851  {
852  mitk::LevelWindow opaclevwin;
853  opaclevwin.SetRangeMinMax(0, 255);
854  opaclevwin.SetWindowBounds(0, 255);
856  node->SetProperty("opaclevelwindow", prop, renderer);
857  }
858  }
859  Superclass::SetDefaultProperties(node, renderer, overwrite);
860 }
861 
863 {
864  return m_LSH.GetLocalStorage(renderer);
865 }
866 
867 template <typename TPixel>
869 {
870  LocalStorage *localStorage = this->GetLocalStorage(renderer);
871 
872  // get the min and max index values of each direction
873  int *extent = localStorage->m_ReslicedImage->GetExtent();
874  int xMin = extent[0];
875  int xMax = extent[1];
876  int yMin = extent[2];
877  int yMax = extent[3];
878 
879  int *dims = localStorage->m_ReslicedImage->GetDimensions(); // dimensions of the image
880  int line = dims[0]; // how many pixels per line?
881  int x = xMin; // pixel index x
882  int y = yMin; // pixel index y
883 
884  // get the depth for each contour
885  float depth = CalculateLayerDepth(renderer);
886 
887  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New(); // the points to draw
888  vtkSmartPointer<vtkCellArray> lines = vtkSmartPointer<vtkCellArray>::New(); // the lines to connect the points
889 
890  // We take the pointer to the first pixel of the image
891  auto* currentPixel = static_cast<TPixel*>(localStorage->m_ReslicedImage->GetScalarPointer());
892 
893  while (y <= yMax)
894  {
895  // if the current pixel value is set to something
896  if ((currentPixel) && (*currentPixel != 0))
897  {
898  // check in which direction a line is necessary
899  // a line is added if the neighbor of the current pixel has the value 0
900  // and if the pixel is located at the edge of the image
901 
902  // if vvvvv not the first line vvvvv
903  if (y > yMin && *(currentPixel - line) == 0)
904  { // x direction - bottom edge of the pixel
905  // add the 2 points
906  vtkIdType p1 =
907  points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth);
908  vtkIdType p2 =
909  points->InsertNextPoint((x + 1) * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth);
910  // add the line between both points
911  lines->InsertNextCell(2);
912  lines->InsertCellPoint(p1);
913  lines->InsertCellPoint(p2);
914  }
915 
916  // if vvvvv not the last line vvvvv
917  if (y < yMax && *(currentPixel + line) == 0)
918  { // x direction - top edge of the pixel
919  vtkIdType p1 =
920  points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth);
921  vtkIdType p2 = points->InsertNextPoint(
922  (x + 1) * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth);
923  lines->InsertNextCell(2);
924  lines->InsertCellPoint(p1);
925  lines->InsertCellPoint(p2);
926  }
927 
928  // if vvvvv not the first pixel vvvvv
929  if ((x > xMin || y > yMin) && *(currentPixel - 1) == 0)
930  { // y direction - left edge of the pixel
931  vtkIdType p1 =
932  points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth);
933  vtkIdType p2 =
934  points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth);
935  lines->InsertNextCell(2);
936  lines->InsertCellPoint(p1);
937  lines->InsertCellPoint(p2);
938  }
939 
940  // if vvvvv not the last pixel vvvvv
941  if ((y < yMax || (x < xMax)) && *(currentPixel + 1) == 0)
942  { // y direction - right edge of the pixel
943  vtkIdType p1 =
944  points->InsertNextPoint((x + 1) * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth);
945  vtkIdType p2 = points->InsertNextPoint(
946  (x + 1) * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth);
947  lines->InsertNextCell(2);
948  lines->InsertCellPoint(p1);
949  lines->InsertCellPoint(p2);
950  }
951 
952  /* now consider pixels at the edge of the image */
953 
954  // if vvvvv left edge of image vvvvv
955  if (x == xMin)
956  { // draw left edge of the pixel
957  vtkIdType p1 =
958  points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth);
959  vtkIdType p2 =
960  points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth);
961  lines->InsertNextCell(2);
962  lines->InsertCellPoint(p1);
963  lines->InsertCellPoint(p2);
964  }
965 
966  // if vvvvv right edge of image vvvvv
967  if (x == xMax)
968  { // draw right edge of the pixel
969  vtkIdType p1 =
970  points->InsertNextPoint((x + 1) * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth);
971  vtkIdType p2 = points->InsertNextPoint(
972  (x + 1) * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth);
973  lines->InsertNextCell(2);
974  lines->InsertCellPoint(p1);
975  lines->InsertCellPoint(p2);
976  }
977 
978  // if vvvvv bottom edge of image vvvvv
979  if (y == yMin)
980  { // draw bottom edge of the pixel
981  vtkIdType p1 =
982  points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth);
983  vtkIdType p2 =
984  points->InsertNextPoint((x + 1) * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth);
985  lines->InsertNextCell(2);
986  lines->InsertCellPoint(p1);
987  lines->InsertCellPoint(p2);
988  }
989 
990  // if vvvvv top edge of image vvvvv
991  if (y == yMax)
992  { // draw top edge of the pixel
993  vtkIdType p1 =
994  points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth);
995  vtkIdType p2 = points->InsertNextPoint(
996  (x + 1) * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth);
997  lines->InsertNextCell(2);
998  lines->InsertCellPoint(p1);
999  lines->InsertCellPoint(p2);
1000  }
1001  } // end if currentpixel is set
1002 
1003  x++;
1004 
1005  if (x > xMax)
1006  { // reached end of line
1007  x = xMin;
1008  y++;
1009  }
1010 
1011  // Increase the pointer-position to the next pixel.
1012  // This is safe, as the while-loop and the x-reset logic above makes
1013  // sure we do not exceed the bounds of the image
1014  currentPixel++;
1015  } // end of while
1016 
1017  // Create a polydata to store everything in
1018  vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
1019  // Add the points to the dataset
1020  polyData->SetPoints(points);
1021  // Add the lines to the dataset
1022  polyData->SetLines(lines);
1023  return polyData;
1024 }
1025 
1027 {
1028  LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer);
1029  // get the transformation matrix of the reslicer in order to render the slice as axial, coronal or saggital
1030  vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
1031  vtkSmartPointer<vtkMatrix4x4> matrix = localStorage->m_Reslicer->GetResliceAxes();
1032  trans->SetMatrix(matrix);
1033  // transform the plane/contour (the actual actor) to the corresponding view (axial, coronal or saggital)
1034  localStorage->m_Actor->SetUserTransform(trans);
1035  // transform the origin to center based coordinates, because MITK is center based.
1036  localStorage->m_Actor->SetPosition(-0.5 * localStorage->m_mmPerPixel[0], -0.5 * localStorage->m_mmPerPixel[1], 0.0);
1037 
1038  if (localStorage->m_Actors->GetNumberOfPaths() > 1)
1039  {
1040  auto *secondaryActor = dynamic_cast<vtkActor *>(localStorage->m_Actors->GetParts()->GetItemAsObject(0));
1041  secondaryActor->SetUserTransform(trans);
1042  secondaryActor->SetPosition(-0.5 * localStorage->m_mmPerPixel[0], -0.5 * localStorage->m_mmPerPixel[1], 0.0);
1043  }
1044 }
1045 
1047  SlicedGeometry3D *imageGeometry)
1048 {
1049  // if either one of the two geometries is nullptr we return true
1050  // for safety reasons
1051  if (renderingGeometry == nullptr || imageGeometry == nullptr)
1052  return true;
1053 
1054  // get the distance for the first cornerpoint
1055  ScalarType initialDistance = renderingGeometry->SignedDistance(imageGeometry->GetCornerPoint(0));
1056  for (int i = 1; i < 8; i++)
1057  {
1058  mitk::Point3D cornerPoint = imageGeometry->GetCornerPoint(i);
1059 
1060  // get the distance to the other cornerpoints
1061  ScalarType distance = renderingGeometry->SignedDistance(cornerPoint);
1062 
1063  // if it has not the same signing as the distance of the first point
1064  if (initialDistance * distance < 0)
1065  {
1066  // we have an intersection and return true
1067  return true;
1068  }
1069  }
1070 
1071  // all distances have the same sign, no intersection and we return false
1072  return false;
1073 }
1074 
1076 {
1077 }
1078 
1080  : m_VectorComponentExtractor(vtkSmartPointer<vtkImageExtractComponents>::New())
1081 {
1082  m_LevelWindowFilter = vtkSmartPointer<vtkMitkLevelWindowFilter>::New();
1083 
1084  // Do as much actions as possible in here to avoid double executions.
1085  m_Plane = vtkSmartPointer<vtkPlaneSource>::New();
1086  m_Texture = vtkSmartPointer<vtkNeverTranslucentTexture>::New().GetPointer();
1087  m_DefaultLookupTable = vtkSmartPointer<vtkLookupTable>::New();
1088  m_BinaryLookupTable = vtkSmartPointer<vtkLookupTable>::New();
1089  m_ColorLookupTable = vtkSmartPointer<vtkLookupTable>::New();
1090  m_Mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
1091  m_Actor = vtkSmartPointer<vtkActor>::New();
1092  m_Actors = vtkSmartPointer<vtkPropAssembly>::New();
1094  m_TSFilter = vtkSmartPointer<vtkMitkThickSlicesFilter>::New();
1095  m_OutlinePolyData = vtkSmartPointer<vtkPolyData>::New();
1096  m_ReslicedImage = vtkSmartPointer<vtkImageData>::New();
1097  m_EmptyPolyData = vtkSmartPointer<vtkPolyData>::New();
1098 
1099  // the following actions are always the same and thus can be performed
1100  // in the constructor for each image (i.e. the image-corresponding local storage)
1101  m_TSFilter->ReleaseDataFlagOn();
1102 
1104  // built a default lookuptable
1105  mitkLUT->SetType(mitk::LookupTable::GRAYSCALE);
1106  m_DefaultLookupTable = mitkLUT->GetVtkLookupTable();
1107 
1108  mitkLUT->SetType(mitk::LookupTable::LEGACY_BINARY);
1109  m_BinaryLookupTable = mitkLUT->GetVtkLookupTable();
1110 
1111  mitkLUT->SetType(mitk::LookupTable::LEGACY_RAINBOW_COLOR);
1112  m_ColorLookupTable = mitkLUT->GetVtkLookupTable();
1113 
1114  // do not repeat the texture (the image)
1115  m_Texture->RepeatOff();
1116 
1117  // set the mapper for the actor
1118  m_Actor->SetMapper(m_Mapper);
1119 
1120  vtkSmartPointer<vtkActor> outlineShadowActor = vtkSmartPointer<vtkActor>::New();
1121  outlineShadowActor->SetMapper(m_Mapper);
1122 
1123  m_Actors->AddPart(outlineShadowActor);
1124  m_Actors->AddPart(m_Actor);
1125 }
void SetWindowBounds(ScalarType lowerBound, ScalarType upperBound, bool expandRangesIfNecessary=true)
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...
virtual IdType GetValueAsId() const
float CalculateLayerDepth(mitk::BaseRenderer *renderer)
This method uses the vtkCamera clipping range and the layer property to calcualte the depth of the ob...
virtual ScalarType SignedDistance(const Point3D &pt3d_mm) const
itk::TimeStamp m_LastUpdateTime
Timestamp of last update of stored data.
The TransferFunctionProperty class Property class for the mitk::TransferFunction. ...
virtual DataNode * GetCurrentWorldPlaneGeometryNode()
Get a DataNode pointing to a data object containing the current 2D-worldgeometry. ...
L * GetLocalStorage(mitk::BaseRenderer *forRenderer)
Retrieves a LocalStorage for a specific BaseRenderer.
static char * line
Definition: svm.cpp:2870
virtual TimeStepType CountTimeSteps() const =0
Returns the number of time steps.
void ApplyRenderingMode(mitk::BaseRenderer *renderer)
This method switches between different rendering modes (e.g. use a lookup table or a transfer functio...
unsigned long GetMTime() const override
Get the timestamp of the last change of the map or the last change of one of the properties store in ...
vtkSmartPointer< vtkActor > m_Actor
Actor of a 2D render window.
void ApplyLookuptable(mitk::BaseRenderer *renderer)
This method applies (or modifies) the lookuptable for all types of images.
void ApplyOpacity(mitk::BaseRenderer *renderer)
Set the opacity of the actor.
static Pointer New()
vtkRenderer * GetVtkRenderer() const
bool GetStringProperty(const char *propertyKey, std::string &string, const mitk::BaseRenderer *renderer=nullptr) const
Convenience access method for string properties (instances of StringProperty)
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
#define MITK_ERROR
Definition: mitkLogMacros.h:20
vtkSmartPointer< vtkImageExtractComponents > m_VectorComponentExtractor
double ScalarType
vcl_size_t GetNumberOfComponents() const
Get the number of components of which each element consists.
void Update(mitk::BaseRenderer *renderer) override
Checks whether this mapper needs to update itself and generate data.
static bool CalculateClippedPlaneBounds(const BaseGeometry *boundingGeometry, const PlaneGeometry *planeGeometry, double *bounds)
Calculate the bounding box of the resliced image. This is necessary for arbitrarily rotated planes in...
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.
LocalStorage * GetLocalStorage(mitk::BaseRenderer *renderer)
Get the LocalStorage corresponding to the current renderer.
#define MITK_DEBUG
Definition: mitkLogMacros.h:22
Point3D GetCornerPoint(int id) const
Get the position of the corner number id (in world coordinates)
static Pointer New()
bool RenderingGeometryIntersectsImage(const PlaneGeometry *renderingGeometry, SlicedGeometry3D *imageGeometry)
Calculates whether the given rendering geometry intersects the given SlicedGeometry3D.
virtual const PlaneGeometry * GetCurrentWorldPlaneGeometry()
Get the current 2D-worldgeometry (m_CurrentWorldPlaneGeometry) used for 2D-rendering.
static Pointer New()
unsigned long GetMTime() const override
Get the timestamp of the last change of the contents of this node or the referenced BaseData...
bool GetBoolProperty(const char *propertyKey, bool &boolValue, const mitk::BaseRenderer *renderer=nullptr) const
Convenience access method for bool properties (instances of BoolProperty)
bool GetOpacity(float &opacity, const mitk::BaseRenderer *renderer, const char *propertyKey="opacity") const
Convenience access method for opacity properties (instances of FloatProperty)
bool GetIntProperty(const char *propertyKey, int &intValue, const mitk::BaseRenderer *renderer=nullptr) const
Convenience access method for int properties (instances of IntProperty)
void ApplyColorTransferFunction(mitk::BaseRenderer *renderer)
This method applies a color transfer function. Internally, a vtkColorTransferFunction is used...
vtkSmartPointer< vtkLookupTable > m_ColorLookupTable
mitk::LocalStorageHandler< LocalStorage > m_LSH
The LocalStorageHandler holds all (three) LocalStorages for the three 2D render windows.
vtkSmartPointer< vtkPropAssembly > m_Actors
~LocalStorage() override
Default deconstructor of the local storage.
void SetRangeMinMax(ScalarType min, ScalarType max)
virtual T GetValue() const
The LevelWindow class Class to store level/window values.
static Pointer New()
bool HasReferenceGeometry() const
void SetProperty(const std::string &propertyKey, BaseProperty *property, const std::string &contextName="", bool fallBackOnDefaultContext=false) override
Add new or change existent property.
vtkProp * GetVtkProp(mitk::BaseRenderer *renderer) override
vtkSmartPointer< vtkLookupTable > m_DefaultLookupTable
The lookuptables for colors and level window.
vtkSmartPointer< vtkPolyData > m_OutlinePolyData
PolyData object containg all lines/points needed for outlining the contour. This container is used to...
The ColorProperty class RGB color property.
BaseData * GetData() const
Get the data object (instance of BaseData, e.g., an Image) managed by this DataNode.
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 ...
#define MITK_WARN
Definition: mitkLogMacros.h:19
The LookupTableProperty class Property to associate mitk::LookupTable to an mitk::DataNode.
bool GetColor(float rgb[3], const mitk::BaseRenderer *renderer=nullptr, const char *propertyKey="color") const
Convenience access method for color properties (instances of ColorProperty)
vtkSmartPointer< vtkMitkLevelWindowFilter > m_LevelWindowFilter
This filter is used to apply the level window to Grayvalue and RBG(A) images.
void GenerateDataForRenderer(mitk::BaseRenderer *renderer) override
Does the actual resampling, without rendering the image yet. All the data is generated inside this me...
static Pointer New()
ScalarType GetUpperWindowBound() const
mitk::ScalarType * m_mmPerPixel
mmPerPixel relation between pixel and mm. (World spacing).
const mitk::Image * GetInput(void)
Get the Image to map.
vtkSmartPointer< vtkPolyDataMapper > m_Mapper
Mapper of a 2D render window.
Image class for storing images.
Definition: mitkImage.h:72
vtkSmartPointer< vtkPolyData > m_EmptyPolyData
Empty vtkPolyData that is set when rendering geometry does not intersect the image geometry...
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 SetAuto(const Image *image, bool tryPicTags=true, bool guessByCentralSlice=true, unsigned selectedComponent=0)
sets level/window to optimize the contrast of the given Image
void ApplyLevelWindow(mitk::BaseRenderer *renderer)
ApplyLevelWindow Apply the level window for the given renderer.
vtkSmartPointer< vtkTexture > m_Texture
The texture which is used to render the current slice.
Describes a geometry defined by an vtkAbstractTransform and a plane.
void ApplyColor(mitk::BaseRenderer *renderer)
Set the color of the image/polydata.
virtual void CalculateTimeStep(BaseRenderer *renderer)
Updates the time step, which is sometimes needed in subclasses.
Definition: mitkMapper.cpp:79
itk::ImageIOBase::IOPixelType GetPixelType() const
mitk::Image::Pointer image
vtkSmartPointer< vtkMitkThickSlicesFilter > m_TSFilter
Filter for thick slices.
static void SetDefaultProperties(mitk::DataNode *node, mitk::BaseRenderer *renderer=nullptr, bool overwrite=false)
Set the default properties for general image rendering.
Describes the geometry of a data object consisting of slices.
void TransformActor(mitk::BaseRenderer *renderer)
Transforms the actor to the actual position in 3D.
static Pointer New()
virtual bool IsValid() const
Is this BaseGeometry in a state that is valid?
mitk::PropertyList * GetPropertyList(const mitk::BaseRenderer *renderer=nullptr) const
Get the PropertyList of the renderer. If renderer is nullptr, the BaseRenderer-independent PropertyLi...
vtkSmartPointer< vtkLookupTable > m_BinaryLookupTable
static Pointer New()
Internal class holding the mapper, actor, etc. for each of the 3 2D render windows.
int GetTimestep() const
Returns the current time step as calculated from the renderer.
Definition: mitkMapper.h:147
vtkSmartPointer< vtkPolyData > CreateOutlinePolyData(mitk::BaseRenderer *renderer)
Generates a vtkPolyData object containing the outline of a given binary slice.
static Pointer New()
unsigned long GetCurrentWorldPlaneGeometryUpdateTime()
Get timestamp of last call of SetCurrentWorldPlaneGeometry.
Describes a two-dimensional, rectangular plane.
void GeneratePlane(mitk::BaseRenderer *renderer, double planeBounds[6])
Generates a plane according to the size of the resliced image in milimeters.
void SetLevelWindow(ScalarType level, ScalarType window, bool expandRangesIfNecessary=true)
vtkSmartPointer< vtkPlaneSource > m_Plane
Plane on which the slice is rendered as texture.
static Pointer New()
bool GetLevelWindow(mitk::LevelWindow &levelWindow, const mitk::BaseRenderer *renderer=nullptr, const char *propertyKey="levelwindow") const
Convenience access method for level-window properties (instances of LevelWindowProperty) ...
ScalarType GetLowerWindowBound() const
bool MITKCORE_EXPORT GetBackwardsCompatibleDICOMProperty(unsigned int group, unsigned int element, std::string const &backwardsCompatiblePropertyName, PropertyList const *propertyList, std::string &propertyValue)
virtual bool IsValidTimeStep(TimeStepType timeStep) const =0
Test for the given time step if a geometry is availible.
LocalStorage()
Default constructor of the local storage.
Class for nodes of the DataTree.
Definition: mitkDataNode.h:57
Class for defining the data type of pixels.
Definition: mitkPixelType.h:51
mitk::ExtractSliceFilter::Pointer m_Reslicer
The actual reslicer (one per renderer)
static void SetDefaultProperties(DataNode *node, BaseRenderer *renderer=nullptr, bool overwrite=false)
Set default values of properties used by this mapper to node.
Definition: mitkMapper.cpp:143
vtkSmartPointer< vtkImageData > m_ReslicedImage
Current slice of a 2D render window.