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
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.