Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
mitkBoundingShapeVtkMapper2D.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 detailocalStorage.
14 
15 ===================================================================*/
16 
17 #include "../DataManagement/mitkBoundingShapeUtil.h"
18 #include <mitkBaseProperty.h>
20 
21 #include <vtkActor2D.h>
22 #include <vtkAppendPolyData.h>
23 #include <vtkCoordinate.h>
24 #include <vtkCubeSource.h>
25 #include <vtkMath.h>
26 #include <vtkPointData.h>
27 #include <vtkPolyData.h>
28 #include <vtkPolyDataMapper2D.h>
29 #include <vtkProperty2D.h>
30 #include <vtkSphereSource.h>
31 #include <vtkStripper.h>
32 #include <vtkTransformFilter.h>
33 #include <vtkTransformPolyDataFilter.h>
34 
35 static vtkSmartPointer<vtkSphereSource> CreateHandle()
36 {
38 
39  handle->SetPhiResolution(8);
40  handle->SetThetaResolution(16);
41 
42  return handle;
43 }
44 
45 namespace mitk
46 {
47  class BoundingShapeVtkMapper2D::Impl
48  {
49  public:
50  Impl()
51  {
52  Point3D initialPoint;
53  initialPoint.Fill(0);
54 
55  for (int i = 0; i < 6; ++i)
56  HandlePropertyList.push_back(Handle(initialPoint, i, GetHandleIndices(i)));
57  }
58 
59  std::vector<Handle> HandlePropertyList;
60  mitk::LocalStorageHandler<LocalStorage> LocalStorageHandler;
61  };
62 }
63 
64 mitk::BoundingShapeVtkMapper2D::LocalStorage::LocalStorage()
65  : m_Actor(vtkSmartPointer<vtkActor>::New()),
66  m_HandleActor(vtkSmartPointer<vtkActor2D>::New()),
67  m_SelectedHandleActor(vtkSmartPointer<vtkActor2D>::New()),
68  m_Mapper(vtkSmartPointer<vtkPolyDataMapper>::New()),
69  m_HandleMapper(vtkSmartPointer<vtkPolyDataMapper2D>::New()),
70  m_SelectedHandleMapper(vtkSmartPointer<vtkPolyDataMapper2D>::New()),
71  m_Cutter(vtkSmartPointer<vtkCutter>::New()),
72  m_CuttingPlane(vtkSmartPointer<vtkPlane>::New()),
73  m_LastSliceNumber(0),
74  m_PropAssembly(vtkSmartPointer<vtkPropAssembly>::New()),
75  m_ZoomFactor(1.0)
76 {
77  m_Actor->SetMapper(m_Mapper);
78  m_Actor->GetProperty()->SetOpacity(0.3);
79  m_Actor->VisibilityOn();
80 
81  m_HandleActor->SetMapper(m_HandleMapper);
82  m_HandleActor->VisibilityOn();
83 
84  m_SelectedHandleActor->VisibilityOn();
85  m_SelectedHandleActor->GetProperty()->SetColor(0, 1.0, 0);
86  m_SelectedHandleActor->SetMapper(m_SelectedHandleMapper);
87 
88  vtkCoordinate *tcoord = vtkCoordinate::New();
89  tcoord->SetCoordinateSystemToWorld();
90  m_SelectedHandleMapper->SetTransformCoordinate(tcoord);
91  tcoord->Delete();
92 
93  m_Cutter->SetCutFunction(m_CuttingPlane);
94 
95  for (int i = 0; i < 6; ++i)
96  m_Handles.push_back(CreateHandle());
97 
98  m_PropAssembly->AddPart(m_Actor);
99  m_PropAssembly->AddPart(m_HandleActor);
100  m_PropAssembly->VisibilityOn();
101 }
102 
103 bool mitk::BoundingShapeVtkMapper2D::LocalStorage::IsUpdateRequired(mitk::BaseRenderer *renderer,
104  mitk::Mapper *mapper,
105  mitk::DataNode *dataNode)
106 {
107  const mitk::PlaneGeometry *worldGeometry = renderer->GetCurrentWorldPlaneGeometry();
108 
109  if (m_LastGenerateDataTime < worldGeometry->GetMTime())
110  return true;
111 
112  unsigned int sliceNumber = renderer->GetSlice();
113 
114  if (m_LastSliceNumber != sliceNumber)
115  return true;
116 
117  if (mapper && m_LastGenerateDataTime < mapper->GetMTime())
118  return true;
119 
120  if (dataNode)
121  {
122  if (m_LastGenerateDataTime < dataNode->GetMTime())
123  return true;
124 
125  mitk::BaseData *data = dataNode->GetData();
126 
127  if (data && m_LastGenerateDataTime < data->GetMTime())
128  return true;
129  }
130 
131  return false;
132 }
133 
134 mitk::BoundingShapeVtkMapper2D::LocalStorage::~LocalStorage()
135 {
136 }
137 
138 void mitk::BoundingShapeVtkMapper2D::Update(mitk::BaseRenderer *renderer)
139 {
140  this->GenerateDataForRenderer(renderer);
141 }
142 
144 {
145  Superclass::SetDefaultProperties(node, renderer, overwrite);
146 }
147 
148 mitk::BoundingShapeVtkMapper2D::BoundingShapeVtkMapper2D() : m_Impl(new Impl)
149 {
150 }
151 
152 mitk::BoundingShapeVtkMapper2D::~BoundingShapeVtkMapper2D()
153 {
154  delete m_Impl;
155 }
156 
157 void mitk::BoundingShapeVtkMapper2D::GenerateDataForRenderer(BaseRenderer *renderer)
158 {
159  const DataNode::Pointer node = GetDataNode();
160  if (node == nullptr)
161  return;
162 
163  LocalStorage *localStorage = m_Impl->LocalStorageHandler.GetLocalStorage(renderer);
164 
165  // either update if GeometryData was modified or if the zooming was performed
166  bool needGenerateData = localStorage->IsUpdateRequired(
167  renderer, this, GetDataNode()); // true; // localStorage->GetLastGenerateDataTime() < node->GetMTime() ||
168  // localStorage->GetLastGenerateDataTime() < node->GetData()->GetMTime();
169  // //localStorage->IsGenerateDataRequired(renderer, this, GetDataNode());
170 
171  double scale = renderer->GetScaleFactorMMPerDisplayUnit();
172 
173  if (std::abs(scale - localStorage->m_ZoomFactor) > 0.001)
174  {
175  localStorage->m_ZoomFactor = scale;
176  needGenerateData = true;
177  }
178 
179  if (needGenerateData)
180  {
181  bool visible = true;
182  GetDataNode()->GetVisibility(visible, renderer, "visible");
183 
184  if (!visible)
185  {
186  localStorage->m_Actor->VisibilityOff();
187  return;
188  }
189  GeometryData::Pointer shape = static_cast<GeometryData *>(node->GetData());
190  if (shape == nullptr)
191  return;
192 
193  mitk::BaseGeometry::Pointer geometry = shape->GetGeometry();
194  mitk::Vector3D spacing = geometry->GetSpacing();
195 
196  // calculate cornerpoints and extent from geometry with visualization offset
197  std::vector<Point3D> cornerPoints = GetCornerPoints(geometry, true);
198  Point3D p0 = cornerPoints[0];
199  Point3D p1 = cornerPoints[1];
200  Point3D p2 = cornerPoints[2];
201  Point3D p4 = cornerPoints[4];
202  Point3D extent;
203  extent[0] =
204  sqrt((p0[0] - p4[0]) * (p0[0] - p4[0]) + (p0[1] - p4[1]) * (p0[1] - p4[1]) + (p0[2] - p4[2]) * (p0[2] - p4[2]));
205  extent[1] =
206  sqrt((p0[0] - p2[0]) * (p0[0] - p2[0]) + (p0[1] - p2[1]) * (p0[1] - p2[1]) + (p0[2] - p2[2]) * (p0[2] - p2[2]));
207  extent[2] =
208  sqrt((p0[0] - p1[0]) * (p0[0] - p1[0]) + (p0[1] - p1[1]) * (p0[1] - p1[1]) + (p0[2] - p1[2]) * (p0[2] - p1[2]));
209 
210  // calculate center based on half way of the distance between two opposing cornerpoints
211  mitk::Point3D center = CalcAvgPoint(cornerPoints[7], cornerPoints[0]);
212 
213  if (m_Impl->HandlePropertyList.size() == 6)
214  {
215  // set handle positions
216  Point3D pointLeft = CalcAvgPoint(cornerPoints[5], cornerPoints[6]);
217  Point3D pointRight = CalcAvgPoint(cornerPoints[1], cornerPoints[2]);
218  Point3D pointTop = CalcAvgPoint(cornerPoints[0], cornerPoints[6]);
219  Point3D pointBottom = CalcAvgPoint(cornerPoints[7], cornerPoints[1]);
220  Point3D pointFront = CalcAvgPoint(cornerPoints[2], cornerPoints[7]);
221  Point3D pointBack = CalcAvgPoint(cornerPoints[4], cornerPoints[1]);
222 
223  m_Impl->HandlePropertyList[0].SetPosition(pointLeft);
224  m_Impl->HandlePropertyList[1].SetPosition(pointRight);
225  m_Impl->HandlePropertyList[2].SetPosition(pointTop);
226  m_Impl->HandlePropertyList[3].SetPosition(pointBottom);
227  m_Impl->HandlePropertyList[4].SetPosition(pointFront);
228  m_Impl->HandlePropertyList[5].SetPosition(pointBack);
229  }
230 
231  // caculate face normals
232  double result0[3], result1[3], result2[3];
233  double a[3], b[3];
234  a[0] = (cornerPoints[5][0] - cornerPoints[6][0]);
235  a[1] = (cornerPoints[5][1] - cornerPoints[6][1]);
236  a[2] = (cornerPoints[5][2] - cornerPoints[6][2]);
237 
238  b[0] = (cornerPoints[5][0] - cornerPoints[4][0]);
239  b[1] = (cornerPoints[5][1] - cornerPoints[4][1]);
240  b[2] = (cornerPoints[5][2] - cornerPoints[4][2]);
241 
242  vtkMath::Cross(a, b, result0);
243 
244  a[0] = (cornerPoints[0][0] - cornerPoints[6][0]);
245  a[1] = (cornerPoints[0][1] - cornerPoints[6][1]);
246  a[2] = (cornerPoints[0][2] - cornerPoints[6][2]);
247 
248  b[0] = (cornerPoints[0][0] - cornerPoints[2][0]);
249  b[1] = (cornerPoints[0][1] - cornerPoints[2][1]);
250  b[2] = (cornerPoints[0][2] - cornerPoints[2][2]);
251 
252  vtkMath::Cross(a, b, result1);
253 
254  a[0] = (cornerPoints[2][0] - cornerPoints[7][0]);
255  a[1] = (cornerPoints[2][1] - cornerPoints[7][1]);
256  a[2] = (cornerPoints[2][2] - cornerPoints[7][2]);
257 
258  b[0] = (cornerPoints[2][0] - cornerPoints[6][0]);
259  b[1] = (cornerPoints[2][1] - cornerPoints[6][1]);
260  b[2] = (cornerPoints[2][2] - cornerPoints[6][2]);
261 
262  vtkMath::Cross(a, b, result2);
263 
264  vtkMath::Normalize(result0);
265  vtkMath::Normalize(result1);
266  vtkMath::Normalize(result2);
267 
268  // create cube for rendering bounding box
269  auto cube = vtkCubeSource::New();
270  cube->SetXLength(extent[0] / spacing[0]);
271  cube->SetYLength(extent[1] / spacing[1]);
272  cube->SetZLength(extent[2] / spacing[2]);
273 
274  // calculates translation based on offset+extent not on the transformation matrix
275  vtkSmartPointer<vtkMatrix4x4> imageTransform = geometry->GetVtkTransform()->GetMatrix();
276  auto translation = vtkSmartPointer<vtkTransform>::New();
277  translation->Translate(center[0] - imageTransform->GetElement(0, 3),
278  center[1] - imageTransform->GetElement(1, 3),
279  center[2] - imageTransform->GetElement(2, 3));
280 
281  auto transform = vtkSmartPointer<vtkTransform>::New();
282  transform->SetMatrix(imageTransform);
283  transform->PostMultiply();
284  transform->Concatenate(translation);
285  transform->Update();
286  cube->Update();
287 
288  auto transformFilter = vtkSmartPointer<vtkTransformFilter>::New();
289  transformFilter->SetInputData(cube->GetOutput());
290  transformFilter->SetTransform(transform);
291  transformFilter->Update();
292  cube->Delete();
293 
294  vtkSmartPointer<vtkPolyData> polydata = transformFilter->GetPolyDataOutput();
295  if (polydata == nullptr || (polydata->GetNumberOfPoints() < 1))
296  {
297  localStorage->m_Actor->VisibilityOff();
298  localStorage->m_HandleActor->VisibilityOff();
299  localStorage->m_SelectedHandleActor->VisibilityOff();
300  return;
301  }
302 
303  // estimate current image plane to decide whether the cube is visible or not
304  const PlaneGeometry *planeGeometry = renderer->GetCurrentWorldPlaneGeometry();
305  if ((planeGeometry == nullptr) || (!planeGeometry->IsValid()) || (!planeGeometry->HasReferenceGeometry()))
306  return;
307 
308  double origin[3];
309  origin[0] = planeGeometry->GetOrigin()[0];
310  origin[1] = planeGeometry->GetOrigin()[1];
311  origin[2] = planeGeometry->GetOrigin()[2];
312 
313  double normal[3];
314  normal[0] = planeGeometry->GetNormal()[0];
315  normal[1] = planeGeometry->GetNormal()[1];
316  normal[2] = planeGeometry->GetNormal()[2];
317 
318  // MITK_INFO << "normal1 " << normal[0] << " " << normal[1] << " " << normal[2];
319  localStorage->m_CuttingPlane->SetOrigin(origin);
320  localStorage->m_CuttingPlane->SetNormal(normal);
321 
322  // add cube polydata to local storage
323  localStorage->m_Cutter->SetInputData(polydata);
324  localStorage->m_Cutter->SetGenerateCutScalars(1);
325  localStorage->m_Cutter->Update();
326 
327  if (localStorage->m_PropAssembly->GetParts()->IsItemPresent(localStorage->m_HandleActor))
328  localStorage->m_PropAssembly->RemovePart(localStorage->m_HandleActor);
329  if (localStorage->m_PropAssembly->GetParts()->IsItemPresent(localStorage->m_Actor))
330  localStorage->m_PropAssembly->RemovePart(localStorage->m_Actor);
331 
332  vtkCoordinate *tcoord = vtkCoordinate::New();
333  tcoord->SetCoordinateSystemToWorld();
334  localStorage->m_HandleMapper->SetTransformCoordinate(tcoord);
335  tcoord->Delete();
336 
337  if (localStorage->m_Cutter->GetOutput()->GetNumberOfPoints() > 0) // if plane is visible in the renderwindow
338  {
339  mitk::DoubleProperty::Pointer handleSizeProperty =
340  dynamic_cast<mitk::DoubleProperty *>(this->GetDataNode()->GetProperty("Bounding Shape.Handle Size Factor"));
341 
342  ScalarType initialHandleSize;
343  if (handleSizeProperty != nullptr)
344  initialHandleSize = handleSizeProperty->GetValue();
345  else
346  initialHandleSize = 1.0 / 40.0;
347 
348  mitk::Point2D displaySize = renderer->GetDisplaySizeInMM();
349  double handleSize = ((displaySize[0] + displaySize[1]) / 2.0) * initialHandleSize;
350 
351  auto appendPoly = vtkSmartPointer<vtkAppendPolyData>::New();
352  unsigned int i = 0;
353 
354  // add handles and their assigned properties to the local storage
355  mitk::IntProperty::Pointer activeHandleId =
356  dynamic_cast<mitk::IntProperty *>(node->GetProperty("Bounding Shape.Active Handle ID"));
357 
358  bool visible = false;
359  bool selected = false;
360  for (auto handle : localStorage->m_Handles)
361  {
362  Point3D handleCenter = m_Impl->HandlePropertyList[i].GetPosition();
363 
364  handle->SetRadius(handleSize);
365  handle->SetCenter(handleCenter[0], handleCenter[1], handleCenter[2]);
366 
367  vtkMath::Normalize(normal);
368  double angle = vtkMath::DegreesFromRadians(acos(vtkMath::Dot(normal, result0)));
369  double angle1 = vtkMath::DegreesFromRadians(acos(vtkMath::Dot(normal, result1)));
370  double angle2 = vtkMath::DegreesFromRadians(acos(vtkMath::Dot(normal, result2)));
371 
372  // show handles only if the corresponding face is aligned to the render window
373  if ((((std::abs(angle - 0) < 0.001) || (std::abs(angle - 180) < 0.001)) && i != 0 && i != 1) ||
374  (((std::abs(angle1 - 0) < 0.001) || (std::abs(angle1 - 180) < 0.001)) && i != 2 && i != 3) ||
375  (((std::abs(angle2 - 0) < 0.001) || (std::abs(angle2 - 180) < 0.001)) && i != 4 && i != 5))
376  {
377  if (activeHandleId == nullptr)
378  {
379  appendPoly->AddInputConnection(handle->GetOutputPort());
380  }
381  else
382  {
383  if ((activeHandleId->GetValue() != m_Impl->HandlePropertyList[i].GetIndex()))
384  {
385  appendPoly->AddInputConnection(handle->GetOutputPort());
386  }
387  else
388  {
389  handle->Update();
390  localStorage->m_SelectedHandleMapper->SetInputData(handle->GetOutput());
391  localStorage->m_SelectedHandleActor->VisibilityOn();
392  selected = true;
393  }
394  }
395  visible = true;
396  }
397 
398  i++;
399  }
400 
401  if (visible)
402  {
403  appendPoly->Update();
404  }
405  else
406  {
407  localStorage->m_HandleActor->VisibilityOff();
408  localStorage->m_SelectedHandleActor->VisibilityOff();
409  }
410 
411  auto stripper = vtkSmartPointer<vtkStripper>::New();
412  stripper->SetInputData(localStorage->m_Cutter->GetOutput());
413  stripper->Update();
414 
415  auto cutPolyData = vtkSmartPointer<vtkPolyData>::New();
416  cutPolyData->SetPoints(stripper->GetOutput()->GetPoints());
417  cutPolyData->SetPolys(stripper->GetOutput()->GetLines());
418 
419  localStorage->m_Actor->GetMapper()->SetInputDataObject(cutPolyData);
420  mitk::ColorProperty::Pointer selectedColor = dynamic_cast<mitk::ColorProperty *>(node->GetProperty("color"));
421  if (selectedColor != nullptr)
422  {
423  mitk::Color color = selectedColor->GetColor();
424  localStorage->m_Actor->GetProperty()->SetColor(color[0], color[1], color[2]);
425  }
426 
427  if (activeHandleId != nullptr)
428  {
429  localStorage->m_HandleActor->GetProperty()->SetColor(1, 0, 0);
430  }
431  else
432  {
433  localStorage->m_HandleActor->GetProperty()->SetColor(1, 1, 1);
434  }
435  localStorage->m_HandleActor->GetMapper()->SetInputDataObject(appendPoly->GetOutput());
436 
437  // add parts to the overall storage
438  localStorage->m_PropAssembly->AddPart(localStorage->m_Actor);
439  localStorage->m_PropAssembly->AddPart(localStorage->m_HandleActor);
440  if (selected)
441  {
442  localStorage->m_PropAssembly->AddPart(localStorage->m_SelectedHandleActor);
443  }
444 
445  localStorage->m_PropAssembly->VisibilityOn();
446  localStorage->m_Actor->VisibilityOn();
447  localStorage->m_HandleActor->VisibilityOn();
448  }
449  else
450  {
451  localStorage->m_PropAssembly->VisibilityOff();
452  localStorage->m_Actor->VisibilityOff();
453  localStorage->m_HandleActor->VisibilityOff();
454  localStorage->m_SelectedHandleActor->VisibilityOff();
455  localStorage->UpdateGenerateDataTime();
456  }
457  localStorage->UpdateGenerateDataTime();
458  }
459 }
460 
462 {
463  return m_Impl->LocalStorageHandler.GetLocalStorage(renderer)->m_PropAssembly;
464 }
465 
467 {
468 }
vtkProp * GetVtkProp(BaseRenderer *renderer) override
virtual unsigned int GetSlice() const
Base of all data objects.
Definition: mitkBaseData.h:39
void ApplyColorAndOpacityProperties(BaseRenderer *, vtkActor *) override
Apply color and opacity properties read from the PropertyList. Called by mapper subclasses.
double ScalarType
itk::SmartPointer< Self > Pointer
static void SetDefaultProperties(DataNode *node, BaseRenderer *renderer=nullptr, bool overwrite=false)
Organizes the rendering process.
DataCollection - Class to facilitate loading/accessing structured data.
virtual const PlaneGeometry * GetCurrentWorldPlaneGeometry()
Get the current 2D-worldgeometry (m_CurrentWorldPlaneGeometry) used for 2D-rendering.
BaseData * GetData() const
Get the data object (instance of BaseData, e.g., an Image) managed by this DataNode.
std::vector< mitk::Point3D > GetCornerPoints(mitk::BaseGeometry::Pointer geometry, bool visualizationOffset)
helper function for calculating corner points of the bounding object from a given geometry ...
Base class of all mappers, Vtk as well as OpenGL mappers.
Definition: mitkMapper.h:54
std::vector< int > GetHandleIndices(int index)
itk::SmartPointer< Self > Pointer
Definition: mitkDataNode.h:81
The ColorProperty class RGB color property.
Point< ScalarType, 3 > Point3D
Definition: mitkPoint.h:99
itk::RGBPixel< float > Color
Color Standard RGB color typedef (float)
void Normalize(itk::Image< TPixel, VImageDimension > *itkImage, mitk::Image::Pointer im2, mitk::Image::Pointer mask1, std::string output)
Definition: CLBrainMask.cpp:40
const float selectedColor[]
Describes a two-dimensional, rectangular plane.
static vtkSmartPointer< vtkSphereSource > CreateHandle()
mitk::Point3D CalcAvgPoint(mitk::Point3D a, mitk::Point3D b)
helper function for calculating the average of two points
Class for nodes of the DataTree.
Definition: mitkDataNode.h:66
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.