Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkContourModelMapper2D.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 ===================================================================*/
17 
19 
20 #include <vtkAppendPolyData.h>
21 #include <vtkCellArray.h>
22 #include <vtkCutter.h>
23 #include <vtkPlane.h>
24 #include <vtkPoints.h>
25 #include <vtkProperty.h>
26 #include <vtkSphereSource.h>
27 #include <vtkStripper.h>
28 #include <vtkTubeFilter.h>
29 
30 #include <mitkPlaneGeometry.h>
31 
33 {
34 }
35 
37 {
38 }
39 
41 {
42  // convient way to get the data from the dataNode
43  return static_cast<const mitk::ContourModel *>(GetDataNode()->GetData());
44 }
45 
47 {
48  // return the actor corresponding to the renderer
49  return m_LSH.GetLocalStorage(renderer)->m_Actor;
50 }
51 
53 {
54  /*++ convert the contour to vtkPolyData and set it as input for our mapper ++*/
55 
56  LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer);
57 
58  mitk::ContourModel *inputContour = static_cast<mitk::ContourModel *>(GetDataNode()->GetData());
59 
60  unsigned int timestep = renderer->GetTimeStep();
61 
62  // if there's something to be rendered
63  if (inputContour->GetNumberOfVertices(timestep) > 0)
64  {
65  localStorage->m_OutlinePolyData = this->CreateVtkPolyDataFromContour(inputContour, renderer);
66  }
67 
68  this->ApplyContourProperties(renderer);
69 
70  localStorage->m_Mapper->SetInputData(localStorage->m_OutlinePolyData);
71 }
72 
74 {
75  bool visible = true;
76  GetDataNode()->GetVisibility(visible, renderer, "visible");
77 
78  if (!visible)
79  return;
80 
81  // check if there is something to be rendered
82  mitk::ContourModel *data = static_cast<mitk::ContourModel *>(GetDataNode()->GetData());
83  if (data == NULL)
84  {
85  return;
86  }
87 
88  // Calculate time step of the input data for the specified renderer (integer value)
89  this->CalculateTimeStep(renderer);
90 
91  LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer);
92 
93  // Check if time step is valid
94  const TimeGeometry *dataTimeGeometry = data->GetTimeGeometry();
95  if ((dataTimeGeometry == NULL) || (dataTimeGeometry->CountTimeSteps() == 0) ||
96  (!dataTimeGeometry->IsValidTimeStep(renderer->GetTimeStep())))
97  {
98  // clear the rendered polydata
99  localStorage->m_Mapper->RemoveAllInputs(); // SetInput(vtkSmartPointer<vtkPolyData>::New());
100  return;
101  }
102 
103  const DataNode *node = this->GetDataNode();
104  data->UpdateOutputInformation();
105 
106  // check if something important has changed and we need to rerender
107  if ((localStorage->m_LastUpdateTime < node->GetMTime()) // was the node modified?
108  ||
109  (localStorage->m_LastUpdateTime < data->GetPipelineMTime()) // Was the data modified?
110  ||
111  (localStorage->m_LastUpdateTime <
112  renderer->GetCurrentWorldPlaneGeometryUpdateTime()) // was the geometry modified?
113  ||
114  (localStorage->m_LastUpdateTime < renderer->GetCurrentWorldPlaneGeometry()->GetMTime()) ||
115  (localStorage->m_LastUpdateTime < node->GetPropertyList()->GetMTime()) // was a property modified?
116  ||
117  (localStorage->m_LastUpdateTime < node->GetPropertyList(renderer)->GetMTime()))
118  {
119  this->GenerateDataForRenderer(renderer);
120  }
121 
122  // since we have checked that nothing important has changed, we can set
123  // m_LastUpdateTime to the current time
124  localStorage->m_LastUpdateTime.Modified();
125 }
126 
128  mitk::BaseRenderer *renderer)
129 {
130  unsigned int timestep = this->GetTimestep();
131  // Create a polydata to store everything in
132  vtkSmartPointer<vtkPolyData> resultingPolyData = vtkSmartPointer<vtkPolyData>::New();
133 
134  // check for the worldgeometry from the current render window
135  const mitk::PlaneGeometry *currentWorldGeometry = renderer->GetCurrentWorldPlaneGeometry();
136 
137  if (currentWorldGeometry)
138  {
139  // origin and normal of vtkPlane
140  mitk::Point3D origin = currentWorldGeometry->GetOrigin();
141  mitk::Vector3D normal = currentWorldGeometry->GetNormal();
142  // the implicit function to slice through the polyData
143  vtkSmartPointer<vtkPlane> plane = vtkSmartPointer<vtkPlane>::New();
144  plane->SetOrigin(origin[0], origin[1], origin[2]);
145  plane->SetNormal(normal[0], normal[1], normal[2]);
146 
147  /* First of all convert the control points of the contourModel to vtk points
148  * and add lines in between them
149  */
150  // the points to draw
151  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
152  // the lines to connect the points
153  vtkSmartPointer<vtkCellArray> lines = vtkSmartPointer<vtkCellArray>::New();
154  // Create a polydata to store everything in
155  vtkSmartPointer<vtkPolyData> polyDataIn3D = vtkSmartPointer<vtkPolyData>::New();
156 
157  vtkSmartPointer<vtkAppendPolyData> appendPoly = vtkSmartPointer<vtkAppendPolyData>::New();
158 
160  renderingContour = inputContour;
161 
162  bool subdivision = false;
163  this->GetDataNode()->GetBoolProperty("subdivision curve", subdivision, renderer);
164  if (subdivision)
165  {
167 
169 
170  subdivFilter->SetInput(inputContour);
171  subdivFilter->Update();
172 
173  subdivContour = subdivFilter->GetOutput();
174 
175  if (subdivContour->GetNumberOfVertices() == 0)
176  {
177  subdivContour = inputContour;
178  }
179 
180  renderingContour = subdivContour;
181  }
182 
183  // iterate over all control points
184  mitk::ContourModel::VertexIterator current = renderingContour->IteratorBegin(timestep);
185  mitk::ContourModel::VertexIterator next = renderingContour->IteratorBegin(timestep);
186  if (next != renderingContour->IteratorEnd(timestep))
187  {
188  next++;
189 
190  mitk::ContourModel::VertexIterator end = renderingContour->IteratorEnd(timestep);
191 
192  while (next != end)
193  {
194  mitk::ContourModel::VertexType *currentControlPoint = *current;
195  mitk::ContourModel::VertexType *nextControlPoint = *next;
196 
197  vtkIdType p1 = points->InsertNextPoint(currentControlPoint->Coordinates[0],
198  currentControlPoint->Coordinates[1],
199  currentControlPoint->Coordinates[2]);
200  vtkIdType p2 = points->InsertNextPoint(
201  nextControlPoint->Coordinates[0], nextControlPoint->Coordinates[1], nextControlPoint->Coordinates[2]);
202  // add the line between both contorlPoints
203  lines->InsertNextCell(2);
204  lines->InsertCellPoint(p1);
205  lines->InsertCellPoint(p2);
206 
207  if (currentControlPoint->IsControlPoint)
208  {
209  double coordinates[3];
210  coordinates[0] = currentControlPoint->Coordinates[0];
211  coordinates[1] = currentControlPoint->Coordinates[1];
212  coordinates[2] = currentControlPoint->Coordinates[2];
213 
214  double distance = plane->DistanceToPlane(coordinates);
215  if (distance < 0.1)
216  {
217  vtkSmartPointer<vtkSphereSource> sphere = vtkSmartPointer<vtkSphereSource>::New();
218 
219  sphere->SetRadius(1.2);
220  sphere->SetCenter(coordinates[0], coordinates[1], coordinates[2]);
221  sphere->Update();
222  appendPoly->AddInputConnection(sphere->GetOutputPort());
223  }
224  }
225 
226  current++;
227  next++;
228  } // end while (it!=end)
229 
230  // check if last control point is enabled to draw it
231  if ((*current)->IsControlPoint)
232  {
233  double coordinates[3];
234  coordinates[0] = (*current)->Coordinates[0];
235  coordinates[1] = (*current)->Coordinates[1];
236  coordinates[2] = (*current)->Coordinates[2];
237 
238  double distance = plane->DistanceToPlane(coordinates);
239  if (distance < 0.1)
240  {
241  vtkSmartPointer<vtkSphereSource> sphere = vtkSmartPointer<vtkSphereSource>::New();
242 
243  sphere->SetRadius(1.2);
244  sphere->SetCenter(coordinates[0], coordinates[1], coordinates[2]);
245  sphere->Update();
246  appendPoly->AddInputConnection(sphere->GetOutputPort());
247  }
248  }
249 
250  /* If the contour is closed an additional line has to be created between the very first point
251  * and the last point
252  */
253  if (renderingContour->IsClosed(timestep))
254  {
255  // add a line from the last to the first control point
256  mitk::ContourModel::VertexType *firstControlPoint = *(renderingContour->IteratorBegin(timestep));
257  mitk::ContourModel::VertexType *lastControlPoint = *(--(renderingContour->IteratorEnd(timestep)));
258  vtkIdType p2 = points->InsertNextPoint(
259  lastControlPoint->Coordinates[0], lastControlPoint->Coordinates[1], lastControlPoint->Coordinates[2]);
260  vtkIdType p1 = points->InsertNextPoint(
261  firstControlPoint->Coordinates[0], firstControlPoint->Coordinates[1], firstControlPoint->Coordinates[2]);
262 
263  // add the line between both contorlPoints
264  lines->InsertNextCell(2);
265  lines->InsertCellPoint(p1);
266  lines->InsertCellPoint(p2);
267  } // end if(isClosed)
268 
269  // Add the points to the dataset
270  polyDataIn3D->SetPoints(points);
271  // Add the lines to the dataset
272  polyDataIn3D->SetLines(lines);
273 
274  // cut through polyData
275  bool useCuttingPlane = false;
276  this->GetDataNode()->GetBoolProperty("use cutting plane", useCuttingPlane, renderer);
277  if (useCuttingPlane)
278  {
279  // slice through the data to get a 2D representation of the (possible) 3D contour
280 
281  // needed because currently there is no outher solution if the contour is within the plane
282  vtkSmartPointer<vtkTubeFilter> tubeFilter = vtkSmartPointer<vtkTubeFilter>::New();
283  tubeFilter->SetInputData(polyDataIn3D);
284  tubeFilter->SetRadius(0.05);
285 
286  // cuts through vtkPolyData with a given implicit function. In our case a plane
287  vtkSmartPointer<vtkCutter> cutter = vtkSmartPointer<vtkCutter>::New();
288 
289  cutter->SetCutFunction(plane);
290 
291  cutter->SetInputConnection(tubeFilter->GetOutputPort());
292 
293  // we want the scalars of the input - so turn off generating the scalars within vtkCutter
294  cutter->GenerateCutScalarsOff();
295  cutter->Update();
296 
297  // set to 2D representation of the contour
298  resultingPolyData = cutter->GetOutput();
299 
300  } // end if(project contour)
301  else
302  {
303  // set to 3D polyData
304  resultingPolyData = polyDataIn3D;
305  }
306 
307  } // end if (it != end)
308 
309  appendPoly->AddInputData(resultingPolyData);
310  appendPoly->Update();
311 
312  // return contour with control points
313  return appendPoly->GetOutput();
314  }
315  else
316  {
317  // return empty polyData
318  return resultingPolyData;
319  }
320 }
321 
323 {
324  LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer);
325 
326  float lineWidth(1.0);
327  if (this->GetDataNode()->GetFloatProperty("width", lineWidth, renderer))
328  {
329  localStorage->m_Actor->GetProperty()->SetLineWidth(lineWidth);
330  }
331 
332  mitk::ColorProperty::Pointer colorprop =
333  dynamic_cast<mitk::ColorProperty *>(GetDataNode()->GetProperty("color", renderer));
334  if (colorprop)
335  {
336  // set the color of the contour
337  double red = colorprop->GetColor().GetRed();
338  double green = colorprop->GetColor().GetGreen();
339  double blue = colorprop->GetColor().GetBlue();
340  localStorage->m_Actor->GetProperty()->SetColor(red, green, blue);
341  }
342 
343  // make sure that directional lighting isn't used for our contour
344  localStorage->m_Actor->GetProperty()->SetAmbient(1.0);
345  localStorage->m_Actor->GetProperty()->SetDiffuse(0.0);
346  localStorage->m_Actor->GetProperty()->SetSpecular(0.0);
347 }
348 
349 /*+++++++++++++++++++ LocalStorage part +++++++++++++++++++++++++*/
350 
352 {
353  return m_LSH.GetLocalStorage(renderer);
354 }
355 
357 {
359  m_Actor = vtkSmartPointer<vtkActor>::New();
360  m_OutlinePolyData = vtkSmartPointer<vtkPolyData>::New();
361 
362  // set the mapper for the actor
363  m_Actor->SetMapper(m_Mapper);
364 }
365 
367  mitk::BaseRenderer *renderer,
368  bool overwrite)
369 {
370  node->AddProperty("color", ColorProperty::New(0.9, 1.0, 0.1), renderer, overwrite);
371  node->AddProperty("width", mitk::FloatProperty::New(1.0), renderer, overwrite);
372  node->AddProperty("use cutting plane", mitk::BoolProperty::New(true), renderer, overwrite);
373  node->AddProperty("subdivision curve", mitk::BoolProperty::New(false), renderer, overwrite);
374 
375  Superclass::SetDefaultProperties(node, renderer, overwrite);
376 }
const Point3D GetOrigin() const
Get the origin, e.g. the upper-left corner of the plane.
mitk::PropertyList * GetPropertyList(const mitk::BaseRenderer *renderer=nullptr) const
Get the PropertyList of the renderer. If renderer is NULL, the BaseRenderer-independent PropertyList ...
ContourModel is a structure of linked vertices defining a contour in 3D space. The vertices are store...
virtual void UpdateOutputInformation() override
Update the OutputInformation of a ContourModel object.
mitk::Point3D Coordinates
Coordinates in 3D space.
virtual 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 ...
static Pointer New()
Organizes the rendering process.
mitk::ContourElement::VertexIterator VertexIterator
virtual const PlaneGeometry * GetCurrentWorldPlaneGeometry()
Get the current 2D-worldgeometry (m_CurrentWorldPlaneGeometry) used for 2D-rendering.
const mitk::TimeGeometry * GetTimeGeometry() const
Return the TimeGeometry of the data as const pointer.
Definition: mitkBaseData.h:52
LocalStorage * GetLocalStorage(mitk::BaseRenderer *renderer)
Get the LocalStorage corresponding to the current renderer.
virtual unsigned long GetMTime() const override
Get the timestamp of the last change of the contents of this node or the referenced BaseData...
virtual void Update(mitk::BaseRenderer *renderer) override
Checks whether this mapper needs to update itself and generate data.
void GenerateDataForRenderer(mitk::BaseRenderer *renderer) override
Generate the data needed for rendering into renderer.
Vector3D GetNormal() const
Normal of the plane.
static Pointer New()
The ColorProperty class RGB color property.
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 ...
virtual vtkProp * GetVtkProp(mitk::BaseRenderer *renderer) override
const mitk::ContourModel * GetInput(void)
virtual void ApplyContourProperties(mitk::BaseRenderer *renderer)
vtkSmartPointer< vtkPolyDataMapper > m_Mapper
Mapper of a 2D render window.
vtkSmartPointer< vtkActor > m_Actor
Actor of a 2D render window.
LocalStorage()
Default constructor of the local storage.
virtual unsigned int GetTimeStep() const
static Pointer New()
itk::TimeStamp m_LastUpdateTime
Timestamp of last update of stored data.
static Pointer New()
unsigned long GetCurrentWorldPlaneGeometryUpdateTime()
Get timestamp of last call of SetCurrentWorldPlaneGeometry.
Describes a two-dimensional, rectangular plane.
static void SetDefaultProperties(mitk::DataNode *node, mitk::BaseRenderer *renderer=NULL, bool overwrite=false)
Set the default properties for general image rendering.
Represents a single vertex of contour.
virtual vtkSmartPointer< vtkPolyData > CreateVtkPolyDataFromContour(mitk::ContourModel *inputContour, mitk::BaseRenderer *renderer)
virtual bool IsValidTimeStep(TimeStepType timeStep) const =0
Test for the given time step if a geometry is availible.
vtkSmartPointer< vtkPolyData > m_OutlinePolyData
Class for nodes of the DataTree.
Definition: mitkDataNode.h:66
int GetNumberOfVertices(int timestep=0) const
Returns the number of vertices at a given timestep.
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.