Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkStandaloneDataStorage.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 
18 
19 #include "itkMutexLockHolder.h"
20 #include "itkSimpleFastMutexLock.h"
21 #include "mitkDataNode.h"
22 #include "mitkGroupTagProperty.h"
23 #include "mitkNodePredicateBase.h"
25 #include "mitkProperties.h"
26 
28 {
29 }
30 
32 {
33  for (AdjacencyList::iterator it = m_SourceNodes.begin(); it != m_SourceNodes.end(); ++it)
34  {
35  this->RemoveListeners(it->first);
36  }
37 }
38 
40 {
41  return true;
42 }
43 
45 {
46  {
48  if (!IsInitialized())
49  throw std::logic_error("DataStorage not initialized");
50  /* check if node is in its own list of sources */
51  if ((parents != NULL) && (std::find(parents->begin(), parents->end(), node) != parents->end()))
52  throw std::invalid_argument("Node is it's own parent");
53  /* check if node already exists in StandaloneDataStorage */
54  if (m_SourceNodes.find(node) != m_SourceNodes.end())
55  throw std::invalid_argument("Node is already in DataStorage");
56 
57  /* create parent list if it does not exist */
59  if (parents != NULL)
60  sp = parents;
61  else
63  /* Store node and parent list in sources adjacency list */
64  m_SourceNodes.insert(std::make_pair(node, sp));
65 
66  /* Store node and an empty children list in derivations adjacency list */
68  mitk::DataStorage::SetOfObjects::ConstPointer children = childrenPointer.GetPointer();
69  m_DerivedNodes.insert(std::make_pair(node, children));
70 
71  /* create entry in derivations adjacency list for each parent of the new node */
72  for (SetOfObjects::ConstIterator it = sp->Begin(); it != sp->End(); it++)
73  {
74  mitk::DataNode::ConstPointer parent = it.Value().GetPointer();
76  m_DerivedNodes[parent]; // get or create pointer to list of derived objects for that parent node
77  if (derivedObjects.IsNull())
78  m_DerivedNodes[parent] =
79  mitk::DataStorage::SetOfObjects::New(); // Create a set of Objects, if it does not already exist
81  m_DerivedNodes[parent].GetPointer()); // temporarily get rid of const pointer to insert new element
82  deob->InsertElement(deob->Size(),
83  node); // node is derived from parent. Insert it into the parents list of derived objects
84  }
85 
86  // register for ITK changed events
87  this->AddListeners(node);
88  }
89 
90  /* Notify observers */
91  EmitAddNodeEvent(node);
92 }
93 
95 {
96  if (!IsInitialized())
97  throw std::logic_error("DataStorage not initialized");
98  if (node == NULL)
99  return;
100 
101  // remove ITK modified event listener
102  this->RemoveListeners(node);
103 
104  // muellerm, 22.9.10: add additional reference count to ensure
105  // that the node is not deleted when removed from the relation map
106  // while m_Mutex is locked. This would cause the an itk::DeleteEvent
107  // is thrown and a deadlock will occur when event receivers
108  // access the DataStorage again in their event processing function
109  //
110  mitk::DataNode::ConstPointer nodeGuard(node);
111 
112  /* Notify observers of imminent node removal */
113  EmitRemoveNodeEvent(node);
114  {
116  /* remove node from both relation adjacency lists */
117  this->RemoveFromRelation(node, m_SourceNodes);
118  this->RemoveFromRelation(node, m_DerivedNodes);
119  }
120 }
121 
123 {
125  return (m_SourceNodes.find(node) != m_SourceNodes.end());
126 }
127 
129 {
130  for (AdjacencyList::const_iterator mapIter = relation.cbegin(); mapIter != relation.cend();
131  ++mapIter) // for each node in the relation
132  if (mapIter->second.IsNotNull()) // if node has a relation list
133  {
135  const_cast<SetOfObjects *>(mapIter->second.GetPointer()); // search for node to be deleted in the relation list
136  SetOfObjects::STLContainerType::iterator relationListIter = std::find(
137  s->begin(),
138  s->end(),
139  node); // this assumes, that the relation list does not contain duplicates (which should be safe to assume)
140  if (relationListIter != s->end()) // if node to be deleted is in relation list
141  s->erase(relationListIter); // remove it from parentlist
142  }
143  /* now remove node from the relation */
144  AdjacencyList::iterator adIt;
145  adIt = relation.find(node);
146  if (adIt != relation.end())
147  relation.erase(adIt);
148 }
149 
151 {
153  if (!IsInitialized())
154  throw std::logic_error("DataStorage not initialized");
155 
157  /* Fill resultset with all objects that are managed by the StandaloneDataStorage object */
158  unsigned int index = 0;
159  for (AdjacencyList::const_iterator it = m_SourceNodes.cbegin(); it != m_SourceNodes.cend(); ++it)
160  if (it->first.IsNull())
161  continue;
162  else
163  resultset->InsertElement(index++, const_cast<mitk::DataNode *>(it->first.GetPointer()));
164 
165  return SetOfObjects::ConstPointer(resultset);
166 }
167 
169  const mitk::DataNode *node,
170  const AdjacencyList &relation,
171  const NodePredicateBase *condition,
172  bool onlyDirectlyRelated) const
173 {
174  if (node == NULL)
175  throw std::invalid_argument("invalid node");
176 
177  /* Either read direct relations directly from adjacency list */
178  if (onlyDirectlyRelated)
179  {
180  AdjacencyList::const_iterator it = relation.find(node); // get parents of current node
181  if ((it == relation.cend()) || (it->second.IsNull())) // node not found in list or no set of parents
182  return SetOfObjects::ConstPointer(mitk::DataStorage::SetOfObjects::New()); // return an empty set
183  else
184  return this->FilterSetOfObjects(it->second, condition);
185  }
186 
187  /* Or traverse adjacency list to collect all related nodes */
188  std::vector<mitk::DataNode::ConstPointer> resultset;
189  std::vector<mitk::DataNode::ConstPointer> openlist;
190 
191  /* Initialize openlist with node. this will add node to resultset,
192  but that is necessary to detect circular relations that would lead to endless recursion */
193  openlist.push_back(node);
194 
195  while (openlist.size() > 0)
196  {
197  mitk::DataNode::ConstPointer current = openlist.back(); // get element that needs to be processed
198  openlist.pop_back(); // remove last element, because it gets processed now
199  resultset.push_back(current); // add current element to resultset
200  AdjacencyList::const_iterator it = relation.find(current); // get parents of current node
201  if ((it == relation.cend()) // if node not found in list
202  ||
203  (it->second.IsNull()) // or no set of parents available
204  ||
205  (it->second->Size() == 0)) // or empty set of parents
206  continue; // then continue with next node in open list
207  else
208  for (SetOfObjects::ConstIterator parentIt = it->second->Begin(); parentIt != it->second->End();
209  ++parentIt) // for each parent of current node
210  {
211  mitk::DataNode::ConstPointer p = parentIt.Value().GetPointer();
212  if (!(std::find(resultset.cbegin(), resultset.cend(), p) !=
213  resultset.end()) // if it is not already in resultset
214  &&
215  !(std::find(openlist.cbegin(), openlist.cend(), p) != openlist.cend())) // and not already in openlist
216  openlist.push_back(p); // then add it to openlist, so that it can be processed
217  }
218  }
219 
220  /* now finally copy the results to a proper SetOfObjects variable exluding the initial node and checking the condition
221  * if any is given */
223  if (condition != NULL)
224  {
225  for (std::vector<mitk::DataNode::ConstPointer>::const_iterator resultIt = resultset.cbegin();
226  resultIt != resultset.cend();
227  ++resultIt)
228  if ((*resultIt != node) && (condition->CheckNode(*resultIt) == true))
229  realResultset->InsertElement(realResultset->Size(),
230  mitk::DataNode::Pointer(const_cast<mitk::DataNode *>((*resultIt).GetPointer())));
231  }
232  else
233  {
234  for (std::vector<mitk::DataNode::ConstPointer>::const_iterator resultIt = resultset.cbegin();
235  resultIt != resultset.cend();
236  ++resultIt)
237  if (*resultIt != node)
238  realResultset->InsertElement(realResultset->Size(),
239  mitk::DataNode::Pointer(const_cast<mitk::DataNode *>((*resultIt).GetPointer())));
240  }
241  return SetOfObjects::ConstPointer(realResultset);
242 }
243 
245  const mitk::DataNode *node, const NodePredicateBase *condition, bool onlyDirectSources) const
246 {
248  return this->GetRelations(node, m_SourceNodes, condition, onlyDirectSources);
249 }
250 
252  const mitk::DataNode *node, const NodePredicateBase *condition, bool onlyDirectDerivations) const
253 {
255  return this->GetRelations(node, m_DerivedNodes, condition, onlyDirectDerivations);
256 }
257 
258 void mitk::StandaloneDataStorage::PrintSelf(std::ostream &os, itk::Indent indent) const
259 {
260  os << indent << "StandaloneDataStorage:\n";
261  Superclass::PrintSelf(os, indent);
262 }
Data management class that handles 'was created by' relations.
itk::SmartPointer< Self > Pointer
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...
virtual void PrintSelf(std::ostream &os, itk::Indent indent) const override
Prints the contents of the StandaloneDataStorage to os. Do not call directly, call ->Print() instead...
SetOfObjects::ConstPointer GetSources(const mitk::DataNode *node, const NodePredicateBase *condition=nullptr, bool onlyDirectSources=true) const override
returns a set of source objects for a given node that meet the given condition(s).
DataCollection - Class to facilitate loading/accessing structured data.
virtual bool Exists(const mitk::DataNode *node) const override
Checks if a node exists in the StandaloneDataStorage.
itk::SmartPointer< const Self > ConstPointer
virtual bool CheckNode(const mitk::DataNode *node) const =0
This method will be used to evaluate the node. Has to be overwritten in subclasses.
itk::SmartPointer< Self > Pointer
Definition: mitkDataNode.h:81
virtual ~StandaloneDataStorage()
Standard Destructor.
bool IsInitialized() const
convenience method to check if the object has been initialized (i.e. a data tree has been set) ...
SetOfObjects::ConstPointer GetDerivations(const mitk::DataNode *node, const NodePredicateBase *condition=nullptr, bool onlyDirectDerivations=true) const override
returns a set of derived objects for a given node.
void Add(mitk::DataNode *node, const mitk::DataStorage::SetOfObjects *parents=nullptr) override
Adds a DataNode containing a data object to its internal storage.
void Remove(const mitk::DataNode *node) override
Removes node from the StandaloneDataStorage.
SetOfObjects::ConstPointer GetAll() const override
returns a set of all data objects that are stored in the data storage
Interface for evaluation conditions used in the DataStorage class GetSubset() method.
StandaloneDataStorage()
Standard Constructor for New() instantiation.
void RemoveFromRelation(const mitk::DataNode *node, AdjacencyList &relation)
deletes all references to a node in a given relation (used in Remove() and TreeListener) ...
SetOfObjects::ConstPointer GetRelations(const mitk::DataNode *node, const AdjacencyList &relation, const NodePredicateBase *condition=nullptr, bool onlyDirectlyRelated=true) const
Traverses the Relation graph and extracts a list of related elements (e.g. Sources or Derivations) ...
std::map< mitk::DataNode::ConstPointer, SetOfObjects::ConstPointer > AdjacencyList
noncyclical directed graph data structure to store the nodes with their relation
Class for nodes of the DataTree.
Definition: mitkDataNode.h:66
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.