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