diff --git a/Core/Code/DataManagement/mitkDataStorage.cpp b/Core/Code/DataManagement/mitkDataStorage.cpp index fab3f6ac75..b524d29765 100644 --- a/Core/Code/DataManagement/mitkDataStorage.cpp +++ b/Core/Code/DataManagement/mitkDataStorage.cpp @@ -1,553 +1,481 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkDataStorage.h" #include "mitkDataTreeNode.h" #include "mitkProperties.h" #include "mitkNodePredicateBase.h" #include "mitkNodePredicateProperty.h" #include "mitkGroupTagProperty.h" #include "itkCommand.h" mitk::DataStorage::DataStorage() : itk::Object() , m_BlockNodeModifiedEvents(false) { } mitk::DataStorage::~DataStorage() { ///// we can not call GetAll() in destructor, because it is implemented in a subclass //SetOfObjects::ConstPointer all = this->GetAll(); //for (SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) // this->RemoveListeners(it->Value()); //m_NodeModifiedObserverTags.clear(); //m_NodeDeleteObserverTags.clear(); } void mitk::DataStorage::Add(mitk::DataTreeNode* node, mitk::DataTreeNode* parent) { mitk::DataStorage::SetOfObjects::Pointer parents = mitk::DataStorage::SetOfObjects::New(); parents->InsertElement(0, parent); this->Add(node, parents); } void mitk::DataStorage::Remove(const mitk::DataStorage::SetOfObjects* nodes) { if (nodes == NULL) return; for (mitk::DataStorage::SetOfObjects::ConstIterator it = nodes->Begin(); it != nodes->End(); it++) this->Remove(it.Value()); } mitk::DataStorage::SetOfObjects::ConstPointer mitk::DataStorage::GetSubset(const NodePredicateBase* condition) const { mitk::DataStorage::SetOfObjects::ConstPointer result = this->FilterSetOfObjects(this->GetAll(), condition); return result; } mitk::DataTreeNode* mitk::DataStorage::GetNamedNode(const char* name) const { if (name == NULL) return NULL; mitk::StringProperty::Pointer s(mitk::StringProperty::New(name)); mitk::NodePredicateProperty::Pointer p = mitk::NodePredicateProperty::New("name", s); mitk::DataStorage::SetOfObjects::ConstPointer rs = this->GetSubset(p); if (rs->Size() >= 1) return rs->GetElement(0); else return NULL; } mitk::DataTreeNode* mitk::DataStorage::GetNode(const NodePredicateBase* condition) const { if (condition == NULL) return NULL; mitk::DataStorage::SetOfObjects::ConstPointer rs = this->GetSubset(condition); if (rs->Size() >= 1) return rs->GetElement(0); else return NULL; } mitk::DataTreeNode* mitk::DataStorage::GetNamedDerivedNode(const char* name, const mitk::DataTreeNode* sourceNode, bool onlyDirectDerivations) const { if (name == NULL) return NULL; mitk::StringProperty::Pointer s(mitk::StringProperty::New(name)); mitk::NodePredicateProperty::Pointer p = mitk::NodePredicateProperty::New("name", s); mitk::DataStorage::SetOfObjects::ConstPointer rs = this->GetDerivations(sourceNode, p, onlyDirectDerivations); if (rs->Size() >= 1) return rs->GetElement(0); else return NULL; } void mitk::DataStorage::PrintSelf(std::ostream& os, itk::Indent indent) const { //Superclass::PrintSelf(os, indent); mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetAll(); os << indent << "DataStorage " << this << " is managing " << all->Size() << " objects. List of objects:" << std::endl; for (mitk::DataStorage::SetOfObjects::ConstIterator allIt = all->Begin(); allIt != all->End(); allIt++) { std::string name; allIt.Value()->GetName(name); std::string datatype; if (allIt.Value()->GetData() != NULL) datatype = allIt.Value()->GetData()->GetNameOfClass(); os << indent << " " << allIt.Value().GetPointer() << "<" << datatype << ">: " << name << std::endl; mitk::DataStorage::SetOfObjects::ConstPointer parents = this->GetSources(allIt.Value()); if (parents->Size() > 0) { os << indent << " Direct sources: "; for (mitk::DataStorage::SetOfObjects::ConstIterator parentIt = parents->Begin(); parentIt != parents->End(); parentIt++) os << parentIt.Value().GetPointer() << ", "; os << std::endl; } mitk::DataStorage::SetOfObjects::ConstPointer derivations = this->GetDerivations(allIt.Value()); if (derivations->Size() > 0) { os << indent << " Direct derivations: "; for (mitk::DataStorage::SetOfObjects::ConstIterator derivationIt = derivations->Begin(); derivationIt != derivations->End(); derivationIt++) os << derivationIt.Value().GetPointer() << ", "; os << std::endl; } } os << std::endl; } mitk::DataStorage::SetOfObjects::ConstPointer mitk::DataStorage::FilterSetOfObjects(const SetOfObjects* set, const NodePredicateBase* condition) const { if (set == NULL) return NULL; if (condition == NULL) return set; mitk::DataStorage::SetOfObjects::Pointer result = mitk::DataStorage::SetOfObjects::New(); for (mitk::DataStorage::SetOfObjects::ConstIterator it = set->Begin(); it != set->End(); it++) if (condition->CheckNode(it.Value()) == true) result->InsertElement(result->Size(), it.Value()); return mitk::DataStorage::SetOfObjects::ConstPointer(result); } const mitk::DataTreeNode::GroupTagList mitk::DataStorage::GetGroupTags() const { DataTreeNode::GroupTagList result; SetOfObjects::ConstPointer all = this->GetAll(); if (all.IsNull()) return result; for (mitk::DataStorage::SetOfObjects::ConstIterator nodeIt = all->Begin(); nodeIt != all->End(); nodeIt++) // for each node { mitk::PropertyList* pl = nodeIt.Value()->GetPropertyList(); for (mitk::PropertyList::PropertyMap::const_iterator propIt = pl->GetMap()->begin(); propIt != pl->GetMap()->end(); propIt++) if (dynamic_cast(propIt->second.first.GetPointer()) != NULL) result.insert(propIt->first); } return result; } void mitk::DataStorage::EmitAddNodeEvent(const mitk::DataTreeNode* node) { AddNodeEvent.Send(node); } void mitk::DataStorage::EmitRemoveNodeEvent(const mitk::DataTreeNode* node) { RemoveNodeEvent.Send(node); } void mitk::DataStorage::OnNodeModifiedOrDeleted( const itk::Object *caller, const itk::EventObject &event ) { if(m_BlockNodeModifiedEvents) return; const mitk::DataTreeNode* _Node = dynamic_cast(caller); if(_Node) { const itk::ModifiedEvent* modEvent = dynamic_cast(&event); if(modEvent) ChangedNodeEvent.Send(_Node); else DeleteNodeEvent.Send(_Node); } } void mitk::DataStorage::AddListeners( const mitk::DataTreeNode* _Node ) { // node must not be 0 and must not be yet registered if(_Node && m_NodeModifiedObserverTags.find(_Node) == m_NodeModifiedObserverTags.end()) { itk::MemberCommand::Pointer nodeModifiedCommand = itk::MemberCommand::New(); nodeModifiedCommand->SetCallbackFunction(this, &mitk::DataStorage::OnNodeModifiedOrDeleted); m_NodeModifiedObserverTags[_Node] = _Node->AddObserver(itk::ModifiedEvent(), nodeModifiedCommand); // add itk delete listener on datastorage itk::MemberCommand::Pointer deleteCommand = itk::MemberCommand::New(); deleteCommand->SetCallbackFunction(this, &mitk::DataStorage::OnNodeModifiedOrDeleted); // add observer m_NodeDeleteObserverTags[_Node] = _Node->AddObserver(itk::DeleteEvent(), deleteCommand); } } void mitk::DataStorage::RemoveListeners( const mitk::DataTreeNode* _Node ) { // node must not be 0 and must be registered if(_Node && m_NodeModifiedObserverTags.find(_Node) != m_NodeModifiedObserverTags.end()) { // const cast is bad! but sometimes it is necessary. removing an observer does not really // touch the internal state mitk::DataTreeNode* NonConstNode = const_cast(_Node); NonConstNode->RemoveObserver(m_NodeModifiedObserverTags.find(_Node)->second); NonConstNode->RemoveObserver(m_NodeDeleteObserverTags.find(_Node)->second); } } -mitk::Geometry3D::Pointer mitk::DataStorage::ComputeBoundingGeometry3D( const SetOfObjects* input) +mitk::TimeSlicedGeometry::Pointer mitk::DataStorage::ComputeBoundingGeometry3D( const SetOfObjects* input, const char* boolPropertyKey, mitk::BaseRenderer* renderer, const char* boolPropertyKey2) { if (input == NULL) throw std::invalid_argument("DataStorage: input is invalid"); - BoundingBox::PointsContainer::Pointer pointscontainer = BoundingBox::PointsContainer::New(); - BoundingBox::PointIdentifier pointid = 0; - Point3D point; - Vector3D minSpacing; - minSpacing.Fill(ScalarTypeNumericTraits::max()); - - TimeBounds timeBounds; - ScalarType stmin, stmax; - stmin = ScalarTypeNumericTraits::NonpositiveMin(); - stmax = ScalarTypeNumericTraits::max(); - - timeBounds[0] = stmax; - timeBounds[1] = stmin; - - for (SetOfObjects::ConstIterator it = input->Begin(); it != input->End(); ++it) - { - DataTreeNode::Pointer node = it->Value(); - if (node.IsNull()) - continue; - if (node->GetData() == NULL) - continue; - if (node->GetData()->IsEmpty()) - continue; - - const Geometry3D* geometry = node->GetData()->GetUpdatedTimeSlicedGeometry(); - if (geometry == NULL ) - continue; - - - // bounding box - - for(int i = 0; i < 8; ++i) - { - point = geometry->GetCornerPoint(i); - if (point[0]*point[0]+point[1]*point[1]+point[2]*point[2] < large) - { - pointscontainer->InsertElement( pointid++, point); - } - else - { - itkGenericOutputMacro( << "Unrealistically distant corner point encountered. Ignored. Node: " << node ); - } - } - // spacing - try - { - AffineTransform3D::Pointer inverseTransform = AffineTransform3D::New(); - geometry->GetIndexToWorldTransform()->GetInverse(inverseTransform); - vnl_vector< AffineTransform3D::MatrixType::ValueType > unitVector(3); - for (unsigned int axis = 0; axis < 3; ++axis) - { - unitVector.fill(0); - unitVector[axis] = 1.0; - ScalarType mmPerPixel = 1.0 / (inverseTransform->GetMatrix()*unitVector).magnitude(); - if (minSpacing[axis] > mmPerPixel) - minSpacing[axis] = mmPerPixel; - } - // timebounds - const TimeBounds& curTimeBounds = geometry->GetTimeBounds(); - ScalarType cur = curTimeBounds[0]; - //is it after -infinity, but before everything else that we found until now? - if ((cur > stmin) && (cur < timeBounds[0])) - timeBounds[0] = cur; - - cur = curTimeBounds[1]; - //is it before infinity, but after everything else that we found until now? - if ((cur < stmax) && (cur > timeBounds[1])) - timeBounds[1] = cur; - } - catch(itk::ExceptionObject e) - { - LOG_ERROR << e << std::endl; - } - } - - BoundingBox::Pointer result = BoundingBox::New(); - result->SetPoints(pointscontainer); - result->ComputeBoundingBox(); - - Geometry3D::Pointer geometry; - if (result->GetPoints()->Size() > 0) - { - geometry = Geometry3D::New(); - geometry->Initialize(); - // correct bounding-box (is now in mm, should be in index-coordinates) - // according to spacing - BoundingBox::BoundsArrayType bounds = result->GetBounds(); - for (unsigned int i = 0; i < 6; ++i) - bounds[i] /= minSpacing[i/2]; - - geometry->SetBounds(bounds); - geometry->SetSpacing(minSpacing); - // timebounds - if (timeBounds[0] >= stmax) - { - timeBounds[0] = stmin; - timeBounds[1] = stmax; - } - geometry->SetTimeBounds(timeBounds); - } - return geometry; -} - - -mitk::Geometry3D::Pointer mitk::DataStorage::ComputeBoundingGeometry3D( const char* boolPropertyKey, mitk::BaseRenderer* renderer, const char* boolPropertyKey2) -{ BoundingBox::PointsContainer::Pointer pointscontainer=BoundingBox::PointsContainer::New(); BoundingBox::PointIdentifier pointid=0; Point3D point; Vector3D minSpacing; minSpacing.Fill(ScalarTypeNumericTraits::max()); - TimeBounds timeBounds; - ScalarType stmin, stmax, cur; + ScalarType stmin, stmax; stmin= ScalarTypeNumericTraits::NonpositiveMin(); stmax= ScalarTypeNumericTraits::max(); - timeBounds[0]=stmax; timeBounds[1]=stmin; - SetOfObjects::ConstPointer all = this->GetAll(); - for (SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) + ScalarType minimalIntervallSize = stmax; + ScalarType minimalTime = stmax; + ScalarType maximalTime = 0; + + for (SetOfObjects::ConstIterator it = input->Begin(); it != input->End(); ++it) { DataTreeNode::Pointer node = it->Value(); if((node.IsNotNull()) && (node->GetData() != NULL) && (node->GetData()->IsEmpty()==false) && node->IsOn(boolPropertyKey, renderer) && node->IsOn(boolPropertyKey2, renderer) ) { - const Geometry3D* geometry = node->GetData()->GetUpdatedTimeSlicedGeometry(); + const TimeSlicedGeometry* geometry = node->GetData()->GetUpdatedTimeSlicedGeometry(); if (geometry != NULL ) { // bounding box unsigned char i; for(i=0; i<8; ++i) { point = geometry->GetCornerPoint(i); if(point[0]*point[0]+point[1]*point[1]+point[2]*point[2] < large) pointscontainer->InsertElement( pointid++, point); else { itkGenericOutputMacro( << "Unrealistically distant corner point encountered. Ignored. Node: " << node ); } } // spacing try { AffineTransform3D::Pointer inverseTransform = AffineTransform3D::New(); geometry->GetIndexToWorldTransform()->GetInverse(inverseTransform); vnl_vector< AffineTransform3D::MatrixType::ValueType > unitVector(3); int axis; for(axis = 0; axis < 3; ++axis) { unitVector.fill(0); unitVector[axis] = 1.0; ScalarType mmPerPixel = 1.0/(inverseTransform->GetMatrix()*unitVector).magnitude(); if(minSpacing[axis] > mmPerPixel) { minSpacing[axis] = mmPerPixel; } } // timebounds - const TimeBounds & curTimeBounds = geometry->GetTimeBounds(); - cur=curTimeBounds[0]; - //is it after -infinity, but before everything else that we found until now? - if((cur > stmin) && (cur < timeBounds[0])) - timeBounds[0] = cur; - - cur=curTimeBounds[1]; - //is it before infinity, but after everything else that we found until now? - if((cur < stmax) && (cur > timeBounds[1])) - timeBounds[1] = cur; + // iterate over all time steps + TimeBounds minTB = geometry->GetTimeBounds(); + for (unsigned int i=0; iGetTimeSteps(); i++) + { + const TimeBounds & curTimeBounds = node->GetData()->GetGeometry(i)->GetTimeBounds(); + // get the minimal time of all objects in the DataStorage + if ((curTimeBounds[0]stmin)) + { + minimalTime=curTimeBounds[0]; + } + // get the maximal time of all objects in the DataStorage + if ((curTimeBounds[1]>maximalTime)&&(curTimeBounds[1]SetPoints(pointscontainer); result->ComputeBoundingBox(); - Geometry3D::Pointer geometry; + // minimal time bounds of a single time step for all geometries + TimeBounds minTimeBounds; + minTimeBounds[0] = 0; + minTimeBounds[1] = 1; + // compute the number of time steps + unsigned int numberOfTimeSteps = 1; + if (maximalTime!=0) // make sure that there is at least one time sliced geometry in the data storage + { + minTimeBounds[0] = minimalTime; + minTimeBounds[1] = minimalTime + minimalIntervallSize; + numberOfTimeSteps = (maximalTime-minimalTime)/minimalIntervallSize; + } + + TimeSlicedGeometry::Pointer timeSlicedGeometry = NULL; if ( result->GetPoints()->Size()>0 ) { - geometry = Geometry3D::New(); + // Initialize a geometry of a single time step + Geometry3D::Pointer geometry = Geometry3D::New(); geometry->Initialize(); // correct bounding-box (is now in mm, should be in index-coordinates) // according to spacing BoundingBox::BoundsArrayType bounds = result->GetBounds(); int i; for(i = 0; i < 6; ++i) { bounds[i] /= minSpacing[i/2]; } geometry->SetBounds(bounds); geometry->SetSpacing(minSpacing); - // timebounds - if(!(timeBounds[0]SetTimeBounds(timeBounds); + geometry->SetTimeBounds(minTimeBounds); + // Initialize the time sliced geometry + timeSlicedGeometry = TimeSlicedGeometry::New(); + timeSlicedGeometry->InitializeEvenlyTimed(geometry,numberOfTimeSteps); } - return geometry; + return timeSlicedGeometry; +} + + +mitk::TimeSlicedGeometry::Pointer mitk::DataStorage::ComputeBoundingGeometry3D( const char* boolPropertyKey, mitk::BaseRenderer* renderer, const char* boolPropertyKey2) +{ + return this->ComputeBoundingGeometry3D(this->GetAll(), boolPropertyKey, renderer, boolPropertyKey2); } -mitk::Geometry3D::Pointer mitk::DataStorage::ComputeVisibleBoundingGeometry3D( mitk::BaseRenderer* renderer, const char* boolPropertyKey ) +mitk::TimeSlicedGeometry::Pointer mitk::DataStorage::ComputeVisibleBoundingGeometry3D( mitk::BaseRenderer* renderer, const char* boolPropertyKey ) { return ComputeBoundingGeometry3D( "visible", renderer, boolPropertyKey ); } mitk::BoundingBox::Pointer mitk::DataStorage::ComputeBoundingBox( const char* boolPropertyKey, mitk::BaseRenderer* renderer, const char* boolPropertyKey2) { BoundingBox::PointsContainer::Pointer pointscontainer=BoundingBox::PointsContainer::New(); BoundingBox::PointIdentifier pointid=0; Point3D point; SetOfObjects::ConstPointer all = this->GetAll(); for (SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) { DataTreeNode::Pointer node = it->Value(); if((node.IsNotNull()) && (node->GetData() != NULL) && (node->GetData()->IsEmpty()==false) && node->IsOn(boolPropertyKey, renderer) && node->IsOn(boolPropertyKey2, renderer) ) { const Geometry3D* geometry = node->GetData()->GetUpdatedTimeSlicedGeometry(); if (geometry != NULL ) { unsigned char i; for(i=0; i<8; ++i) { point = geometry->GetCornerPoint(i); if(point[0]*point[0]+point[1]*point[1]+point[2]*point[2] < large) pointscontainer->InsertElement( pointid++, point); else { itkGenericOutputMacro( << "Unrealistically distant corner point encountered. Ignored. Node: " << node ); } } } } } BoundingBox::Pointer result = BoundingBox::New(); result->SetPoints(pointscontainer); result->ComputeBoundingBox(); return result; } mitk::TimeBounds mitk::DataStorage::ComputeTimeBounds( const char* boolPropertyKey, mitk::BaseRenderer* renderer, const char* boolPropertyKey2) { TimeBounds timeBounds; ScalarType stmin, stmax, cur; stmin= ScalarTypeNumericTraits::NonpositiveMin(); stmax= ScalarTypeNumericTraits::max(); timeBounds[0]=stmax; timeBounds[1]=stmin; SetOfObjects::ConstPointer all = this->GetAll(); for (SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) { DataTreeNode::Pointer node = it->Value(); if((node.IsNotNull()) && (node->GetData() != NULL) && (node->GetData()->IsEmpty()==false) && node->IsOn(boolPropertyKey, renderer) && node->IsOn(boolPropertyKey2, renderer) ) { const Geometry3D* geometry = node->GetData()->GetUpdatedTimeSlicedGeometry(); if (geometry != NULL ) { const TimeBounds & curTimeBounds = geometry->GetTimeBounds(); cur=curTimeBounds[0]; //is it after -infinity, but before everything else that we found until now? if((cur > stmin) && (cur < timeBounds[0])) timeBounds[0] = cur; cur=curTimeBounds[1]; //is it before infinity, but after everything else that we found until now? if((cur < stmax) && (cur > timeBounds[1])) timeBounds[1] = cur; } } } if(!(timeBounds[0] < stmax)) { timeBounds[0] = stmin; timeBounds[1] = stmax; } return timeBounds; } diff --git a/Core/Code/DataManagement/mitkDataStorage.h b/Core/Code/DataManagement/mitkDataStorage.h index 98e3b0b8e8..c0c812ab0a 100644 --- a/Core/Code/DataManagement/mitkDataStorage.h +++ b/Core/Code/DataManagement/mitkDataStorage.h @@ -1,374 +1,379 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKDATASTORAGE_H_HEADER_INCLUDED_ #define MITKDATASTORAGE_H_HEADER_INCLUDED_ #include "itkObject.h" #include "mitkCommon.h" #include "mitkMessage.h" #include "itkVectorContainer.h" #include "mitkDataTreeNode.h" #include "mitkGeometry3D.h" #include namespace mitk { class NodePredicateBase; class DataTreeNode; class BaseRenderer; //##Documentation //## @brief Data management class that handles 'was created by' relations //## //## The DataStorage provides data storage and management functionality. //## It handles a 'was created by' relation by associating each data object with a //## set of source objects, that this object was created from. //## Thus, nodes are stored in a noncyclical directed graph data structure. //## If a new node is added to the DataStorage, AddNodeEvent is emitted. //## If a node is removed, RemoveNodeEvent is emitted. //## //## //## \ingroup DataStorage class MITK_CORE_EXPORT DataStorage : public itk::Object { public: mitkClassMacro(DataStorage, itk::Object); //##Documentation //## @brief A Container of objects that is used as a result set of GetSubset() query operations (Set of SmartPointers to DataTreeNodes). typedef itk::VectorContainer SetOfObjects; //##Documentation //## @brief Adds a DataTreeNode containing a data object to its internal storage //## //## This Method adds a new data object to the DataStorage. The new object is //## passed in the first parameter. The second parameter is a set //## of source objects, that were used to create this object. The new object will have //## a 'was created from' relation to its source objects. //## the addition of a new object will fire the notification mechanism. //## If the node parameter is NULL or if the DataTreeNode has already been added, //## an exception will be thrown. virtual void Add(mitk::DataTreeNode* node, const mitk::DataStorage::SetOfObjects* parents = NULL) = 0; //##Documentation //## @brief Convenience method to add a node that has one parent //## void Add(mitk::DataTreeNode* node, mitk::DataTreeNode* parent); //##Documentation //## @brief Removes node from the DataStorage //## virtual void Remove(const mitk::DataTreeNode* node) = 0; //##Documentation //## @brief Checks if a node exists in the DataStorage //## virtual bool Exists(const mitk::DataTreeNode* node) const = 0; //##Documentation //## @brief Removes a set of nodes from the DataStorage //## void Remove(const mitk::DataStorage::SetOfObjects* nodes); //##Documentation //## @brief returns a set of data objects that meet the given condition(s) //## //## GetSubset returns a set of objects with a specific data type that meet the condition(s) //## specified in the condition parameter. Conditions can be //## - data type of the data object //## - is source object of specific object (e.g. all source objects of node x) //## - has property with specific value (e.g. OrganType is Liver) //## - negation of any condition //## - conjunction of a set of conditions //## - disjunction of a set of conditions //## Conditions are implemented as predicates using the Composite Design Pattern //## (see definition of NodePredicateBase for details). //## The method returns a set of SmartPointers to the DataTreeNodes that fulfill the //## conditions. A set of all objects can be retrieved with the GetAll() method; SetOfObjects::ConstPointer GetSubset(const NodePredicateBase* condition) const; //##Documentation //## @brief returns a set of source objects for a given node that meet the given condition(s). //## virtual SetOfObjects::ConstPointer GetSources(const mitk::DataTreeNode* node, const NodePredicateBase* condition = NULL, bool onlyDirectSources = true) const = 0; //##Documentation //## @brief returns a set of derived objects for a given node. //## //## GetDerivations() returns a set of objects that are derived from the DataTreeNode node. //## This means, that node was used to create the returned objects. If the parameter //## onlyDirectDerivations is set to true (default value), only objects that directly have //## node as one of their source objects will be returned. Otherwise, objects that are //## derived from derivations of node are returned too. //## The derived objects can be filtered with a predicate object as described in the GetSubset() //## method by providing a predicate as the condition parameter. virtual SetOfObjects::ConstPointer GetDerivations(const mitk::DataTreeNode* node, const NodePredicateBase* condition = NULL, bool onlyDirectDerivations = true) const = 0; //##Documentation //## @brief returns a set of all data objects that are stored in the data storage //## virtual SetOfObjects::ConstPointer GetAll() const = 0; //##Documentation //## @brief Convenience method to get the first node that matches the predicate condition //## mitk::DataTreeNode* GetNode(const NodePredicateBase* condition = NULL) const; //##Documentation //## @brief Convenience method to get the first node with a given name //## mitk::DataTreeNode* GetNamedNode(const char* name) const; //##Documentation //## @brief Convenience method to get the first node with a given name //## mitk::DataTreeNode* GetNamedNode(const std::string name) const { return this->GetNamedNode(name.c_str()); } //##Documentation //## @brief Convenience method to get the first node with a given name that is derived from sourceNode //## mitk::DataTreeNode* GetNamedDerivedNode(const char* name, const mitk::DataTreeNode* sourceNode, bool onlyDirectDerivations = true) const; //##Documentation //## @brief Convenience method to get the first data object of a given data type with a given name //## template DataType* GetNamedObject(const char* name) const { if (name == NULL) return NULL; mitk::DataTreeNode* n = this->GetNamedNode(name); if (n == NULL) return NULL; else return dynamic_cast(n->GetData()); } //##Documentation //## @brief Convenience method to get the first data object of a given data type with a given name //## template DataType* GetNamedObject(const std::string name) const { return this->GetNamedObject(name.c_str()); } //##Documentation //## @brief Convenience method to get the first data object of a given data type with a given name that is derived from a specific node //## template DataType* GetNamedDerivedObject(const char* name, const mitk::DataTreeNode* sourceNode, bool onlyDirectDerivations = true) const { if (name == NULL) return NULL; mitk::DataTreeNode* n = this->GetNamedDerivedNode(name, sourceNode, onlyDirectDerivations); if (n == NULL) return NULL; else return dynamic_cast(n->GetData()); } //##Documentation //## @brief Returns a list of used grouptags //## const DataTreeNode::GroupTagList GetGroupTags() const; /* Public Events */ typedef Message1 DataStorageEvent; //##Documentation //## @brief AddEvent is emitted whenever a new node has been added to the DataStorage. //## //## Observers should register to this event by calling myDataStorage->AddNodeEvent.AddListener(myObject, MyObject::MyMethod). //## After registering, myObject->MyMethod() will be called every time a new node has been added to the DataStorage. //## Observers should unregister by calling myDataStorage->AddNodeEvent.RemoveListener(myObject, MyObject::MyMethod). //## Note: AddEvents are _not_ emitted if a node is added to DataStorage by adding it to the the underlying DataTree! DataStorageEvent AddNodeEvent; //##Documentation //## @brief RemoveEvent is emitted directly before a node is removed from the DataStorage. //## //## Observers should register to this event by calling myDataStorage->RemoveNodeEvent.AddListener(myObject, MyObject::MyMethod). //## After registering, myObject->MyMethod() will be called every time a new node has been added to the DataStorage. //## Observers should unregister by calling myDataStorage->RemoveNodeEvent.RemoveListener(myObject, MyObject::MyMethod). //## Note: RemoveEvents are also emitted if a node was removed from the DataStorage by deleting it from the underlying DataTree DataStorageEvent RemoveNodeEvent; //##Documentation //## @brief ChangedEvent is emitted directly after a node was changed. //## //## Observers should register to this event by calling myDataStorage->ChangedNodeEvent.AddListener(myObject, MyObject::MyMethod). //## After registering, myObject->MyMethod() will be called every time a new node has been changed. //## Observers should unregister by calling myDataStorage->ChangedNodeEvent.RemoveListener(myObject, MyObject::MyMethod). //## Internally the DataStorage listens to itk::ModifiedEvents on the nodes and forwards them //## to the listeners of this event. DataStorageEvent ChangedNodeEvent; //##Documentation //## @brief DeleteNodeEvent is emitted directly before a node is deleted. //## //## Observers should register to this event by calling myDataStorage->DeleteNodeEvent.AddListener(myObject, MyObject::MyMethod). //## After registering, myObject->MyMethod() will be called when a node is deleted. //## Observers should unregister by calling myDataStorage->DeleteNodeEvent.RemoveListener(myObject, MyObject::MyMethod). //## Internally the DataStorage listens to itk::DeleteEvents on the nodes and forwards them //## to the listeners of this event. DataStorageEvent DeleteNodeEvent; //##Documentation //## @brief Compute the axis-parallel bounding geometry of the input objects //## //## Throws std::invalid_argument exception if input is NULL - mitk::Geometry3D::Pointer ComputeBoundingGeometry3D( const SetOfObjects* input); + //## @param input set of objects of the DataStorage to be included in the bounding geometry + //## @param boolPropertyKey if a BoolProperty with this boolPropertyKey exists for a node (for @a renderer) + //## and is set to @a false, the node is ignored for the bounding-box calculation. + //## @param renderer see @a boolPropertyKey + //## @param boolPropertyKey2 a second condition that is applied additionally to @a boolPropertyKey + mitk::TimeSlicedGeometry::Pointer ComputeBoundingGeometry3D( const SetOfObjects* input, const char* boolPropertyKey = NULL, mitk::BaseRenderer* renderer = NULL, const char* boolPropertyKey2 = NULL); //##Documentation //## @brief Compute the axis-parallel bounding geometry of the data tree //## (bounding box, minimal spacing of the considered nodes, live-span) //## //## it -> an iterator to a data tree structure //## @param boolPropertyKey if a BoolProperty with this boolPropertyKey exists for a node (for @a renderer) //## and is set to @a false, the node is ignored for the bounding-box calculation. //## @param renderer see @a boolPropertyKey //## @param boolPropertyKey2 a second condition that is applied additionally to @a boolPropertyKey - mitk::Geometry3D::Pointer ComputeBoundingGeometry3D( const char* boolPropertyKey = NULL, mitk::BaseRenderer* renderer = NULL, const char* boolPropertyKey2 = NULL); + mitk::TimeSlicedGeometry::Pointer ComputeBoundingGeometry3D( const char* boolPropertyKey = NULL, mitk::BaseRenderer* renderer = NULL, const char* boolPropertyKey2 = NULL); //##Documentation //## @brief Compute the axis-parallel bounding geometry of all visible parts of the //## data tree bounding box, minimal spacing of the considered nodes, live-span) //## //## Simply calls ComputeBoundingGeometry3D(it, "visible", renderer, boolPropertyKey). //## it -> an iterator of a data tree structure //## @param renderer the reference to the renderer //## @param boolPropertyKey if a BoolProperty with this boolPropertyKey exists for a node (for @a renderer) //## and is set to @a false, the node is ignored for the bounding-box calculation. - mitk::Geometry3D::Pointer ComputeVisibleBoundingGeometry3D( mitk::BaseRenderer* renderer = NULL, const char* boolPropertyKey = NULL); + mitk::TimeSlicedGeometry::Pointer ComputeVisibleBoundingGeometry3D( mitk::BaseRenderer* renderer = NULL, const char* boolPropertyKey = NULL); //##Documentation //## @brief Compute the bounding box of data tree structure //## it -> an iterator to a data tree structure //## @param boolPropertyKey if a BoolProperty with this boolPropertyKey exists for a node (for @a renderer) //## and is set to @a false, the node is ignored for the bounding-box calculation. //## @param renderer see @a boolPropertyKey //## @param boolPropertyKey2 a second condition that is applied additionally to @a boolPropertyKey mitk::BoundingBox::Pointer ComputeBoundingBox( const char* boolPropertyKey = NULL, mitk::BaseRenderer* renderer = NULL, const char* boolPropertyKey2 = NULL); //##Documentation //## \brief Compute the bounding box of all visible parts of the data tree structure, for general //## rendering or renderer specific visibility property checking //## //## Simply calls ComputeBoundingBox(it, "visible", renderer, boolPropertyKey). //## it -> an iterator of a data tree structure //## @param renderer the reference to the renderer //## @param boolPropertyKey if a BoolProperty with this boolPropertyKey exists for a node (for @a renderer) //## and is set to @a false, the node is ignored for the bounding-box calculation. mitk::BoundingBox::Pointer ComputeVisibleBoundingBox( mitk::BaseRenderer* renderer = NULL, const char* boolPropertyKey = NULL) { return ComputeBoundingBox( "visible", renderer, boolPropertyKey); } //##Documentation //## @brief Compute the time-bounds of the contents of a data tree structure //## //## The methods returns only [-infinity, +infinity], if all data-objects have an infinite live-span. Otherwise, //## all data-objects with infinite live-span are ignored. //## it -> an iterator to a data tree structure //## @param boolPropertyKey if a BoolProperty with this boolPropertyKey exists for a node (for @a renderer) //## and is set to @a false, the node is ignored for the time-bounds calculation. //## @param renderer see @a boolPropertyKey //## @param boolPropertyKey2 a second condition that is applied additionally to @a boolPropertyKey mitk::TimeBounds ComputeTimeBounds( const char* boolPropertyKey, mitk::BaseRenderer* renderer, const char* boolPropertyKey2); //##Documentation //## @brief Compute the time-bounds of all visible parts of the data tree structure, for general //## rendering or renderer specific visibility property checking //## //## The methods returns only [-infinity, +infinity], if all data-objects have an infinite live-span. Otherwise, //## all data-objects with infinite live-span are ignored. //## Simply calls ComputeTimeBounds(it, "visible", renderer, boolPropertyKey). //## @param it an iterator to a data tree structure //## @param boolPropertyKey if a BoolProperty with this boolPropertyKey exists for a node (for @a renderer) //## and is set to @a false, the node is ignored for the time-bounds calculation. //## @param renderer see @a boolPropertyKey mitk::TimeBounds ComputeTimeBounds( mitk::BaseRenderer* renderer, const char* boolPropertyKey) { return ComputeTimeBounds( "visible", renderer, boolPropertyKey); } protected: //##Documentation //## @brief EmitAddNodeEvent emits the AddNodeEvent //## //## This method should be called by subclasses to emit the AddNodeEvent void EmitAddNodeEvent(const mitk::DataTreeNode* node); //##Documentation //## @brief EmitRemoveNodeEvent emits the RemoveNodeEvent //## //## This method should be called by subclasses to emit the RemoveNodeEvent void EmitRemoveNodeEvent(const mitk::DataTreeNode* node); //##Documentation //## @brief OnNodeModified listens to modified events of DataTreeNodes. //## //## The node is hidden behind the caller parameter, which has to be casted first. //## If the cast succeeds the ChangedNodeEvent is emitted with this node. void OnNodeModifiedOrDeleted( const itk::Object *caller, const itk::EventObject &event ); //##Documentation //## @brief Adds a Modified-Listener to the given Node. void AddListeners(const mitk::DataTreeNode* _Node); //##Documentation //## @brief Removes a Modified-Listener from the given Node. void RemoveListeners(const mitk::DataTreeNode* _Node); //##Documentation //## @brief Saves Modified-Observer Tags for each node in order to remove the event listeners again. std::map m_NodeModifiedObserverTags; //##Documentation //## @brief Saves Delete-Observer Tags for each node in order to remove the event listeners again. std::map m_NodeDeleteObserverTags; //##Documentation //## @brief If this class changes nodes itself, set this to TRUE in order //## to suppress NodeChangedEvent to be emitted. bool m_BlockNodeModifiedEvents; //##Documentation //## @brief Standard Constructor for ::New() instantiation DataStorage(); //##Documentation //## @brief Standard Destructor virtual ~DataStorage(); //##Documentation //## @brief Filters a SetOfObjects by the condition. If no condition is provided, the original set is returned SetOfObjects::ConstPointer FilterSetOfObjects(const SetOfObjects* set, const NodePredicateBase* condition) const; //##Documentation //## @brief Prints the contents of the DataStorage to os. Do not call directly, call ->Print() instead virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; }; } // namespace mitk #endif /* MITKDATASTORAGE_H_HEADER_INCLUDED_ */ diff --git a/Core/Code/Testing/mitkDataStorageTest.cpp b/Core/Code/Testing/mitkDataStorageTest.cpp index 4b2b98e840..b99e840511 100644 --- a/Core/Code/Testing/mitkDataStorageTest.cpp +++ b/Core/Code/Testing/mitkDataStorageTest.cpp @@ -1,705 +1,728 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include #include #include "mitkImage.h" #include "mitkSurface.h" #include "mitkStringProperty.h" #include "mitkColorProperty.h" #include "mitkGroupTagProperty.h" #include "mitkDataTreeNode.h" #include "mitkReferenceCountWatcher.h" #include "mitkDataStorage.h" #include "mitkStandaloneDataStorage.h" #include "mitkNodePredicateProperty.h" #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateDimension.h" #include "mitkNodePredicateData.h" #include "mitkNodePredicateNOT.h" #include "mitkNodePredicateAND.h" #include "mitkNodePredicateOR.h" #include "mitkNodePredicateSource.h" #include "mitkMessage.h" #include "mitkTestingMacros.h" void TestDataStorage(mitk::DataStorage* ds); class DSEventReceiver // Helper class for event testing { public: const mitk::DataTreeNode* m_NodeAdded; const mitk::DataTreeNode* m_NodeRemoved; DSEventReceiver() : m_NodeAdded(NULL), m_NodeRemoved(NULL) { } void OnAdd(const mitk::DataTreeNode* node) { m_NodeAdded = node; } void OnRemove(const mitk::DataTreeNode* node) { m_NodeRemoved = node; } }; //## Documentation //## main testing method //## NOTE: the current Singleton implementation of DataTreeStorage will lead to crashes if a testcase fails //## and therefore mitk::DataStorage::ShutdownSingleton() is not called. int mitkDataStorageTest(int /*argc*/, char* /*argv*/[]) { MITK_TEST_BEGIN("DataStorageTest"); /* Create StandaloneDataStorage */ MITK_TEST_OUTPUT( << "Create StandaloneDataStorage : "); mitk::StandaloneDataStorage::Pointer sds; try { sds = mitk::StandaloneDataStorage::New(); MITK_TEST_CONDITION_REQUIRED(sds.IsNotNull(), "Testing Instatiation"); } catch (...) { MITK_TEST_FAILED_MSG( << "Exception during creation of StandaloneDataStorage"); } MITK_TEST_OUTPUT( << "Testing StandaloneDataStorage: "); TestDataStorage(sds); // TODO: Add specific StandaloneDataStorage Tests here sds = NULL; MITK_TEST_END(); } //##Documentation //## @brief Test for the DataStorage class and its associated classes (e.g. the predicate classes) //## This method will be called once for each subclass of DataStorage void TestDataStorage( mitk::DataStorage* ds ) { /* DataStorage valid? */ MITK_TEST_CONDITION_REQUIRED(ds != NULL, "DataStorage valid?"); // create some DataTreeNodes to fill the ds mitk::DataTreeNode::Pointer n1 = mitk::DataTreeNode::New(); // node with image and name property mitk::Image::Pointer image = mitk::Image::New(); - unsigned int imageDimensions[] = { 10, 10, 10 }; + unsigned int imageDimensions[] = { 10, 10, 10, 10}; mitk::PixelType pt(typeid(int)); - image->Initialize( pt, 3, imageDimensions ); + image->Initialize( pt, 4, imageDimensions ); n1->SetData(image); n1->SetProperty("name", mitk::StringProperty::New("Node 1 - Image Node")); mitk::DataStorage::SetOfObjects::Pointer parents1 = mitk::DataStorage::SetOfObjects::New(); mitk::DataTreeNode::Pointer n2 = mitk::DataTreeNode::New(); // node with surface and name and color properties mitk::Surface::Pointer surface = mitk::Surface::New(); n2->SetData(surface); n2->SetProperty("name", mitk::StringProperty::New("Node 2 - Surface Node")); mitk::Color color; color.Set(1.0f, 1.0f, 0.0f); n2->SetColor(color); n2->SetProperty("Resection Proposal 1", mitk::GroupTagProperty::New()); mitk::DataStorage::SetOfObjects::Pointer parents2 = mitk::DataStorage::SetOfObjects::New(); parents2->InsertElement(0, n1); // n1 (image node) is source of n2 (surface node) mitk::DataTreeNode::Pointer n3 = mitk::DataTreeNode::New(); // node without data but with name property n3->SetProperty("name", mitk::StringProperty::New("Node 3 - Empty Node")); n3->SetProperty("Resection Proposal 1", mitk::GroupTagProperty::New()); n3->SetProperty("Resection Proposal 2", mitk::GroupTagProperty::New()); mitk::DataStorage::SetOfObjects::Pointer parents3 = mitk::DataStorage::SetOfObjects::New(); parents3->InsertElement(0, n2); // n2 is source of n3 mitk::DataTreeNode::Pointer n4 = mitk::DataTreeNode::New(); // node without data but with color property n4->SetColor(color); n4->SetProperty("Resection Proposal 2", mitk::GroupTagProperty::New()); mitk::DataStorage::SetOfObjects::Pointer parents4 = mitk::DataStorage::SetOfObjects::New(); parents4->InsertElement(0, n2); parents4->InsertElement(1, n3); // n2 and n3 are sources of n4 mitk::DataTreeNode::Pointer n5 = mitk::DataTreeNode::New(); // extra node n5->SetProperty("name", mitk::StringProperty::New("Node 5")); try /* adding objects */ { /* Add an object */ ds->Add(n1, parents1); MITK_TEST_CONDITION_REQUIRED((ds->GetAll()->Size() == 1) && (ds->GetAll()->GetElement(0) == n1), "Testing Adding a new object"); /* Check exception on adding the same object again */ MITK_TEST_OUTPUT( << "Check exception on adding the same object again: "); MITK_TEST_FOR_EXCEPTION(..., ds->Add(n1, parents1)); MITK_TEST_CONDITION(ds->GetAll()->Size() == 1, "Test if object count is correct after exception"); /* Add an object that has a source object */ ds->Add(n2, parents2); MITK_TEST_CONDITION_REQUIRED(ds->GetAll()->Size() == 2, "Testing Adding an object that has a source object"); /* Add some more objects needed for further tests */ ds->Add(n3, parents3); // n3 object that has name property and one parent ds->Add(n4, parents4); // n4 object that has color property ds->Add(n5); // n5 has no parents MITK_TEST_CONDITION_REQUIRED(ds->GetAll()->Size() == 5, "Adding some more objects needed for further tests"); } catch(...) { MITK_TEST_FAILED_MSG( << "Exeption during object creation"); } try /* object retrieval methods */ { /* Requesting all Objects */ { const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetAll(); std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION( (stlAll.size() == 5) // check if all tree nodes are in resultset && (std::find(stlAll.begin(), stlAll.end(), n1) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n3) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n4) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n5) != stlAll.end()), "Testing GetAll()" ); } /* Requesting a named object */ { mitk::NodePredicateProperty::Pointer predicate(mitk::NodePredicateProperty::New("name", mitk::StringProperty::New("Node 2 - Surface Node"))); mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(predicate); MITK_TEST_CONDITION((all->Size() == 1) && (all->GetElement(0) == n2), "Requesting a named object"); } /* Requesting objects of specific data type */ { mitk::NodePredicateDataType::Pointer predicate(mitk::NodePredicateDataType::New("Image")); mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(predicate); MITK_TEST_CONDITION((all->Size() == 1) && (all->GetElement(0) == n1), "Requesting objects of specific data type") } /* Requesting objects of specific dimension */ { mitk::NodePredicateDimension::Pointer predicate(mitk::NodePredicateDimension::New( 3 )); mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(predicate); MITK_TEST_CONDITION((all->Size() == 1) && (all->GetElement(0) == n1), "Requesting objects of specific dimension") } /* Requesting objects with specific data object */ { mitk::NodePredicateData::Pointer predicate(mitk::NodePredicateData::New(image)); mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(predicate); MITK_TEST_CONDITION((all->Size() == 1) && (all->GetElement(0) == n1), "Requesting objects with specific data object") } /* Requesting objects with NULL data */ { mitk::NodePredicateData::Pointer predicate(mitk::NodePredicateData::New(NULL)); mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(predicate); MITK_TEST_CONDITION( (all->Size() == 3) && (std::find(all->begin(), all->end(), n3) != all->end()) && (std::find(all->begin(), all->end(), n4) != all->end()) && (std::find(all->begin(), all->end(), n5) != all->end()) , "Requesting objects with NULL data"); } /* Requesting objects that meet a conjunction criteria */ { mitk::NodePredicateDataType::Pointer p1 = mitk::NodePredicateDataType::New("Surface"); mitk::NodePredicateProperty::Pointer p2 = mitk::NodePredicateProperty::New("color", mitk::ColorProperty::New(color)); mitk::NodePredicateAND::Pointer predicate = mitk::NodePredicateAND::New(); predicate->AddPredicate(p1); predicate->AddPredicate(p2); // objects must be of datatype "Surface" and have red color (= n2) const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(predicate); MITK_TEST_CONDITION((all->Size() == 1) && (all->GetElement(0) == n2), "Requesting objects that meet a conjunction criteria"); } /* Requesting objects that meet a disjunction criteria */ { mitk::NodePredicateDataType::Pointer p1(mitk::NodePredicateDataType::New("Image")); mitk::NodePredicateProperty::Pointer p2(mitk::NodePredicateProperty::New("color", mitk::ColorProperty::New(color))); mitk::NodePredicateOR::Pointer predicate = mitk::NodePredicateOR::New(); predicate->AddPredicate(p1); predicate->AddPredicate(p2); // objects must be of datatype "Surface" or have red color (= n1, n2, n4) const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(predicate); MITK_TEST_CONDITION( (all->Size() == 3) && (std::find(all->begin(), all->end(), n1) != all->end()) && (std::find(all->begin(), all->end(), n2) != all->end()) && (std::find(all->begin(), all->end(), n4) != all->end()), "Requesting objects that meet a disjunction criteria"); } /* Requesting objects that do not meet a criteria */ { mitk::ColorProperty::Pointer cp = mitk::ColorProperty::New(color); mitk::NodePredicateProperty::Pointer proppred(mitk::NodePredicateProperty::New("color", cp)); mitk::NodePredicateNOT::Pointer predicate(mitk::NodePredicateNOT::New(proppred)); const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(predicate); std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION( (all->Size() == 3) // check if correct objects are in resultset && (std::find(stlAll.begin(), stlAll.end(), n1) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n3) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n5) != stlAll.end()), "Requesting objects that do not meet a criteria"); } /* Requesting *direct* source objects */ { const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSources(n3, NULL, true); // Get direct parents of n3 (=n2) std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION( (all->Size() == 1) && (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()), "Requesting *direct* source objects"); } /* Requesting *all* source objects */ { const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSources(n3, NULL, false); // Get all parents of n3 (= n1 + n2) std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION( (all->Size() == 2) && (std::find(stlAll.begin(), stlAll.end(), n1) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()), "Requesting *all* source objects"); // check if n1 and n2 are the resultset } /* Requesting *all* sources of object with multiple parents */ { const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSources(n4, NULL, false); // Get all parents of n4 (= n1 + n2 + n3) std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION( (all->Size() == 3) && (std::find(stlAll.begin(), stlAll.end(), n1) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n3) != stlAll.end()) // check if n1 and n2 and n3 are the resultset , "Requesting *all* sources of object with multiple parents"); } /* Requesting *direct* derived objects */ { const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetDerivations(n1, NULL, true); // Get direct childs of n1 (=n2) std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION( (all->Size() == 1) && (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end())// check if n1 is the resultset , "Requesting *direct* derived objects"); } ///* Requesting *direct* derived objects with multiple parents/derivations */ { const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetDerivations(n2, NULL, true); // Get direct childs of n2 (=n3 + n4) std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION( (all->Size() == 2) && (std::find(stlAll.begin(), stlAll.end(), n3) != stlAll.end()) // check if n3 is the resultset && (std::find(stlAll.begin(), stlAll.end(), n4) != stlAll.end()) // check if n4 is the resultset , "Requesting *direct* derived objects with multiple parents/derivations"); } //* Requesting *all* derived objects */ { const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetDerivations(n1, NULL, false); // Get all childs of n1 (=n2, n3, n4) std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION( (all->Size() == 3) && (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n3) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n4) != stlAll.end()) , "Requesting *all* derived objects"); } /* Checking for circular source relationships */ { parents1->InsertElement(0, n4); // make n1 derived from n4 (which is derived from n2, which is derived from n1) const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSources(n4, NULL, false); // Get all parents of n4 (= n1 + n2 + n3, not n4 itself and not multiple versions of the nodes!) std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION( (all->Size() == 3) && (std::find(stlAll.begin(), stlAll.end(), n1) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n3) != stlAll.end()) // check if n1 and n2 and n3 are the resultset , "Checking for circular source relationships"); } ///* Checking for circular derivation relationships can not be performed, because the internal derivations datastructure // can not be accessed from the outside. (Therefore it should not be possible to create these circular relations */ //* Checking GroupTagProperty */ { mitk::GroupTagProperty::Pointer tp = mitk::GroupTagProperty::New(); mitk::NodePredicateProperty::Pointer pred(mitk::NodePredicateProperty::New("Resection Proposal 1", tp)); const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(pred); std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION( (all->Size() == 2) // check if n2 and n3 are in resultset && (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n3) != stlAll.end()) , "Checking GroupTagProperty"); } /* Checking GroupTagProperty 2 */ { mitk::GroupTagProperty::Pointer tp = mitk::GroupTagProperty::New(); mitk::NodePredicateProperty::Pointer pred(mitk::NodePredicateProperty::New("Resection Proposal 2", tp)); const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSubset(pred); std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION( (all->Size() == 2) // check if n3 and n4 are in resultset && (std::find(stlAll.begin(), stlAll.end(), n3) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n4) != stlAll.end()) , "Checking GroupTagProperty 2"); } /* Checking direct sources with condition */ { mitk::NodePredicateDataType::Pointer pred = mitk::NodePredicateDataType::New("Surface"); const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSources(n4, pred, true); std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION( (all->Size() == 1) // check if n2 is in resultset && (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()) , "checking direct sources with condition"); } /* Checking all sources with condition */ { mitk::NodePredicateDataType::Pointer pred = mitk::NodePredicateDataType::New("Image"); const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSources(n4, pred, false); std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION( (all->Size() == 1) // check if n1 is in resultset && (std::find(stlAll.begin(), stlAll.end(), n1) != stlAll.end()) , "Checking all sources with condition"); } /* Checking all sources with condition with empty resultset */ { mitk::NodePredicateDataType::Pointer pred = mitk::NodePredicateDataType::New("VesselTree"); const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetSources(n4, pred, false); MITK_TEST_CONDITION(all->Size() == 0 , "Checking all sources with condition with empty resultset"); // check if resultset is empty } /* Checking direct derivations with condition */ { mitk::NodePredicateProperty::Pointer pred = mitk::NodePredicateProperty::New("color"); const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetDerivations(n1, pred, true); std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION( (all->Size() == 1) // check if n2 is in resultset && (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()) , "Checking direct derivations with condition"); } /* Checking all derivations with condition */ { mitk::NodePredicateProperty::Pointer pred = mitk::NodePredicateProperty::New("color"); const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetDerivations(n1, pred, false); std::vector stlAll = all->CastToSTLConstContainer(); MITK_TEST_CONDITION( (all->Size() == 2) // check if n2 and n4 are in resultset && (std::find(stlAll.begin(), stlAll.end(), n2) != stlAll.end()) && (std::find(stlAll.begin(), stlAll.end(), n4) != stlAll.end()) , "Checking direct derivations with condition"); } /* Checking named node method */ MITK_TEST_CONDITION(ds->GetNamedNode("Node 2 - Surface Node") == n2, "Checking named node method"); MITK_TEST_CONDITION(ds->GetNamedNode(std::string("Node 2 - Surface Node")) == n2, "Checking named node(std::string) method"); /* Checking named node method with wrong name */ MITK_TEST_CONDITION(ds->GetNamedNode("This name does not exist") == NULL, "Checking named node method with wrong name"); /* Checking named object method */ MITK_TEST_CONDITION(ds->GetNamedObject("Node 1 - Image Node") == image, "Checking named object method"); MITK_TEST_CONDITION(ds->GetNamedObject(std::string("Node 1 - Image Node")) == image, "Checking named object(std::string) method"); /* Checking named object method with wrong DataType */ MITK_TEST_CONDITION(ds->GetNamedObject("Node 1 - Image Node") == NULL, "Checking named object method with wrong DataType"); /* Checking named object method with wrong name */ MITK_TEST_CONDITION(ds->GetNamedObject("This name does not exist") == NULL, "Checking named object method with wrong name"); /* Checking GetNamedDerivedNode with valid name and direct derivation only */ MITK_TEST_CONDITION(ds->GetNamedDerivedNode("Node 2 - Surface Node", n1, true) == n2, "Checking GetNamedDerivedNode with valid name & direct derivation only"); /* Checking GetNamedDerivedNode with invalid Name and direct derivation only */ MITK_TEST_CONDITION(ds->GetNamedDerivedNode("wrong name", n1, true) == NULL, "Checking GetNamedDerivedNode with invalid name & direct derivation only"); /* Checking GetNamedDerivedNode with invalid Name and direct derivation only */ MITK_TEST_CONDITION(ds->GetNamedDerivedNode("Node 3 - Empty Node", n1, false) == n3, "Checking GetNamedDerivedNode with invalid name & direct derivation only"); /* Checking GetNamedDerivedNode with valid Name but direct derivation only */ MITK_TEST_CONDITION(ds->GetNamedDerivedNode("Node 3 - Empty Node", n1, true) == NULL, "Checking GetNamedDerivedNode with valid Name but direct derivation only"); /* Checking GetNode with valid predicate */ { mitk::NodePredicateDataType::Pointer p(mitk::NodePredicateDataType::New("Image")); MITK_TEST_CONDITION(ds->GetNode(p) == n1, "Checking GetNode with valid predicate"); } /* Checking GetNode with invalid predicate */ { mitk::NodePredicateDataType::Pointer p(mitk::NodePredicateDataType::New("PointSet")); MITK_TEST_CONDITION(ds->GetNode(p) == NULL, "Checking GetNode with invalid predicate"); } } // object retrieval methods catch(...) { MITK_TEST_FAILED_MSG( << "Exeption during object retrieval (GetXXX() Methods)"); } try /* object removal methods */ { /* Checking removal of a node without relations */ { mitk::DataTreeNode::Pointer extra = mitk::DataTreeNode::New(); extra->SetProperty("name", mitk::StringProperty::New("extra")); mitk::ReferenceCountWatcher::Pointer watcher = new mitk::ReferenceCountWatcher(extra); int refCountbeforeDS = watcher->GetReferenceCount(); ds->Add(extra); MITK_TEST_CONDITION(ds->GetNamedNode("extra") == extra, "Adding extra node"); ds->Remove(extra); MITK_TEST_CONDITION( (ds->GetNamedNode("extra") == NULL) && (refCountbeforeDS == watcher->GetReferenceCount()) , "Checking removal of a node without relations"); extra = NULL; } /* Checking removal of a node with a parent */ { mitk::DataTreeNode::Pointer extra = mitk::DataTreeNode::New(); extra->SetProperty("name", mitk::StringProperty::New("extra")); mitk::ReferenceCountWatcher::Pointer watcher = new mitk::ReferenceCountWatcher(extra); int refCountbeforeDS = watcher->GetReferenceCount(); ds->Add(extra, n1); // n1 is parent of extra MITK_TEST_CONDITION( (ds->GetNamedNode("extra") == extra) && (ds->GetDerivations(n1)->Size() == 2) // n2 and extra should be derived from n1 , "Adding extra node"); ds->Remove(extra); MITK_TEST_CONDITION( (ds->GetNamedNode("extra") == NULL) && (refCountbeforeDS == watcher->GetReferenceCount()) && (ds->GetDerivations(n1)->Size() == 1) , "Checking removal of a node with a parent"); extra = NULL; } /* Checking removal of a node with two parents */ { mitk::DataTreeNode::Pointer extra = mitk::DataTreeNode::New(); extra->SetProperty("name", mitk::StringProperty::New("extra")); mitk::ReferenceCountWatcher::Pointer watcher = new mitk::ReferenceCountWatcher(extra); int refCountbeforeDS = watcher->GetReferenceCount(); mitk::DataStorage::SetOfObjects::Pointer p = mitk::DataStorage::SetOfObjects::New(); p->push_back(n1); p->push_back(n2); ds->Add(extra, p); // n1 and n2 are parents of extra MITK_TEST_CONDITION( (ds->GetNamedNode("extra") == extra) && (ds->GetDerivations(n1)->Size() == 2) // n2 and extra should be derived from n1 && (ds->GetDerivations(n2)->Size() == 3) , "add extra node"); ds->Remove(extra); MITK_TEST_CONDITION( (ds->GetNamedNode("extra") == NULL) && (refCountbeforeDS == watcher->GetReferenceCount()) && (ds->GetDerivations(n1)->Size() == 1) // after remove, only n2 should be derived from n1 && (ds->GetDerivations(n2)->Size() == 2) // after remove, only n3 and n4 should be derived from n2 , "Checking removal of a node with two parents"); extra = NULL; } /* Checking removal of a node with two derived nodes */ { mitk::DataTreeNode::Pointer extra = mitk::DataTreeNode::New(); extra->SetProperty("name", mitk::StringProperty::New("extra")); mitk::ReferenceCountWatcher::Pointer watcher = new mitk::ReferenceCountWatcher(extra); int refCountbeforeDS = watcher->GetReferenceCount(); ds->Add(extra); mitk::DataTreeNode::Pointer d1 = mitk::DataTreeNode::New(); d1->SetProperty("name", mitk::StringProperty::New("d1")); ds->Add(d1, extra); mitk::DataTreeNode::Pointer d2 = mitk::DataTreeNode::New(); d2->SetProperty("name", mitk::StringProperty::New("d2")); ds->Add(d2, extra); MITK_TEST_CONDITION( (ds->GetNamedNode("extra") == extra) && (ds->GetNamedNode("d1") == d1) && (ds->GetNamedNode("d2") == d2) && (ds->GetSources(d1)->Size() == 1) // extra should be source of d1 && (ds->GetSources(d2)->Size() == 1) // extra should be source of d2 && (ds->GetDerivations(extra)->Size() == 2) // d1 and d2 should be derived from extra , "add extra node"); ds->Remove(extra); MITK_TEST_CONDITION( (ds->GetNamedNode("extra") == NULL) && (ds->GetNamedNode("d1") == d1) && (ds->GetNamedNode("d2") == d2) && (refCountbeforeDS == watcher->GetReferenceCount()) && (ds->GetSources(d1)->Size() == 0) // after remove, d1 should not have a source anymore && (ds->GetSources(d2)->Size() == 0) // after remove, d2 should not have a source anymore , "Checking removal of a node with two derived nodes"); extra = NULL; } /* Checking removal of a node with two parents and two derived nodes */ { mitk::DataTreeNode::Pointer extra = mitk::DataTreeNode::New(); extra->SetProperty("name", mitk::StringProperty::New("extra")); mitk::ReferenceCountWatcher::Pointer watcher = new mitk::ReferenceCountWatcher(extra); mitk::ReferenceCountWatcher::Pointer n1watcher = new mitk::ReferenceCountWatcher(n1); int refCountbeforeDS = watcher->GetReferenceCount(); mitk::DataStorage::SetOfObjects::Pointer p = mitk::DataStorage::SetOfObjects::New(); p->push_back(n1); p->push_back(n2); ds->Add(extra, p); // n1 and n2 are parents of extra mitk::DataTreeNode::Pointer d1 = mitk::DataTreeNode::New(); d1->SetProperty("name", mitk::StringProperty::New("d1x")); ds->Add(d1, extra); mitk::DataTreeNode::Pointer d2 = mitk::DataTreeNode::New(); d2->SetProperty("name", mitk::StringProperty::New("d2x")); ds->Add(d2, extra); MITK_TEST_CONDITION( (ds->GetNamedNode("extra") == extra) && (ds->GetNamedNode("d1x") == d1) && (ds->GetNamedNode("d2x") == d2) && (ds->GetSources(d1)->Size() == 1) // extra should be source of d1 && (ds->GetSources(d2)->Size() == 1) // extra should be source of d2 && (ds->GetDerivations(n1)->Size() == 2) // n2 and extra should be derived from n1 && (ds->GetDerivations(n2)->Size() == 3) // n3, n4 and extra should be derived from n2 && (ds->GetDerivations(extra)->Size() == 2) // d1 and d2 should be derived from extra , "add extra node"); ds->Remove(extra); MITK_TEST_CONDITION( (ds->GetNamedNode("extra") == NULL) && (ds->GetNamedNode("d1x") == d1) && (ds->GetNamedNode("d2x") == d2) && (refCountbeforeDS == watcher->GetReferenceCount()) && (ds->GetDerivations(n1)->Size() == 1) // after remove, only n2 should be derived from n1 && (ds->GetDerivations(n2)->Size() == 2) // after remove, only n3 and n4 should be derived from n2 && (ds->GetSources(d1)->Size() == 0) // after remove, d1 should not have a source anymore && (ds->GetSources(d2)->Size() == 0) // after remove, d2 should not have a source anymore , "Checking removal of a node with two parents and two derived nodes"); extra = NULL; } } catch(...) { MITK_TEST_FAILED_MSG( << "Exeption during object removal methods"); } /* Checking for node is it's own parent exception */ { MITK_TEST_FOR_EXCEPTION_BEGIN(...); mitk::DataTreeNode::Pointer extra = mitk::DataTreeNode::New(); extra->SetProperty("name", mitk::StringProperty::New("extra")); mitk::DataStorage::SetOfObjects::Pointer p = mitk::DataStorage::SetOfObjects::New(); p->push_back(n1); p->push_back(extra); // extra is parent of extra!!! ds->Add(extra, p); MITK_TEST_FOR_EXCEPTION_END(...); } /* Checking reference count of node after add and remove */ { mitk::DataTreeNode::Pointer extra = mitk::DataTreeNode::New(); mitk::ReferenceCountWatcher::Pointer watcher = new mitk::ReferenceCountWatcher(extra); extra->SetProperty("name", mitk::StringProperty::New("extra")); mitk::DataStorage::SetOfObjects::Pointer p = mitk::DataStorage::SetOfObjects::New(); p->push_back(n1); p->push_back(n3); ds->Add(extra, p); extra = NULL; ds->Remove(ds->GetNamedNode("extra")); MITK_TEST_CONDITION(watcher->GetReferenceCount() == 0, "Checking reference count of node after add and remove"); } /* Checking GetGrouptags() */ { const std::set groupTags = ds->GetGroupTags(); MITK_TEST_CONDITION( (groupTags.size() == 2) && (std::find(groupTags.begin(), groupTags.end(), "Resection Proposal 1") != groupTags.end()) && (std::find(groupTags.begin(), groupTags.end(), "Resection Proposal 2") != groupTags.end()) , "Checking GetGrouptags()"); } /* Checking Event handling */ DSEventReceiver listener; try { ds->AddNodeEvent += mitk::MessageDelegate1(&listener, &DSEventReceiver::OnAdd); ds->RemoveNodeEvent += mitk::MessageDelegate1(&listener, &DSEventReceiver::OnRemove); mitk::DataTreeNode::Pointer extra = mitk::DataTreeNode::New(); mitk::ReferenceCountWatcher::Pointer watcher = new mitk::ReferenceCountWatcher(extra); ds->Add(extra); MITK_TEST_CONDITION(listener.m_NodeAdded == extra.GetPointer(), "Checking AddEvent"); ds->Remove(extra); MITK_TEST_CONDITION(listener.m_NodeRemoved == extra.GetPointer(), "Checking RemoveEvent"); /* RemoveListener */ ds->AddNodeEvent -= mitk::MessageDelegate1(&listener, &DSEventReceiver::OnAdd); ds->RemoveNodeEvent -= mitk::MessageDelegate1(&listener, &DSEventReceiver::OnRemove); listener.m_NodeAdded = NULL; listener.m_NodeRemoved = NULL; ds->Add(extra); ds->Remove(extra); MITK_TEST_CONDITION((listener.m_NodeRemoved == NULL) && (listener.m_NodeAdded == NULL), "Checking RemoveListener"); std::cout << "Pointer handling after event handling: " << std::flush; extra = NULL; // delete reference to the node. its memory should be freed now MITK_TEST_CONDITION(watcher->GetReferenceCount() == 0, "Pointer handling after event handling"); } catch(...) { /* cleanup */ ds->AddNodeEvent -= mitk::MessageDelegate1(&listener, &DSEventReceiver::OnAdd); ds->RemoveNodeEvent -= mitk::MessageDelegate1(&listener, &DSEventReceiver::OnRemove); MITK_TEST_FAILED_MSG( << "Exception during object removal methods"); } + /*Checking ComputeBoundingGeometry3D method*/ + const mitk::DataStorage::SetOfObjects::ConstPointer all = ds->GetAll(); + mitk::TimeSlicedGeometry::Pointer geometry = ds->ComputeBoundingGeometry3D(); + MITK_TEST_CONDITION(geometry->GetTimeSteps()==10, "Test for number or time steps with ComputeBoundingGeometry()"); + mitk::TimeBounds timebounds = geometry->GetTimeBounds(); + MITK_TEST_CONDITION((timebounds[0]==0)&&(timebounds[1]==10),"Test for timebounds with ComputeBoundingGeometry()"); + for (int i=0; iGetTimeSteps(); i++) + { + mitk::Geometry3D::Pointer subGeometry = geometry->GetGeometry3D(i); + mitk::TimeBounds bounds = subGeometry->GetTimeBounds(); + MITK_TEST_CONDITION((bounds[0]==i)&&(bounds[1]==i+1),"Test for timebounds of geometry at different time steps with ComputeBoundingGeometry()"); + } + geometry = ds->ComputeBoundingGeometry3D(all); + MITK_TEST_CONDITION(geometry->GetTimeSteps()==10, "Test for number or time steps with ComputeBoundingGeometry(allNodes)"); + timebounds = geometry->GetTimeBounds(); + MITK_TEST_CONDITION((timebounds[0]==0)&&(timebounds[1]==10),"Test for timebounds with ComputeBoundingGeometry(allNodes)"); + for (int i=0; iGetTimeSteps(); i++) + { + mitk::Geometry3D::Pointer subGeometry = geometry->GetGeometry3D(i); + mitk::TimeBounds bounds = subGeometry->GetTimeBounds(); + MITK_TEST_CONDITION((bounds[0]==i)&&(bounds[1]==i+1),"Test for timebounds of geometry at different time steps with ComputeBoundingGeometry()"); + } + /* Clear DataStorage */ ds->Remove(ds->GetAll()); MITK_TEST_CONDITION(ds->GetAll()->Size() == 0, "Checking Clear DataStorage"); } diff --git a/CoreUI/Bundles/org.mitk.gui.qt.common/src/QmitkFileOpenAction.cpp b/CoreUI/Bundles/org.mitk.gui.qt.common/src/QmitkFileOpenAction.cpp index 0d815df5c9..5b91e9ba0f 100644 --- a/CoreUI/Bundles/org.mitk.gui.qt.common/src/QmitkFileOpenAction.cpp +++ b/CoreUI/Bundles/org.mitk.gui.qt.common/src/QmitkFileOpenAction.cpp @@ -1,140 +1,140 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "QmitkFileOpenAction.h" #include #include #include #include #include #include #include "QmitkStdMultiWidgetEditor.h" QmitkFileOpenAction::QmitkFileOpenAction(cherry::IWorkbenchWindow::Pointer window) : QAction(0) { m_Window = window; this->setParent(static_cast(m_Window->GetShell()->GetControl())); this->setText("&Open..."); m_Window = window; this->connect(this, SIGNAL(triggered(bool)), this, SLOT(Run())); } void QmitkFileOpenAction::Run() { //QFileDialog dialog(static_cast(m_Window->GetShell()->GetControl())); //dialog.setFileMode(QFileDialog::ExistingFiles); //QStringList filters; //filters << "Images (*.pic *.pic.gz *.vti *.dcm *.nhdr *.nrrd *.mhd)" // << "Surfaces (*.stl *.vtk *.vtp)" // << "MITK Pointset (*.mps)" // << "All Files (*.*)"; //dialog.setFilters(filters); QStringList fileNames = QFileDialog::getOpenFileNames(NULL,"Open","/",mitk::CoreObjectFactory::GetInstance()->GetFileExtensions()); //if (dialog.exec()) // fileNames = dialog.selectedFiles(); if (fileNames.empty()) return; mitk::DataStorageEditorInput::Pointer editorInput; mitk::DataStorage::Pointer dataStorage; QmitkStdMultiWidgetEditor::Pointer multiWidgetEditor; cherry::IEditorPart::Pointer editor = m_Window->GetActivePage()->GetActiveEditor(); if (editor.Cast().IsNull()) { editorInput = new mitk::DataStorageEditorInput(); dataStorage = editorInput->GetDataStorageReference()->GetDataStorage(); } else { multiWidgetEditor = editor.Cast(); dataStorage = multiWidgetEditor->GetEditorInput().Cast()->GetDataStorageReference()->GetDataStorage(); } bool dsmodified = false; for (QStringList::Iterator fileName = fileNames.begin(); fileName != fileNames.end(); ++fileName) { mitk::DataTreeNodeFactory::Pointer nodeReader = mitk::DataTreeNodeFactory::New(); try { nodeReader->SetFileName(fileName->toStdString()); nodeReader->Update(); for ( unsigned int i = 0 ; i < nodeReader->GetNumberOfOutputs( ); ++i ) { mitk::DataTreeNode::Pointer node; node = nodeReader->GetOutput(i); if ( node->GetData() != NULL ) { dataStorage->Add(node); dsmodified = true; } } } catch(...) { } } if (multiWidgetEditor.IsNull()) { cherry::IEditorPart::Pointer editor = m_Window->GetActivePage()->OpenEditor(editorInput, QmitkStdMultiWidgetEditor::EDITOR_ID); multiWidgetEditor = editor.Cast(); } else { multiWidgetEditor->GetStdMultiWidget()->RequestUpdate(); } if(dsmodified) { mitk::Geometry3D::Pointer geometry = dataStorage->ComputeBoundingGeometry3D(); - if ( geometry.IsNotNull() ) - { - // let's see if we have data with a limited live-span ... - mitk::TimeBounds timebounds = geometry->GetTimeBounds(); - if ( timebounds[1] < mitk::ScalarTypeNumericTraits::max() ) - { - mitk::ScalarType duration = timebounds[1]-timebounds[0]; - - mitk::TimeSlicedGeometry::Pointer timegeometry = - mitk::TimeSlicedGeometry::New(); - timegeometry->InitializeEvenlyTimed( - geometry, (unsigned int) duration ); - timegeometry->SetTimeBounds( timebounds ); - - timebounds[1] = timebounds[0] + 1.0; - geometry->SetTimeBounds( timebounds ); - - geometry = timegeometry; - } - } - mitk::RenderingManager::GetInstance()->InitializeViews(geometry); + //if ( geometry.IsNotNull() ) + //{ + // // let's see if we have data with a limited live-span ... + // mitk::TimeBounds timebounds = geometry->GetTimeBounds(); + // if ( timebounds[1] < mitk::ScalarTypeNumericTraits::max() ) + // { + // mitk::ScalarType duration = timebounds[1]-timebounds[0]; + + // mitk::TimeSlicedGeometry::Pointer timegeometry = + // mitk::TimeSlicedGeometry::New(); + // timegeometry->InitializeEvenlyTimed( + // geometry, (unsigned int) duration ); + // timegeometry->SetTimeBounds( timebounds ); + + // timebounds[1] = timebounds[0] + 1.0; + // geometry->SetTimeBounds( timebounds ); + + // geometry = timegeometry; + // } + //} + mitk::RenderingManager::GetInstance()->InitializeViews(geometry,mitk::RenderingManager::REQUEST_UPDATE_ALL,true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } }