Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkBoundingShapeVtkMapper3D.cpp
Go to the documentation of this file.
1 /*===================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
18 #include "../DataManagement/mitkBoundingShapeUtil.h"
19 #include <mitkBaseProperty.h>
20 #include <vtkAppendPolyData.h>
21 #include <vtkCamera.h>
22 #include <vtkCubeSource.h>
23 #include <vtkDataSetMapper.h>
24 #include <vtkMath.h>
25 #include <vtkPolyData.h>
26 #include <vtkPolyDataMapper.h>
27 #include <vtkSphereSource.h>
28 #include <vtkTransformFilter.h>
29 
30 namespace mitk
31 {
32  class BoundingShapeVtkMapper3D::Impl
33  {
34  class LocalStorage : public Mapper::BaseLocalStorage
35  {
36  public:
37  LocalStorage();
38  ~LocalStorage();
39 
40  LocalStorage(const LocalStorage &) = delete;
41  LocalStorage &operator=(const LocalStorage &) = delete;
42 
43  std::vector<vtkSmartPointer<vtkSphereSource>> Handles;
44  vtkSmartPointer<vtkActor> Actor;
45  vtkSmartPointer<vtkActor> HandleActor;
46  vtkSmartPointer<vtkActor> SelectedHandleActor;
47  vtkSmartPointer<vtkPropAssembly> PropAssembly;
48  };
49 
50  public:
51  Impl() : DistanceFromCam(1.0)
52  {
53  Point3D initialPoint;
54  initialPoint.Fill(0);
55 
56  for (int i = 0; i < 6; ++i)
57  HandlePropertyList.push_back(Handle(initialPoint, i, GetHandleIndices(i)));
58  }
59 
60  double DistanceFromCam;
61  std::vector<Handle> HandlePropertyList;
62  mitk::LocalStorageHandler<LocalStorage> LocalStorageHandler;
63  };
64 }
65 
66 mitk::BoundingShapeVtkMapper3D::Impl::LocalStorage::LocalStorage()
67  : Actor(vtkSmartPointer<vtkActor>::New()),
68  HandleActor(vtkSmartPointer<vtkActor>::New()),
69  SelectedHandleActor(vtkSmartPointer<vtkActor>::New()),
70  PropAssembly(vtkSmartPointer<vtkPropAssembly>::New())
71 {
72  for (int i = 0; i < 6; i++)
73  Handles.push_back(vtkSmartPointer<vtkSphereSource>::New());
74 }
75 
76 mitk::BoundingShapeVtkMapper3D::Impl::LocalStorage::~LocalStorage()
77 {
78 }
79 
81 {
82  Superclass::SetDefaultProperties(node, renderer, overwrite);
83 }
84 
85 mitk::BoundingShapeVtkMapper3D::BoundingShapeVtkMapper3D() : m_Impl(new Impl)
86 {
87 }
88 
89 mitk::BoundingShapeVtkMapper3D::~BoundingShapeVtkMapper3D()
90 {
91  delete m_Impl;
92 }
93 
95 {
96  //Superclass::ApplyColorAndOpacityProperties(renderer, actor);
97 }
98 
100 {
101  if (actor == nullptr)
102  return;
103 
104  auto dataNode = this->GetDataNode();
105 
106  if (dataNode == nullptr)
107  return;
108 
109  bool isVisible = false;
110  dataNode->GetBoolProperty("Bounding Shape.3D Rendering", isVisible, renderer);
111 
112  actor->SetVisibility(isVisible);
113 
114  float lineWidth = 1.0f;
115  dataNode->GetFloatProperty("Bounding Shape.Line.Width", lineWidth, renderer);
116 
117  auto property = actor->GetProperty();
118  property->SetLineWidth(lineWidth);
119 }
120 
122 {
123  auto dataNode = this->GetDataNode();
124 
125  if (dataNode == nullptr)
126  return;
127 
128  vtkCamera *camera = renderer->GetVtkRenderer()->GetActiveCamera();
129 
130  auto localStorage = m_Impl->LocalStorageHandler.GetLocalStorage(renderer);
131  bool needGenerateData = localStorage->GetLastGenerateDataTime() < dataNode->GetMTime();
132  double distance = camera->GetDistance();
133 
134  if (std::abs(distance - m_Impl->DistanceFromCam) > mitk::eps)
135  {
136  m_Impl->DistanceFromCam = distance;
137  needGenerateData = true;
138  }
139 
140  if (needGenerateData)
141  {
142  bool isVisible = true;
143  dataNode->GetVisibility(isVisible, renderer);
144 
145  if (!isVisible)
146  {
147  localStorage->Actor->VisibilityOff();
148  return;
149  }
150 
151  // set the input-object at time t for the mapper
152  GeometryData *geometryData = dynamic_cast<GeometryData *>(dataNode->GetData());
153  if (geometryData == nullptr)
154  return;
155 
156  mitk::BaseGeometry::Pointer geometry = geometryData->GetGeometry();
157  mitk::Vector3D spacing = geometry->GetSpacing();
158 
159  // calculate cornerpoints from geometry
160  std::vector<Point3D> cornerPoints = GetCornerPoints(geometry, true);
161 
162  Point3D p0 = cornerPoints[0];
163  Point3D p1 = cornerPoints[1];
164  Point3D p2 = cornerPoints[2];
165  Point3D p4 = cornerPoints[4];
166 
167  Point3D extent;
168  extent[0] =
169  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]));
170  extent[1] =
171  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]));
172  extent[2] =
173  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]));
174 
175  // calculate center based on half way of the distance between two opposing cornerpoints
176  mitk::Point3D center = CalcAvgPoint(cornerPoints[7], cornerPoints[0]);
177 
178  if (m_Impl->HandlePropertyList.size() == 6)
179  {
180  // set handle positions
181  Point3D pointLeft = CalcAvgPoint(cornerPoints[5], cornerPoints[6]);
182  Point3D pointRight = CalcAvgPoint(cornerPoints[1], cornerPoints[2]);
183  Point3D pointTop = CalcAvgPoint(cornerPoints[0], cornerPoints[6]);
184  Point3D pointBottom = CalcAvgPoint(cornerPoints[7], cornerPoints[1]);
185  Point3D pointFront = CalcAvgPoint(cornerPoints[2], cornerPoints[7]);
186  Point3D pointBack = CalcAvgPoint(cornerPoints[4], cornerPoints[1]);
187 
188  m_Impl->HandlePropertyList[0].SetPosition(pointLeft);
189  m_Impl->HandlePropertyList[1].SetPosition(pointRight);
190  m_Impl->HandlePropertyList[2].SetPosition(pointTop);
191  m_Impl->HandlePropertyList[3].SetPosition(pointBottom);
192  m_Impl->HandlePropertyList[4].SetPosition(pointFront);
193  m_Impl->HandlePropertyList[5].SetPosition(pointBack);
194  }
195 
196  auto cube = vtkCubeSource::New();
197  cube->SetXLength(extent[0] / spacing[0]);
198  cube->SetYLength(extent[1] / spacing[1]);
199  cube->SetZLength(extent[2] / spacing[2]);
200 
201  // calculates translation based on offset+extent not on the transformation matrix
202  vtkSmartPointer<vtkMatrix4x4> imageTransform = geometry->GetVtkTransform()->GetMatrix();
203  auto translation = vtkSmartPointer<vtkTransform>::New();
204  translation->Translate(center[0] - imageTransform->GetElement(0, 3),
205  center[1] - imageTransform->GetElement(1, 3),
206  center[2] - imageTransform->GetElement(2, 3));
207 
208  auto transform = vtkSmartPointer<vtkTransform>::New();
209  transform->SetMatrix(imageTransform);
210  transform->PostMultiply();
211  transform->Concatenate(translation);
212  transform->Update();
213  cube->Update();
214 
215  auto transformFilter = vtkSmartPointer<vtkTransformFilter>::New();
216  transformFilter->SetInputData(cube->GetOutput());
217  transformFilter->SetTransform(transform);
218  transformFilter->Update();
219  cube->Delete();
220 
221  vtkSmartPointer<vtkPolyData> polydata = transformFilter->GetPolyDataOutput();
222  if (polydata == nullptr)
223  {
224  localStorage->Actor->VisibilityOff();
225  return;
226  }
227 
228  mitk::DoubleProperty::Pointer handleSizeProperty =
229  dynamic_cast<mitk::DoubleProperty *>(this->GetDataNode()->GetProperty("Bounding Shape.Handle Size Factor"));
230 
231  ScalarType initialHandleSize;
232  if (handleSizeProperty != nullptr)
233  initialHandleSize = handleSizeProperty->GetValue();
234  else
235  initialHandleSize = 1.0 / 40.0;
236 
237  double handlesize =
238  ((camera->GetDistance() * std::tan(vtkMath::RadiansFromDegrees(camera->GetViewAngle()))) / 2.0) *
239  initialHandleSize;
240 
241  if (localStorage->PropAssembly->GetParts()->IsItemPresent(localStorage->HandleActor))
242  localStorage->PropAssembly->RemovePart(localStorage->HandleActor);
243  if (localStorage->PropAssembly->GetParts()->IsItemPresent(localStorage->Actor))
244  localStorage->PropAssembly->RemovePart(localStorage->Actor);
245 
246  auto selectedhandlemapper = vtkSmartPointer<vtkPolyDataMapper>::New();
247  auto appendPoly = vtkSmartPointer<vtkAppendPolyData>::New();
248 
249  mitk::IntProperty::Pointer activeHandleId =
250  dynamic_cast<mitk::IntProperty *>(dataNode->GetProperty("Bounding Shape.Active Handle ID"));
251 
252  int i = 0;
253  for (auto &handle : localStorage->Handles)
254  {
255  Point3D handlecenter = m_Impl->HandlePropertyList[i].GetPosition();
256  handle->SetCenter(handlecenter[0], handlecenter[1], handlecenter[2]);
257  handle->SetRadius(handlesize);
258  handle->Update();
259  if (activeHandleId == nullptr)
260  {
261  appendPoly->AddInputConnection(handle->GetOutputPort());
262  }
263  else
264  {
265  if (activeHandleId->GetValue() != m_Impl->HandlePropertyList[i].GetIndex())
266  {
267  appendPoly->AddInputConnection(handle->GetOutputPort());
268  }
269  else
270  {
271  selectedhandlemapper->SetInputData(handle->GetOutput());
272  localStorage->SelectedHandleActor->SetMapper(selectedhandlemapper);
273  localStorage->SelectedHandleActor->GetProperty()->SetColor(0, 1, 0);
274  localStorage->SelectedHandleActor->GetMapper()->SetInputDataObject(handle->GetOutput());
275  localStorage->PropAssembly->AddPart(localStorage->SelectedHandleActor);
276  }
277  }
278  i++;
279  }
280  appendPoly->Update();
281 
283  mapper->SetInputData(polydata);
284 
285  auto handlemapper = vtkSmartPointer<vtkPolyDataMapper>::New();
286  handlemapper->SetInputData(appendPoly->GetOutput());
287 
288  localStorage->Actor->SetMapper(mapper);
289  localStorage->Actor->GetMapper()->SetInputDataObject(polydata);
290  localStorage->Actor->GetProperty()->SetOpacity(0.3);
291 
292  mitk::ColorProperty::Pointer selectedColor = dynamic_cast<mitk::ColorProperty *>(dataNode->GetProperty("color"));
293  if (selectedColor != nullptr)
294  {
295  mitk::Color color = selectedColor->GetColor();
296  localStorage->Actor->GetProperty()->SetColor(color[0], color[1], color[2]);
297  }
298 
299  localStorage->HandleActor->SetMapper(handlemapper);
300  if (activeHandleId == nullptr)
301  {
302  localStorage->HandleActor->GetProperty()->SetColor(1, 1, 1);
303  }
304  else
305  {
306  localStorage->HandleActor->GetProperty()->SetColor(1, 0, 0);
307  }
308 
309  localStorage->HandleActor->GetMapper()->SetInputDataObject(appendPoly->GetOutput());
310 
311  this->ApplyColorAndOpacityProperties(renderer, localStorage->Actor);
312  this->ApplyBoundingShapeProperties(renderer, localStorage->Actor);
313 
314  this->ApplyColorAndOpacityProperties(renderer, localStorage->HandleActor);
315  this->ApplyBoundingShapeProperties(renderer, localStorage->HandleActor);
316 
317  this->ApplyColorAndOpacityProperties(renderer, localStorage->SelectedHandleActor);
318  this->ApplyBoundingShapeProperties(renderer, localStorage->SelectedHandleActor);
319 
320  // apply properties read from the PropertyList
321  // this->ApplyProperties(localStorage->m_Actor, renderer);
322  // this->ApplyProperties(localStorage->m_HandleActor, renderer);
323  // this->ApplyProperties(localStorage->m_SelectedHandleActor, renderer);
324 
325  localStorage->Actor->VisibilityOn();
326  localStorage->HandleActor->VisibilityOn();
327  localStorage->SelectedHandleActor->VisibilityOn();
328 
329  localStorage->PropAssembly->AddPart(localStorage->Actor);
330  localStorage->PropAssembly->AddPart(localStorage->HandleActor);
331  localStorage->PropAssembly->VisibilityOn();
332 
333  localStorage->UpdateGenerateDataTime();
334  }
335 }
337 {
338  return m_Impl->LocalStorageHandler.GetLocalStorage(renderer)->PropAssembly;
339 }
void ApplyColorAndOpacityProperties(BaseRenderer *, vtkActor *) override
Apply color and opacity properties read from the PropertyList. Called by mapper subclasses.
double ScalarType
vtkProp * GetVtkProp(BaseRenderer *renderer) override
Organizes the rendering process.
DataCollection - Class to facilitate loading/accessing structured data.
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 ...
std::vector< int > GetHandleIndices(int index)
The ColorProperty class RGB color property.
void ApplyBoundingShapeProperties(BaseRenderer *renderer, vtkActor *)
Data class only having a BaseGeometry but not containing any specific data.
Point< ScalarType, 3 > Point3D
Definition: mitkPoint.h:99
itk::RGBPixel< float > Color
Color Standard RGB color typedef (float)
void GenerateDataForRenderer(BaseRenderer *renderer) override
Generate the data needed for rendering into renderer.
const float selectedColor[]
MITKCORE_EXPORT const ScalarType eps
static void SetDefaultProperties(DataNode *node, BaseRenderer *renderer=nullptr, bool overwrite=false)
vtkRenderer * GetVtkRenderer() const
mitk::BaseGeometry * GetGeometry(int t=0) const
Return the geometry, which is a TimeGeometry, of the data as non-const pointer.
Definition: mitkBaseData.h:129
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.