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
mitkSurface.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 
17 #include "mitkSurface.h"
18 #include "mitkInteractionConst.h"
19 #include "mitkSurfaceOperation.h"
20 
21 #include <algorithm>
22 #include <vtkPolyData.h>
23 
24 static vtkSmartPointer<vtkPolyData> DeepCopy(vtkPolyData *other)
25 {
26  if (other == nullptr)
27  return nullptr;
28 
29  vtkSmartPointer<vtkPolyData> copy = vtkSmartPointer<vtkPolyData>::New();
30  copy->DeepCopy(other);
31 
32  return copy;
33 }
34 
35 static void Update(vtkPolyData * /*polyData*/)
36 {
37  // if (polyData != NULL)
38  // polyData->Update(); //VTK6_TODO vtk pipeline
39 }
40 
41 mitk::Surface::Surface() : m_CalculateBoundingBox(false)
42 {
43  this->InitializeEmpty();
44 }
45 
47  : BaseData(other),
48  m_LargestPossibleRegion(other.m_LargestPossibleRegion),
49  m_RequestedRegion(other.m_RequestedRegion),
50  m_CalculateBoundingBox(other.m_CalculateBoundingBox)
51 {
52  if (!other.m_PolyDatas.empty())
53  {
54  m_PolyDatas.resize(other.m_PolyDatas.size());
55  std::transform(other.m_PolyDatas.cbegin(), other.m_PolyDatas.cend(), m_PolyDatas.begin(), DeepCopy);
56  }
57  else
58  {
59  this->InitializeEmpty();
60  }
61 }
62 
64 {
65  std::swap(m_PolyDatas, other.m_PolyDatas);
66  std::swap(m_LargestPossibleRegion, other.m_LargestPossibleRegion);
67  std::swap(m_RequestedRegion, other.m_RequestedRegion);
68  std::swap(m_CalculateBoundingBox, other.m_CalculateBoundingBox);
69 }
70 
72 {
73  this->Swap(other);
74  return *this;
75 }
76 
78 {
79  this->ClearData();
80 }
81 
83 {
84  m_PolyDatas.clear();
85 
86  Superclass::ClearData();
87 }
88 
90 {
91  m_LargestPossibleRegion.SetIndex(3, 0);
92  m_LargestPossibleRegion.SetSize(3, GetTimeGeometry()->CountTimeSteps());
93 
94  return m_LargestPossibleRegion;
95 }
96 
98 {
99  return m_RequestedRegion;
100 }
101 
103 {
104  if (!m_PolyDatas.empty())
105  this->ClearData();
106 
107  Superclass::InitializeTimeGeometry();
108 
109  m_PolyDatas.push_back(nullptr);
110  m_Initialized = true;
111 }
112 
113 void mitk::Surface::SetVtkPolyData(vtkPolyData *polyData, unsigned int t)
114 {
115  this->Expand(t + 1);
116 
117  if (m_PolyDatas[t] != nullptr)
118  {
119  if (m_PolyDatas[t].GetPointer() == polyData)
120  return;
121  }
122 
123  m_PolyDatas[t].TakeReference(polyData);
124 
125  if (polyData != nullptr)
126  polyData->Register(nullptr);
127 
128  m_CalculateBoundingBox = true;
129 
130  this->Modified();
131  this->UpdateOutputInformation();
132 }
133 
134 bool mitk::Surface::IsEmptyTimeStep(unsigned int t) const
135 {
136  if (!IsInitialized())
137  return false;
138 
139  vtkPolyData *polyData = const_cast<Surface *>(this)->GetVtkPolyData(t);
140 
141  return polyData == nullptr || (polyData->GetNumberOfLines() == 0 && polyData->GetNumberOfPolys() == 0 &&
142  polyData->GetNumberOfStrips() == 0 && polyData->GetNumberOfVerts() == 0);
143 }
144 
145 vtkPolyData *mitk::Surface::GetVtkPolyData(unsigned int t) const
146 {
147  if (t < m_PolyDatas.size())
148  {
149  if (m_PolyDatas[t] == nullptr && this->GetSource().IsNotNull())
150  {
151  RegionType requestedRegion;
152  requestedRegion.SetIndex(3, t);
153  requestedRegion.SetSize(3, 1);
154  this->m_RequestedRegion = requestedRegion;
155  this->GetSource()->Update();
156  }
157 
158  return m_PolyDatas[t].GetPointer();
159  }
160 
161  return nullptr;
162 }
163 
165 {
166  if (this->GetSource().IsNotNull())
167  this->GetSource()->UpdateOutputInformation();
168 
169  if (m_CalculateBoundingBox == true && !m_PolyDatas.empty())
170  this->CalculateBoundingBox();
171  else
172  this->GetTimeGeometry()->Update();
173 }
174 
176 {
177  TimeGeometry *timeGeometry = this->GetTimeGeometry();
178 
179  if (timeGeometry->CountTimeSteps() != m_PolyDatas.size())
180  mitkThrow() << "Number of geometry time steps is inconsistent with number of poly data pointers.";
181 
182  for (unsigned int i = 0; i < m_PolyDatas.size(); ++i)
183  {
184  vtkPolyData *polyData = m_PolyDatas[i].GetPointer();
185  double bounds[6] = {0};
186 
187  if (polyData != nullptr && polyData->GetNumberOfPoints() > 0)
188  {
189  // polyData->Update(); //VTK6_TODO vtk pipeline
190  polyData->ComputeBounds();
191  polyData->GetBounds(bounds);
192  }
193 
194  BaseGeometry::Pointer geometry = timeGeometry->GetGeometryForTimeStep(i);
195 
196  if (geometry.IsNull())
197  mitkThrow() << "Time-sliced geometry is invalid (equals NULL).";
198 
199  geometry->SetFloatBounds(bounds);
200  }
201 
202  timeGeometry->Update();
203  m_CalculateBoundingBox = false;
204 }
205 
207 {
208  m_RequestedRegion = GetLargestPossibleRegion();
209 }
210 
212 {
213  RegionType::IndexValueType end = m_RequestedRegion.GetIndex(3) + m_RequestedRegion.GetSize(3);
214 
215  if (static_cast<RegionType::IndexValueType>(m_PolyDatas.size()) < end)
216  return true;
217 
218  for (RegionType::IndexValueType t = m_RequestedRegion.GetIndex(3); t < end; ++t)
219  {
220  if (m_PolyDatas[t] == nullptr)
221  return true;
222  }
223 
224  return false;
225 }
226 
228 {
229  if (m_RequestedRegion.GetIndex(3) >= 0 &&
230  m_RequestedRegion.GetIndex(3) + m_RequestedRegion.GetSize(3) <= m_PolyDatas.size())
231  return true;
232 
233  return false;
234 }
235 
236 void mitk::Surface::SetRequestedRegion(const itk::DataObject *data)
237 {
238  const mitk::Surface *surface = dynamic_cast<const mitk::Surface *>(data);
239 
240  if (surface != nullptr)
241  m_RequestedRegion = surface->GetRequestedRegion();
242  else
243  mitkThrow() << "Data object used to get requested region is not a mitk::Surface.";
244 }
245 
247 {
248  if (region == nullptr)
249  mitkThrow() << "Requested region is invalid (equals NULL)";
250 
251  m_RequestedRegion = *region;
252 }
253 
254 void mitk::Surface::CopyInformation(const itk::DataObject *data)
255 {
256  Superclass::CopyInformation(data);
257 
258  const mitk::Surface *surface = dynamic_cast<const mitk::Surface *>(data);
259 
260  if (surface == nullptr)
261  mitkThrow() << "Data object used to get largest possible region is not a mitk::Surface.";
262 
263  m_LargestPossibleRegion = surface->GetLargestPossibleRegion();
264 }
265 
267 {
269 
270  if (this->GetSource().IsNull())
271  std::for_each(m_PolyDatas.begin(), m_PolyDatas.end(), Update);
272 
274 }
275 
276 void mitk::Surface::Expand(unsigned int timeSteps)
277 {
278  if (timeSteps > m_PolyDatas.size())
279  {
280  Superclass::Expand(timeSteps);
281 
282  m_PolyDatas.resize(timeSteps);
283  m_CalculateBoundingBox = true;
284  }
285 }
286 
288 {
289  switch (operation->GetOperationType())
290  {
291  case OpSURFACECHANGED:
292  {
293  mitk::SurfaceOperation *surfaceOperation = dynamic_cast<mitk::SurfaceOperation *>(operation);
294 
295  if (surfaceOperation == nullptr)
296  break;
297 
298  unsigned int timeStep = surfaceOperation->GetTimeStep();
299 
300  if (m_PolyDatas[timeStep] != nullptr)
301  {
302  vtkPolyData *updatedPolyData = surfaceOperation->GetVtkPolyData();
303 
304  if (updatedPolyData != nullptr)
305  {
306  this->SetVtkPolyData(updatedPolyData, timeStep);
307  this->CalculateBoundingBox();
308  this->Modified();
309  }
310  }
311 
312  break;
313  }
314 
315  default:
316  return;
317  }
318 }
319 
321 {
322  return m_PolyDatas.size();
323 }
324 
325 void mitk::Surface::Graft(const DataObject *data)
326 {
327  const Surface *surface = dynamic_cast<const Surface *>(data);
328 
329  if (surface == nullptr)
330  mitkThrow() << "Data object used to graft surface is not a mitk::Surface.";
331 
332  this->CopyInformation(data);
333  m_PolyDatas.clear();
334 
335  for (unsigned int i = 0; i < surface->GetSizeOfPolyDataSeries(); ++i)
336  {
337  m_PolyDatas.push_back(vtkSmartPointer<vtkPolyData>::New());
338  m_PolyDatas.back()->DeepCopy(const_cast<mitk::Surface *>(surface)->GetVtkPolyData(i));
339  }
340 }
341 
342 void mitk::Surface::PrintSelf(std::ostream &os, itk::Indent indent) const
343 {
344  Superclass::PrintSelf(os, indent);
345 
346  os << indent << "\nNumber PolyDatas: " << m_PolyDatas.size() << "\n";
347 
348  unsigned int count = 0;
349 
350  for (auto it = m_PolyDatas.begin(); it != m_PolyDatas.end(); ++it)
351  {
352  os << "\n";
353 
354  if (*it != nullptr)
355  {
356  os << indent << "PolyData at time step " << count << ":\n";
357  os << indent << "Number of cells: " << (*it)->GetNumberOfCells() << "\n";
358  os << indent << "Number of points: " << (*it)->GetNumberOfPoints() << "\n\n";
359  os << indent << "VTKPolyData:\n";
360 
361  (*it)->Print(os);
362  }
363  else
364  {
365  os << indent << "Empty PolyData at time step " << count << "\n";
366  }
367 
368  ++count;
369  }
370 }
371 
372 bool mitk::Equal(vtkPolyData *leftHandSide, vtkPolyData *rightHandSide, mitk::ScalarType eps, bool verbose)
373 {
374  if ((leftHandSide == nullptr) || (rightHandSide == nullptr))
375  {
376  MITK_ERROR << "mitk::Equal( vtkPolyData* leftHandSide, vtkPolyData* rightHandSide, mitk::ScalarType eps, bool "
377  "verbose ) does not work for NULL pointer input.";
378  return false;
379  }
380  return Equal(*leftHandSide, *rightHandSide, eps, verbose);
381 }
382 
383 bool mitk::Equal(vtkPolyData &leftHandSide, vtkPolyData &rightHandSide, mitk::ScalarType eps, bool verbose)
384 {
385  bool noDifferenceFound = true;
386 
387  if (!mitk::Equal(leftHandSide.GetNumberOfCells(), rightHandSide.GetNumberOfCells(), eps, verbose))
388  {
389  if (verbose)
390  MITK_INFO << "[Equal( vtkPolyData*, vtkPolyData* )] Number of cells not equal";
391  noDifferenceFound = false;
392  }
393 
394  if (!mitk::Equal(leftHandSide.GetNumberOfVerts(), rightHandSide.GetNumberOfVerts(), eps, verbose))
395  {
396  if (verbose)
397  MITK_INFO << "[Equal( vtkPolyData*, vtkPolyData* )] Number of vertices not equal";
398  noDifferenceFound = false;
399  }
400 
401  if (!mitk::Equal(leftHandSide.GetNumberOfLines(), rightHandSide.GetNumberOfLines(), eps, verbose))
402  {
403  if (verbose)
404  MITK_INFO << "[Equal( vtkPolyData*, vtkPolyData* )] Number of lines not equal";
405  noDifferenceFound = false;
406  }
407 
408  if (!mitk::Equal(leftHandSide.GetNumberOfPolys(), rightHandSide.GetNumberOfPolys(), eps, verbose))
409  {
410  if (verbose)
411  MITK_INFO << "[Equal( vtkPolyData*, vtkPolyData* )] Number of polys not equal";
412  noDifferenceFound = false;
413  }
414 
415  if (!mitk::Equal(leftHandSide.GetNumberOfStrips(), rightHandSide.GetNumberOfStrips(), eps, verbose))
416  {
417  if (verbose)
418  MITK_INFO << "[Equal( vtkPolyData*, vtkPolyData* )] Number of strips not equal";
419  noDifferenceFound = false;
420  }
421 
422  {
423  unsigned int numberOfPointsRight = rightHandSide.GetPoints()->GetNumberOfPoints();
424  unsigned int numberOfPointsLeft = leftHandSide.GetPoints()->GetNumberOfPoints();
425  if (!mitk::Equal(numberOfPointsLeft, numberOfPointsRight, eps, verbose))
426  {
427  if (verbose)
428  MITK_INFO << "[Equal( vtkPolyData*, vtkPolyData* )] Number of points not equal";
429  noDifferenceFound = false;
430  }
431  else
432  {
433  for (unsigned int i(0); i < numberOfPointsRight; i++)
434  {
435  bool pointFound = false;
436  double pointOne[3];
437  rightHandSide.GetPoints()->GetPoint(i, pointOne);
438 
439  for (unsigned int j(0); j < numberOfPointsLeft; j++)
440  {
441  double pointTwo[3];
442  leftHandSide.GetPoints()->GetPoint(j, pointTwo);
443 
444  double x = pointOne[0] - pointTwo[0];
445  double y = pointOne[1] - pointTwo[1];
446  double z = pointOne[2] - pointTwo[2];
447  double distance = x * x + y * y + z * z;
448 
449  if (distance < eps)
450  {
451  pointFound = true;
452  break;
453  }
454  }
455  if (!pointFound)
456  {
457  if (verbose)
458  {
459  MITK_INFO << "[Equal( vtkPolyData*, vtkPolyData* )] Right hand side point with id " << i
460  << " and coordinates ( " << std::setprecision(12) << pointOne[0] << " ; " << pointOne[1] << " ; "
461  << pointOne[2] << " ) could not be found in left hand side with epsilon " << eps << ".";
462  }
463  noDifferenceFound = false;
464  break;
465  }
466  }
467  }
468  }
469  return noDifferenceFound;
470 }
471 
472 bool mitk::Equal(mitk::Surface *leftHandSide, mitk::Surface *rightHandSide, mitk::ScalarType eps, bool verbose)
473 {
474  if ((leftHandSide == nullptr) || (rightHandSide == nullptr))
475  {
476  MITK_ERROR << "mitk::Equal( mitk::Surface* leftHandSide, mitk::Surface* rightHandSide, mitk::ScalarType eps, bool "
477  "verbose ) does not work with NULL pointer input.";
478  return false;
479  }
480  return Equal(*leftHandSide, *rightHandSide, eps, verbose);
481 }
482 
483 bool mitk::Equal(mitk::Surface &leftHandSide, mitk::Surface &rightHandSide, mitk::ScalarType eps, bool verbose)
484 {
485  bool noDifferenceFound = true;
486 
487  if (!mitk::Equal(leftHandSide.GetSizeOfPolyDataSeries(), rightHandSide.GetSizeOfPolyDataSeries(), eps, verbose))
488  {
489  if (verbose)
490  MITK_INFO << "[Equal( mitk::surface&, mitk::surface& )] Size of PolyData series not equal.";
491  return false;
492  }
493 
494  // No mitk::Equal for TimeGeometry implemented.
495  // if( ! mitk::Equal( leftHandSide->GetTimeGeometry(), rightHandSide->GetTimeGeometry(), eps, verbose ) )
496  //{
497  // if(verbose)
498  // MITK_INFO << "[Equal( mitk::surface&, mitk::surface& )] Time sliced geometries not equal";
499  // noDifferenceFound = false;
500  //}
501 
502  for (unsigned int i(0); i < rightHandSide.GetSizeOfPolyDataSeries(); i++)
503  {
504  if (!mitk::Equal(*leftHandSide.GetVtkPolyData(i), *rightHandSide.GetVtkPolyData(i), eps, verbose))
505  {
506  if (verbose)
507  MITK_INFO << "[Equal( mitk::surface&, mitk::surface& )] Poly datas not equal.";
508  noDifferenceFound = false;
509  }
510  }
511 
512  return noDifferenceFound;
513 }
virtual bool VerifyRequestedRegion() override
Verify that the RequestedRegion is within the LargestPossibleRegion.
Class for storing surfaces (vtkPolyData).
Definition: mitkSurface.h:32
unsigned int GetSizeOfPolyDataSeries() const
virtual void SetRequestedRegion(const itk::DataObject *data) override
Set the requested region from this data object to match the requested region of the data object passe...
virtual ~Surface()
Definition: mitkSurface.cpp:77
#define MITK_INFO
Definition: mitkLogMacros.h:22
Base of all data objects.
Definition: mitkBaseData.h:39
Base class of all Operation-classes.
Definition: mitkOperation.h:33
#define MITK_ERROR
Definition: mitkLogMacros.h:24
double ScalarType
virtual vtkPolyData * GetVtkPolyData(unsigned int t=0) const
void CalculateBoundingBox()
static vtkSmartPointer< vtkPolyData > DeepCopy(vtkPolyData *other)
Definition: mitkSurface.cpp:24
virtual bool RequestedRegionIsOutsideOfTheBufferedRegion() override
Determine whether the RequestedRegion is outside of the BufferedRegion.
static void Update(vtkPolyData *)
Definition: mitkSurface.cpp:35
virtual void UpdateOutputInformation() override
const RegionType & GetLargestPossibleRegion() const
Definition: mitkSurface.cpp:89
Constants for most interaction classes, due to the generic StateMachines.
virtual void InitializeEmpty() override
Pure virtual; Must be used in subclasses to get a data object to a valid state. Should at least creat...
virtual void SetRequestedRegionToLargestPossibleRegion() override
Set the RequestedRegion to the LargestPossibleRegion.
virtual void Swap(Surface &other)
Definition: mitkSurface.cpp:63
#define mitkThrow()
virtual void SetVtkPolyData(vtkPolyData *polydata, unsigned int t=0)
virtual void ClearData() override
reset to non-initialized state, release memory
Definition: mitkSurface.cpp:82
MITKNEWMODULE_EXPORT bool Equal(mitk::ExampleDataStructure *leftHandSide, mitk::ExampleDataStructure *rightHandSide, mitk::ScalarType eps, bool verbose)
Returns true if the example data structures are considered equal.
static void swap(T &x, T &y)
Definition: svm.cpp:72
virtual BaseGeometry::Pointer GetGeometryForTimeStep(TimeStepType timeStep) const =0
Returns the geometry which corresponds to the given time step.
MITKCORE_EXPORT const ScalarType eps
virtual void Update() override
virtual void Graft(const DataObject *data) override
virtual void PrintSelf(std::ostream &os, itk::Indent indent) const override
virtual bool IsEmptyTimeStep(unsigned int t) const override
Check whether object contains data (at a specified time), e.g., a set of points may be empty...
OperationType GetOperationType()
itk::ImageRegion< 5 > RegionType
Definition: mitkSurface.h:35
void Update()
Updates the geometry.
virtual void CopyInformation(const itk::DataObject *data) override
virtual void ExecuteOperation(Operation *operation) override
overwrite if the Data can be called by an Interactor (StateMachine).
Surface & operator=(Surface other)
Definition: mitkSurface.cpp:71
virtual void Expand(unsigned int timeSteps=1) override
Expands the TimeGeometry to a number of TimeSteps.
virtual const RegionType & GetRequestedRegion() const
Definition: mitkSurface.cpp:97
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.