Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkDataStorage.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 "mitkDataStorage.h"
18 
19 #include "itkCommand.h"
20 #include "itkMutexLockHolder.h"
21 #include "mitkDataNode.h"
22 #include "mitkGroupTagProperty.h"
23 #include "mitkImage.h"
24 #include "mitkNodePredicateBase.h"
26 #include "mitkProperties.h"
27 
28 mitk::DataStorage::DataStorage() : itk::Object(), m_BlockNodeModifiedEvents(false)
29 {
30 }
31 
33 {
35  // SetOfObjects::ConstPointer all = this->GetAll();
36  // for (SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it)
37  // this->RemoveListeners(it->Value());
38  // m_NodeModifiedObserverTags.clear();
39  // m_NodeDeleteObserverTags.clear();
40 }
41 
43 {
45  if (parent != NULL) //< Return empty set if parent is null
46  parents->InsertElement(0, parent);
47  this->Add(node, parents);
48 }
49 
51 {
52  if (nodes == NULL)
53  return;
54  for (mitk::DataStorage::SetOfObjects::ConstIterator it = nodes->Begin(); it != nodes->End(); it++)
55  this->Remove(it.Value());
56 }
57 
59 {
60  mitk::DataStorage::SetOfObjects::ConstPointer result = this->FilterSetOfObjects(this->GetAll(), condition);
61  return result;
62 }
63 
65 
66 {
67  if (name == NULL)
68  return NULL;
69 
72  mitk::DataStorage::SetOfObjects::ConstPointer rs = this->GetSubset(p);
73  if (rs->Size() >= 1)
74  return rs->GetElement(0);
75  else
76  return NULL;
77 }
78 
80 {
81  if (condition == NULL)
82  return NULL;
83 
84  mitk::DataStorage::SetOfObjects::ConstPointer rs = this->GetSubset(condition);
85  if (rs->Size() >= 1)
86  return rs->GetElement(0);
87  else
88  return NULL;
89 }
90 
92  const mitk::DataNode *sourceNode,
93  bool onlyDirectDerivations) const
94 {
95  if (name == NULL)
96  return NULL;
97 
100  mitk::DataStorage::SetOfObjects::ConstPointer rs = this->GetDerivations(sourceNode, p, onlyDirectDerivations);
101  if (rs->Size() >= 1)
102  return rs->GetElement(0);
103  else
104  return NULL;
105 }
106 
107 void mitk::DataStorage::PrintSelf(std::ostream &os, itk::Indent indent) const
108 {
109  // Superclass::PrintSelf(os, indent);
111  os << indent << "DataStorage " << this << " is managing " << all->Size() << " objects. List of objects:" << std::endl;
112  for (mitk::DataStorage::SetOfObjects::ConstIterator allIt = all->Begin(); allIt != all->End(); allIt++)
113  {
114  std::string name;
115  allIt.Value()->GetName(name);
116  std::string datatype;
117  if (allIt.Value()->GetData() != NULL)
118  datatype = allIt.Value()->GetData()->GetNameOfClass();
119  os << indent << " " << allIt.Value().GetPointer() << "<" << datatype << ">: " << name << std::endl;
120  mitk::DataStorage::SetOfObjects::ConstPointer parents = this->GetSources(allIt.Value());
121  if (parents->Size() > 0)
122  {
123  os << indent << " Direct sources: ";
124  for (mitk::DataStorage::SetOfObjects::ConstIterator parentIt = parents->Begin(); parentIt != parents->End();
125  parentIt++)
126  os << parentIt.Value().GetPointer() << ", ";
127  os << std::endl;
128  }
129  mitk::DataStorage::SetOfObjects::ConstPointer derivations = this->GetDerivations(allIt.Value());
130  if (derivations->Size() > 0)
131  {
132  os << indent << " Direct derivations: ";
133  for (mitk::DataStorage::SetOfObjects::ConstIterator derivationIt = derivations->Begin();
134  derivationIt != derivations->End();
135  derivationIt++)
136  os << derivationIt.Value().GetPointer() << ", ";
137  os << std::endl;
138  }
139  }
140  os << std::endl;
141 }
142 
144  const SetOfObjects *set, const NodePredicateBase *condition) const
145 {
146  if (set == NULL)
147  return NULL;
148 
150  for (mitk::DataStorage::SetOfObjects::ConstIterator it = set->Begin(); it != set->End(); it++)
151  if (condition == NULL ||
152  condition->CheckNode(it.Value()) ==
153  true) // alway copy the set, otherwise the iterator in mitk::DataStorage::Remove() will crash
154  result->InsertElement(result->Size(), it.Value());
155 
157 }
158 
160 {
161  DataNode::GroupTagList result;
162  SetOfObjects::ConstPointer all = this->GetAll();
163  if (all.IsNull())
164  return result;
165 
166  for (mitk::DataStorage::SetOfObjects::ConstIterator nodeIt = all->Begin(); nodeIt != all->End();
167  nodeIt++) // for each node
168  {
169  mitk::PropertyList *pl = nodeIt.Value()->GetPropertyList();
170  for (mitk::PropertyList::PropertyMap::const_iterator propIt = pl->GetMap()->begin(); propIt != pl->GetMap()->end();
171  ++propIt)
172  if (dynamic_cast<mitk::GroupTagProperty *>(propIt->second.GetPointer()) != NULL)
173  result.insert(propIt->first);
174  }
175 
176  return result;
177 }
178 
180 {
181  AddNodeEvent.Send(node);
182 }
183 
185 {
186  RemoveNodeEvent.Send(node);
187 }
188 
189 void mitk::DataStorage::OnNodeInteractorChanged(itk::Object *caller, const itk::EventObject &)
190 {
191  const mitk::DataNode *_Node = dynamic_cast<const mitk::DataNode *>(caller);
192  if (_Node)
193  {
194  InteractorChangedNodeEvent.Send(_Node);
195  }
196 }
197 
198 void mitk::DataStorage::OnNodeModifiedOrDeleted(const itk::Object *caller, const itk::EventObject &event)
199 {
200  if (m_BlockNodeModifiedEvents)
201  return;
202 
203  const mitk::DataNode *_Node = dynamic_cast<const mitk::DataNode *>(caller);
204  if (_Node)
205  {
206  const itk::ModifiedEvent *modEvent = dynamic_cast<const itk::ModifiedEvent *>(&event);
207  if (modEvent)
208  ChangedNodeEvent.Send(_Node);
209  else
210  DeleteNodeEvent.Send(_Node);
211  }
212 }
213 
215 {
217  // node must not be 0 and must not be yet registered
218  mitk::DataNode *NonConstNode = const_cast<mitk::DataNode *>(_Node);
219  if (_Node && m_NodeModifiedObserverTags.find(NonConstNode) == m_NodeModifiedObserverTags.end())
220  {
222  nodeModifiedCommand->SetCallbackFunction(this, &mitk::DataStorage::OnNodeModifiedOrDeleted);
223  m_NodeModifiedObserverTags[NonConstNode] = NonConstNode->AddObserver(itk::ModifiedEvent(), nodeModifiedCommand);
224 
225  itk::MemberCommand<mitk::DataStorage>::Pointer interactorChangedCommand =
227  interactorChangedCommand->SetCallbackFunction(this, &mitk::DataStorage::OnNodeInteractorChanged);
228  m_NodeInteractorChangedObserverTags[NonConstNode] =
229  NonConstNode->AddObserver(mitk::DataNode::InteractorChangedEvent(), interactorChangedCommand);
230 
231  // add itk delete listener on datastorage
233  deleteCommand->SetCallbackFunction(this, &mitk::DataStorage::OnNodeModifiedOrDeleted);
234  // add observer
235  m_NodeDeleteObserverTags[NonConstNode] = NonConstNode->AddObserver(itk::DeleteEvent(), deleteCommand);
236  }
237 }
238 
240 {
242  // node must not be 0 and must be registered
243  mitk::DataNode *NonConstNode = const_cast<mitk::DataNode *>(_Node);
244  if (_Node && m_NodeModifiedObserverTags.find(NonConstNode) != m_NodeModifiedObserverTags.end())
245  {
246  // const cast is bad! but sometimes it is necessary. removing an observer does not really
247  // touch the internal state
248  NonConstNode->RemoveObserver(m_NodeModifiedObserverTags.find(NonConstNode)->second);
249  NonConstNode->RemoveObserver(m_NodeDeleteObserverTags.find(NonConstNode)->second);
250  NonConstNode->RemoveObserver(m_NodeInteractorChangedObserverTags.find(NonConstNode)->second);
251 
252  m_NodeModifiedObserverTags.erase(NonConstNode);
253  m_NodeDeleteObserverTags.erase(NonConstNode);
254  m_NodeInteractorChangedObserverTags.erase(NonConstNode);
255  }
256 }
257 
259  const char *boolPropertyKey,
260  const mitk::BaseRenderer *renderer,
261  const char *boolPropertyKey2) const
262 {
263  if (input == NULL)
264  throw std::invalid_argument("DataStorage: input is invalid");
265 
267 
268  BoundingBox::PointIdentifier pointid = 0;
269  Point3D point;
270 
271  Vector3D minSpacing;
273 
274  ScalarType stmin, stmax;
275  stmin = itk::NumericTraits<mitk::ScalarType>::NonpositiveMin();
277 
278  ScalarType minimalIntervallSize = stmax;
279  ScalarType minimalTime = stmax;
280  ScalarType maximalTime = 0;
281 
282  // Needed for check of zero bounding boxes
283  mitk::ScalarType nullpoint[] = {0, 0, 0, 0, 0, 0};
284  BoundingBox::BoundsArrayType itkBoundsZero(nullpoint);
285 
286  for (SetOfObjects::ConstIterator it = input->Begin(); it != input->End(); ++it)
287  {
288  DataNode::Pointer node = it->Value();
289  if ((node.IsNotNull()) && (node->GetData() != NULL) && (node->GetData()->IsEmpty() == false) &&
290  node->IsOn(boolPropertyKey, renderer) && node->IsOn(boolPropertyKey2, renderer))
291  {
292  const TimeGeometry *timeGeometry = node->GetData()->GetUpdatedTimeGeometry();
293 
294  if (timeGeometry != NULL)
295  {
296  // bounding box (only if non-zero)
297  BoundingBox::BoundsArrayType itkBounds = timeGeometry->GetBoundingBoxInWorld()->GetBounds();
298  if (itkBounds == itkBoundsZero)
299  {
300  continue;
301  }
302 
303  unsigned char i;
304  for (i = 0; i < 8; ++i)
305  {
306  point = timeGeometry->GetCornerPointInWorld(i);
307  if (point[0] * point[0] + point[1] * point[1] + point[2] * point[2] < large)
308  pointscontainer->InsertElement(pointid++, point);
309  else
310  {
311  itkGenericOutputMacro(<< "Unrealistically distant corner point encountered. Ignored. Node: " << node);
312  }
313  }
314  try
315  {
316  // time bounds
317  // iterate over all time steps
318  // Attention: Objects with zero bounding box are not respected in time bound calculation
319  for (TimeStepType i = 0; i < timeGeometry->CountTimeSteps(); i++)
320  {
321  // We must not use 'node->GetData()->GetGeometry(i)->GetSpacing()' here, as it returns the spacing
322  // in its original space, which, in case of an image geometry, can have the values in different
323  // order than in world space. For the further calculations, we need to have the spacing values
324  // in world coordinate order (sag-cor-ax).
325  Vector3D spacing;
326  spacing.Fill(1.0);
327  node->GetData()->GetGeometry(i)->IndexToWorld(spacing, spacing);
328  for (int axis = 0; axis < 3; ++ axis)
329  {
330  ScalarType space = std::abs(spacing[axis]);
331  if (space < minSpacing[axis])
332  {
333  minSpacing[axis] = space;
334  }
335  }
336 
337  const TimeBounds &curTimeBounds = node->GetData()->GetTimeGeometry()->GetTimeBounds(i);
338  // get the minimal time of all objects in the DataStorage
339  if ((curTimeBounds[0] < minimalTime) && (curTimeBounds[0] > stmin))
340  {
341  minimalTime = curTimeBounds[0];
342  }
343  // get the maximal time of all objects in the DataStorage
344  if ((curTimeBounds[1] > maximalTime) && (curTimeBounds[1] < stmax))
345  {
346  maximalTime = curTimeBounds[1];
347  }
348  // get the minimal TimeBound of all time steps of the current DataNode
349  if (curTimeBounds[1] - curTimeBounds[0] < minimalIntervallSize)
350  {
351  minimalIntervallSize = curTimeBounds[1] - curTimeBounds[0];
352  }
353  }
354  }
355  catch (itk::ExceptionObject &e)
356  {
357  MITK_ERROR << e << std::endl;
358  }
359  }
360  }
361  }
362 
364  result->SetPoints(pointscontainer);
365  result->ComputeBoundingBox();
366 
367  // compute the number of time steps
368  unsigned int numberOfTimeSteps = 1;
369  if (maximalTime == 0) // make sure that there is at least one time sliced geometry in the data storage
370  {
371  minimalTime = 0;
372  maximalTime = 1;
373  minimalIntervallSize = 1;
374  }
375  numberOfTimeSteps = static_cast<unsigned int>((maximalTime - minimalTime) / minimalIntervallSize);
376 
377  TimeGeometry::Pointer timeGeometry = NULL;
378  if (result->GetPoints()->Size() > 0)
379  {
380  // Initialize a geometry of a single time step
382  geometry->Initialize();
383  // correct bounding-box (is now in mm, should be in index-coordinates)
384  // according to spacing
385  BoundingBox::BoundsArrayType bounds = result->GetBounds();
386  AffineTransform3D::OutputVectorType offset;
387  for (int i = 0; i < 3; ++i)
388  {
389  offset[i] = bounds[i * 2];
390  bounds[i * 2] = 0.0;
391  bounds[i * 2 + 1] = (bounds[i * 2 + 1] - offset[i]) / minSpacing[i];
392  }
393  geometry->GetIndexToWorldTransform()->SetOffset(offset);
394  geometry->SetBounds(bounds);
395  geometry->SetSpacing(minSpacing);
396  // Initialize the time sliced geometry
397  timeGeometry = ProportionalTimeGeometry::New();
398  dynamic_cast<ProportionalTimeGeometry *>(timeGeometry.GetPointer())->Initialize(geometry, numberOfTimeSteps);
399  dynamic_cast<ProportionalTimeGeometry *>(timeGeometry.GetPointer())->SetFirstTimePoint(minimalTime);
400  dynamic_cast<ProportionalTimeGeometry *>(timeGeometry.GetPointer())->SetStepDuration(minimalIntervallSize);
401  }
402  return timeGeometry;
403 }
404 
406  const mitk::BaseRenderer *renderer,
407  const char *boolPropertyKey2) const
408 {
409  return this->ComputeBoundingGeometry3D(this->GetAll(), boolPropertyKey, renderer, boolPropertyKey2);
410 }
411 
413  const char *boolPropertyKey)
414 {
415  return ComputeBoundingGeometry3D("visible", renderer, boolPropertyKey);
416 }
417 
419  const mitk::BaseRenderer *renderer,
420  const char *boolPropertyKey2)
421 {
423 
424  BoundingBox::PointIdentifier pointid = 0;
425  Point3D point;
426 
427  // Needed for check of zero bounding boxes
428  mitk::ScalarType nullpoint[] = {0, 0, 0, 0, 0, 0};
429  BoundingBox::BoundsArrayType itkBoundsZero(nullpoint);
430 
431  SetOfObjects::ConstPointer all = this->GetAll();
432  for (SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it)
433  {
434  DataNode::Pointer node = it->Value();
435  if ((node.IsNotNull()) && (node->GetData() != NULL) && (node->GetData()->IsEmpty() == false) &&
436  node->IsOn(boolPropertyKey, renderer) && node->IsOn(boolPropertyKey2, renderer))
437  {
438  const TimeGeometry *geometry = node->GetData()->GetUpdatedTimeGeometry();
439  if (geometry != NULL)
440  {
441  // bounding box (only if non-zero)
442  BoundingBox::BoundsArrayType itkBounds = geometry->GetBoundingBoxInWorld()->GetBounds();
443  if (itkBounds == itkBoundsZero)
444  {
445  continue;
446  }
447 
448  unsigned char i;
449  for (i = 0; i < 8; ++i)
450  {
451  point = geometry->GetCornerPointInWorld(i);
452  if (point[0] * point[0] + point[1] * point[1] + point[2] * point[2] < large)
453  pointscontainer->InsertElement(pointid++, point);
454  else
455  {
456  itkGenericOutputMacro(<< "Unrealistically distant corner point encountered. Ignored. Node: " << node);
457  }
458  }
459  }
460  }
461  }
462 
464  result->SetPoints(pointscontainer);
465  result->ComputeBoundingBox();
466 
467  return result;
468 }
469 
471  const mitk::BaseRenderer *renderer,
472  const char *boolPropertyKey2)
473 {
474  TimeBounds timeBounds;
475 
476  ScalarType stmin, stmax, cur;
477 
478  stmin = itk::NumericTraits<mitk::ScalarType>::NonpositiveMin();
480 
481  timeBounds[0] = stmax;
482  timeBounds[1] = stmin;
483 
484  SetOfObjects::ConstPointer all = this->GetAll();
485  for (SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it)
486  {
487  DataNode::Pointer node = it->Value();
488  if ((node.IsNotNull()) && (node->GetData() != NULL) && (node->GetData()->IsEmpty() == false) &&
489  node->IsOn(boolPropertyKey, renderer) && node->IsOn(boolPropertyKey2, renderer))
490  {
491  const TimeGeometry *geometry = node->GetData()->GetUpdatedTimeGeometry();
492  if (geometry != NULL)
493  {
494  const TimeBounds &curTimeBounds = geometry->GetTimeBounds();
495  cur = curTimeBounds[0];
496  // is it after -infinity, but before everything else that we found until now?
497  if ((cur > stmin) && (cur < timeBounds[0]))
498  timeBounds[0] = cur;
499 
500  cur = curTimeBounds[1];
501  // is it before infinity, but after everything else that we found until now?
502  if ((cur < stmax) && (cur > timeBounds[1]))
503  timeBounds[1] = cur;
504  }
505  }
506  }
507  if (!(timeBounds[0] < stmax))
508  {
509  timeBounds[0] = stmin;
510  timeBounds[1] = stmax;
511  }
512  return timeBounds;
513 }
514 
516 {
517  m_BlockNodeModifiedEvents = block;
518 }
mitk::DataNode * GetNode(const NodePredicateBase *condition=nullptr) const
Convenience method to get the first node that matches the predicate condition.
virtual void Add(mitk::DataNode *node, const mitk::DataStorage::SetOfObjects *parents=nullptr)=0
Adds a DataNode containing a data object to its internal storage.
itk::SmartPointer< Self > Pointer
DataStorage()
Standard Constructor for New() instantiation.
std::set< std::string > GroupTagList
Definition: mitkDataNode.h:73
itk::VectorContainer< unsigned int, mitk::DataNode::Pointer > SetOfObjects
A Container of objects that is used as a result set of GetSubset() query operations (Set of...
itk::FixedArray< ScalarType, 2 > TimeBounds
Standard typedef for time-bounds.
BoundingBox * GetBoundingBoxInWorld() const
Returns a bounding box that covers all time steps.
#define MITK_ERROR
Definition: mitkLogMacros.h:24
double ScalarType
Organizes the rendering process.
virtual void PrintSelf(std::ostream &os, itk::Indent indent) const override
Prints the contents of the DataStorage to os. Do not call directly, call ->Print() instead...
void AddListeners(const mitk::DataNode *_Node)
Adds a Modified-Listener to the given Node.
SetOfObjects::ConstPointer FilterSetOfObjects(const SetOfObjects *set, const NodePredicateBase *condition) const
Filters a SetOfObjects by the condition. If no condition is provided, the original set is returned...
Key-value list holding instances of BaseProperty.
static Pointer New()
Point3D GetCornerPointInWorld(int id) const
Get the position of the corner number id (in world coordinates)
itk::SmartPointer< const Self > ConstPointer
mitk::TimeGeometry::Pointer ComputeVisibleBoundingGeometry3D(const mitk::BaseRenderer *renderer=nullptr, const char *boolPropertyKey=nullptr)
Compute the axis-parallel bounding geometry of all visible parts of the data tree bounding box...
virtual bool CheckNode(const mitk::DataNode *node) const =0
This method will be used to evaluate the node. Has to be overwritten in subclasses.
static Vector3D offset
const DataNode::GroupTagList GetGroupTags() const
Returns a list of used grouptags.
void BlockNodeModifiedEvents(bool block)
Defines whether or not NodeChangedEvent is invoked .
mitk::TimeBounds ComputeTimeBounds(const char *boolPropertyKey, const mitk::BaseRenderer *renderer, const char *boolPropertyKey2)
Compute the time-bounds of the contents of a data tree structure.
virtual TimeBounds GetTimeBounds() const =0
Get the time bounds (in ms)
SetOfObjects::ConstPointer GetSubset(const NodePredicateBase *condition) const
returns a set of data objects that meet the given condition(s)
void OnNodeInteractorChanged(itk::Object *caller, const itk::EventObject &event)
void EmitAddNodeEvent(const mitk::DataNode *node)
EmitAddNodeEvent emits the AddNodeEvent.
mitk::DataNode * GetNamedDerivedNode(const char *name, const mitk::DataNode *sourceNode, bool onlyDirectDerivations=true) const
Convenience method to get the first node with a given name that is derived from sourceNode.
void OnNodeModifiedOrDeleted(const itk::Object *caller, const itk::EventObject &event)
OnNodeModified listens to modified events of DataNodes.
std::vcl_size_t TimeStepType
static T max(T x, T y)
Definition: svm.cpp:70
static Pointer New(const char *_arg)
MITKCORE_EXPORT const double large
void RemoveListeners(const mitk::DataNode *_Node)
Removes a Modified-Listener from the given Node.
mitk::TimeGeometry::Pointer ComputeBoundingGeometry3D(const SetOfObjects *input, const char *boolPropertyKey=nullptr, const mitk::BaseRenderer *renderer=nullptr, const char *boolPropertyKey2=nullptr) const
Compute the axis-parallel bounding geometry of the input objects.
mitk::BoundingBox::Pointer ComputeBoundingBox(const char *boolPropertyKey=nullptr, const mitk::BaseRenderer *renderer=nullptr, const char *boolPropertyKey2=nullptr)
Compute the bounding box of data tree structure it -> an iterator to a data tree structure.
void EmitRemoveNodeEvent(const mitk::DataNode *node)
EmitRemoveNodeEvent emits the RemoveNodeEvent.
Interface for evaluation conditions used in the DataStorage class GetSubset() method.
virtual void Remove(const mitk::DataNode *node)=0
Removes node from the DataStorage.
mitk::DataNode * GetNamedNode(const char *name) const
Convenience method to get the first node with a given name.
static Pointer New()
virtual ~DataStorage()
Standard Destructor.
Class for nodes of the DataTree.
Definition: mitkDataNode.h:66
const PropertyMap * GetMap() const
BoundingBoxType::BoundsArrayType BoundsArrayType
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.