Medical Imaging Interaction Toolkit  2016.11.0
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,
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.