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