diff --git a/Core/Code/DataManagement/mitkBaseData.cpp b/Core/Code/DataManagement/mitkBaseData.cpp index 97fc10009f..ea8a723463 100644 --- a/Core/Code/DataManagement/mitkBaseData.cpp +++ b/Core/Code/DataManagement/mitkBaseData.cpp @@ -1,352 +1,364 @@ /*========================================================================= 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 "mitkBaseData.h" #include #include template class MITK_CORE_EXPORT itk::SmartPointerForwardReference; #define MITK_WEAKPOINTER_PROBLEM_WORKAROUND_ENABLED mitk::BaseData::BaseData() : m_RequestedRegionInitialized(false), m_SmartSourcePointer(NULL), m_SourceOutputIndexDuplicate(0), m_Initialized(true), m_Unregistering(false), m_CalculatingExternalReferenceCount(false), m_ExternalReferenceCount(-1) { m_TimeSlicedGeometry = TimeSlicedGeometry::New(); m_PropertyList = PropertyList::New(); } +mitk::BaseData::BaseData( const BaseData &other ): +m_RequestedRegionInitialized(other.m_RequestedRegionInitialized), +m_SmartSourcePointer(other.m_SmartSourcePointer), +m_SourceOutputIndexDuplicate(other.m_SourceOutputIndexDuplicate), +m_Initialized(other.m_Initialized), m_Unregistering(other.m_Unregistering), +m_CalculatingExternalReferenceCount(other.m_CalculatingExternalReferenceCount), +m_ExternalReferenceCount(other.m_ExternalReferenceCount) +{ + m_TimeSlicedGeometry = dynamic_cast(other.m_TimeSlicedGeometry->Clone().GetPointer()); + m_PropertyList = other.m_PropertyList->Clone(); +} + mitk::BaseData::~BaseData() { m_SmartSourcePointer = NULL; } void mitk::BaseData::InitializeTimeSlicedGeometry(unsigned int timeSteps) { mitk::TimeSlicedGeometry::Pointer timeGeometry = this->GetTimeSlicedGeometry(); mitk::Geometry3D::Pointer g3d = mitk::Geometry3D::New(); g3d->Initialize(); if ( timeSteps > 1 ) { mitk::ScalarType timeBounds[] = {0.0, 1.0}; g3d->SetTimeBounds( timeBounds ); } // The geometry is propagated automatically to the other items, // if EvenlyTimed is true... timeGeometry->InitializeEvenlyTimed( g3d.GetPointer(), timeSteps ); } void mitk::BaseData::UpdateOutputInformation() { if ( this->GetSource() ) { this->GetSource()->UpdateOutputInformation(); } if(m_TimeSlicedGeometry.IsNotNull()) m_TimeSlicedGeometry->UpdateInformation(); } const mitk::TimeSlicedGeometry* mitk::BaseData::GetUpdatedTimeSlicedGeometry() { SetRequestedRegionToLargestPossibleRegion(); UpdateOutputInformation(); return GetTimeSlicedGeometry(); } void mitk::BaseData::Expand( unsigned int timeSteps ) { if( m_TimeSlicedGeometry.IsNotNull() ) m_TimeSlicedGeometry->ExpandToNumberOfTimeSteps( timeSteps ); } const mitk::Geometry3D* mitk::BaseData::GetUpdatedGeometry(int t) { SetRequestedRegionToLargestPossibleRegion(); UpdateOutputInformation(); return GetGeometry(t); } void mitk::BaseData::SetGeometry(Geometry3D* aGeometry3D) { if(aGeometry3D!=NULL) { TimeSlicedGeometry::Pointer timeSlicedGeometry = dynamic_cast(aGeometry3D); if ( timeSlicedGeometry.IsNotNull() ) m_TimeSlicedGeometry = timeSlicedGeometry; else { timeSlicedGeometry = TimeSlicedGeometry::New(); m_TimeSlicedGeometry = timeSlicedGeometry; timeSlicedGeometry->InitializeEvenlyTimed(aGeometry3D, 1); } Modified(); } else if( m_TimeSlicedGeometry.IsNotNull() ) { m_TimeSlicedGeometry = NULL; Modified(); } return; } void mitk::BaseData::SetClonedGeometry(const Geometry3D* aGeometry3D) { SetGeometry(static_cast(aGeometry3D->Clone().GetPointer())); } void mitk::BaseData::SetClonedGeometry(const Geometry3D* aGeometry3D, unsigned int time) { if (m_TimeSlicedGeometry) { m_TimeSlicedGeometry->SetGeometry3D(static_cast(aGeometry3D->Clone().GetPointer()), time); } } bool mitk::BaseData::IsEmptyTimeStep(unsigned int) const { return IsInitialized() == false; } bool mitk::BaseData::IsEmpty() const { if(IsInitialized() == false) return true; const TimeSlicedGeometry* timeGeometry = const_cast(this)->GetUpdatedTimeSlicedGeometry(); if(timeGeometry == NULL) return true; unsigned int timeSteps = timeGeometry->GetTimeSteps(); for ( unsigned int t = 0 ; t < timeSteps ; ++t ) { if(IsEmptyTimeStep(t) == false) return false; } return true; } itk::SmartPointerForwardReference mitk::BaseData::GetSource() const { return static_cast(Superclass::GetSource().GetPointer()); } int mitk::BaseData::GetExternalReferenceCount() const { if(m_CalculatingExternalReferenceCount==false) //this is only needed because a smart-pointer to m_Outputs (private!!) must be created by calling GetOutputs. { m_CalculatingExternalReferenceCount = true; m_ExternalReferenceCount = -1; int realReferenceCount = GetReferenceCount(); if(GetSource()==NULL) { m_ExternalReferenceCount = realReferenceCount; m_CalculatingExternalReferenceCount = false; return m_ExternalReferenceCount; } mitk::BaseProcess::DataObjectPointerArray outputs = m_SmartSourcePointer->GetOutputs(); unsigned int idx; for (idx = 0; idx < outputs.size(); ++idx) { //references of outputs that are not referenced from someone else (reference additional to the reference from this BaseProcess object) are interpreted as non-existent if(outputs[idx]==this) --realReferenceCount; } m_ExternalReferenceCount = realReferenceCount; if(m_ExternalReferenceCount<0) m_ExternalReferenceCount=0; m_CalculatingExternalReferenceCount = false; } else return -1; return m_ExternalReferenceCount; } void mitk::BaseData::UnRegister() const { #ifdef MITK_WEAKPOINTER_PROBLEM_WORKAROUND_ENABLED if(GetReferenceCount()>1) { Superclass::UnRegister(); if((m_Unregistering==false) && (m_SmartSourcePointer.IsNotNull())) { m_Unregistering=true; // the order of the following boolean statement is important: // this->GetSource() returns a SmartPointerForwardReference, // which increases and afterwards decreases the reference count, // which may result in an ExternalReferenceCount of 0, causing // BaseProcess::UnRegister() to destroy us (also we already // about to do that). if((this->m_SmartSourcePointer->GetExternalReferenceCount()==0) || (this->GetSource()==NULL)) m_SmartSourcePointer=NULL; // now the reference count is zero and this object has been destroyed; thus nothing may be done after this line!! else m_Unregistering=false; } } else #endif Superclass::UnRegister(); // now the reference count is zero and this object has been destroyed; thus nothing may be done after this line!! } void mitk::BaseData::ConnectSource(itk::ProcessObject *arg, unsigned int idx) const { #ifdef MITK_WEAKPOINTER_PROBLEM_WORKAROUND_ENABLED itkDebugMacro( "connecting source " << arg << ", source output index " << idx); if ( GetSource() != arg || m_SourceOutputIndexDuplicate != idx) { m_SmartSourcePointer = dynamic_cast(arg); m_SourceOutputIndexDuplicate = idx; Modified(); } #endif } mitk::PropertyList::Pointer mitk::BaseData::GetPropertyList() const { return m_PropertyList; } mitk::BaseProperty::Pointer mitk::BaseData::GetProperty(const char *propertyKey) const { return m_PropertyList->GetProperty(propertyKey); } void mitk::BaseData::SetProperty(const char *propertyKey, BaseProperty* propertyValue) { m_PropertyList->SetProperty(propertyKey, propertyValue); } void mitk::BaseData::SetPropertyList(PropertyList *pList) { m_PropertyList = pList; } void mitk::BaseData::SetOrigin(const mitk::Point3D& origin) { mitk::TimeSlicedGeometry* timeSlicedGeometry = GetTimeSlicedGeometry(); assert(timeSlicedGeometry!=NULL); mitk::Geometry3D* geometry; unsigned int steps = timeSlicedGeometry->GetTimeSteps(); for(unsigned int timestep = 0; timestep < steps; ++timestep) { geometry = GetGeometry(timestep); if(geometry != NULL) { geometry->SetOrigin(origin); } if(GetTimeSlicedGeometry()->GetEvenlyTimed()) { GetTimeSlicedGeometry()->InitializeEvenlyTimed(geometry, steps); break; } } } unsigned long mitk::BaseData::GetMTime() const { unsigned long time = Superclass::GetMTime(); if(m_TimeSlicedGeometry.IsNotNull()) { if((time < m_TimeSlicedGeometry->GetMTime())) { Modified(); return Superclass::GetMTime(); } //unsigned long geometryTime = m_TimeSlicedGeometry->GetMTime(); //if(time < geometryTime) //{ // return geometryTime; //} } return time; } void mitk::BaseData::CopyInformation( const itk::DataObject* data ) { const Self* bd = dynamic_cast(data); if (bd != NULL) { m_TimeSlicedGeometry = dynamic_cast(bd->GetTimeSlicedGeometry()->Clone().GetPointer()); m_PropertyList = bd->GetPropertyList()->Clone(); } else { // pointer could not be cast back down; this can be the case if your filters input // and output objects differ in type; then you have to write your own GenerateOutputInformation method itkExceptionMacro(<< "mitk::BaseData::CopyInformation() cannot cast " << typeid(data).name() << " to " << typeid(Self*).name() ); } } bool mitk::BaseData::IsInitialized() const { return m_Initialized; } void mitk::BaseData::Clear() { this->ClearData(); this->InitializeEmpty(); } void mitk::BaseData::ClearData() { if(m_Initialized) { ReleaseData(); m_Initialized = false; } } void mitk::BaseData::ExecuteOperation(mitk::Operation* /*operation*/) { //empty by default. override if needed! } void mitk::BaseData::PrintSelf(std::ostream& os, itk::Indent indent) const { os << std::endl; os << indent << " TimeSlicedGeometry: "; if(GetTimeSlicedGeometry() == NULL) os << "NULL" << std::endl; else GetTimeSlicedGeometry()->Print(os, indent); } diff --git a/Core/Code/DataManagement/mitkBaseData.h b/Core/Code/DataManagement/mitkBaseData.h index bb3dc0eb18..937f7a4712 100644 --- a/Core/Code/DataManagement/mitkBaseData.h +++ b/Core/Code/DataManagement/mitkBaseData.h @@ -1,387 +1,388 @@ /*========================================================================= 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 BASEDATA_H_HEADER_INCLUDED_C1EBB6FA #define BASEDATA_H_HEADER_INCLUDED_C1EBB6FA #include #include "mitkBaseProcess.h" #include "mitkTimeSlicedGeometry.h" #include "mitkCommon.h" #include "mitkOperationActor.h" #include "mitkPropertyList.h" namespace mitk { class BaseProcess; //##Documentation //## @brief Base of all data objects //## //## Base of all data objects, e.g., images, contours, surfaces etc. Inherits //## from itk::DataObject and thus can be included in a pipeline. //## Inherits also from OperationActor and can be used as a destination for Undo //## @ingroup Data class MITK_CORE_EXPORT BaseData : public itk::DataObject, public OperationActor { public: - mitkClassMacro(BaseData,itk::DataObject) + mitkClassMacro(BaseData,itk::DataObject); //##Documentation //## @brief Return the TimeSlicedGeometry of the data as const pointer. //## //## \warning No update will be called. Use GetUpdatedGeometry() if you cannot //## be sure that the geometry is up-to-date. //## //## Normally used in GenerateOutputInformation of subclasses of BaseProcess. const mitk::TimeSlicedGeometry* GetTimeSlicedGeometry() const { return m_TimeSlicedGeometry.GetPointer(); } //##Documentation //## @brief Return the TimeSlicedGeometry of the data as pointer. //## //## \warning No update will be called. Use GetUpdatedGeometry() if you cannot //## be sure that the geometry is up-to-date. //## //## Normally used in GenerateOutputInformation of subclasses of BaseProcess. mitk::TimeSlicedGeometry* GetTimeSlicedGeometry() { return m_TimeSlicedGeometry.GetPointer(); } //##Documentation //## @brief Return the Geometry3D of the data. //## //## The method does not simply return the value of the m_TimeSlicedGeometry //## member. Before doing this, it makes sure that the TimeSlicedGeometry //## is up-to-date (by setting the update extent to largest possible and //## calling UpdateOutputInformation). const mitk::TimeSlicedGeometry* GetUpdatedTimeSlicedGeometry(); //##Documentation //## @brief Expands the TimeSlicedGeometry to a number of TimeSteps. //## //## The method expands the TimeSlicedGeometry to the given number of TimeSteps, //## filling newly created elements with empty geometries. Sub-classes should override //## this method to handle the elongation of their data vectors, too. //## Note that a shrinking is neither possible nor intended. virtual void Expand( unsigned int timeSteps ); //##Documentation //## @brief Return the Geometry3D of the data at time \a t. //## //## The method does not simply return //## m_TimeSlicedGeometry->GetGeometry(t). //## Before doing this, it makes sure that the Geometry3D is up-to-date //## (by setting the update extent appropriately and calling //## UpdateOutputInformation). //## //## @todo Appropriate setting of the update extent is missing. const mitk::Geometry3D* GetUpdatedGeometry(int t=0); //##Documentation //## @brief Return the geometry, which is a TimeSlicedGeometry, of the data //## as non-const pointer. //## //## \warning No update will be called. Use GetUpdatedGeometry() if you cannot //## be sure that the geometry is up-to-date. //## //## Normally used in GenerateOutputInformation of subclasses of BaseProcess. mitk::Geometry3D* GetGeometry(int t=0) const { if(m_TimeSlicedGeometry.IsNull()) return NULL; return m_TimeSlicedGeometry->GetGeometry3D(t); } //##Documentation //## @brief Helps to deal with the weak-pointer-problem. virtual void UnRegister() const; //##Documentation //## @brief for internal use only. Helps to deal with the //## weak-pointer-problem. virtual int GetExternalReferenceCount() const; //##Documentation //## @brief Update the information for this BaseData (the geometry in particular) //## so that it can be used as an output of a BaseProcess. //## //## This method is used in the pipeline mechanism to propagate information and //## initialize the meta data associated with a BaseData. Any implementation //## of this method in a derived class is assumed to call its source's //## BaseProcess::UpdateOutputInformation() which determines modified //## times, LargestPossibleRegions, and any extra meta data like spacing, //## origin, etc. Default implementation simply call's it's source's //## UpdateOutputInformation(). //## \note Implementations of this methods in derived classes must take care //## that the geometry is updated by calling //## GetTimeSlicedGeometry()->UpdateInformation() //## \em after calling its source's BaseProcess::UpdateOutputInformation(). void UpdateOutputInformation(); //##Documentation //## @brief Set the RequestedRegion to the LargestPossibleRegion. //## //## This forces a filter to produce all of the output in one execution //## (i.e. not streaming) on the next call to Update(). void SetRequestedRegionToLargestPossibleRegion()=0; //##Documentation //## @brief Determine whether the RequestedRegion is outside of the BufferedRegion. //## //## This method returns true if the RequestedRegion //## is outside the BufferedRegion (true if at least one pixel is //## outside). This is used by the pipeline mechanism to determine //## whether a filter needs to re-execute in order to satisfy the //## current request. If the current RequestedRegion is already //## inside the BufferedRegion from the previous execution (and the //## current filter is up to date), then a given filter does not need //## to re-execute bool RequestedRegionIsOutsideOfTheBufferedRegion()=0; //##Documentation //## @brief Verify that the RequestedRegion is within the LargestPossibleRegion. //## //## If the RequestedRegion is not within the LargestPossibleRegion, //## then the filter cannot possibly satisfy the request. This method //## returns true if the request can be satisfied (even if it will be //## necessary to process the entire LargestPossibleRegion) and //## returns false otherwise. This method is used by //## PropagateRequestedRegion(). PropagateRequestedRegion() throws a //## InvalidRequestedRegionError exception if the requested region is //## not within the LargestPossibleRegion. virtual bool VerifyRequestedRegion() = 0; //##Documentation //## @brief Copy information from the specified data set. //## //## This method is part of the pipeline execution model. By default, a //## BaseProcess will copy meta-data from the first input to all of its //## outputs. See ProcessObject::GenerateOutputInformation(). Each //## subclass of DataObject is responsible for being able to copy //## whatever meta-data it needs from another DataObject. //## The default implementation of this method copies the time sliced geometry //## and the property list of an object. If a subclass overrides this //## method, it should always call its superclass' version. void CopyInformation(const itk::DataObject* data); //##Documentation //## @brief Check whether the data has been initialized, i.e., //## at least the Geometry and other header data has been set //## //## \warning Set to \a true by default for compatibility reasons. //## Set m_Initialized=false in constructors of sub-classes that //## support distinction between initialized and uninitialized state. virtual bool IsInitialized() const; //##Documentation //## @brief Calls ClearData() and InitializeEmpty(); //## \warning Only use in subclasses that reimplemented these methods. //## Just calling Clear from BaseData will reset an object to a not initialized, //## invalid state. virtual void Clear(); //##Documentation //## @brief Check whether object contains data (at //## a specified time), e.g., a set of points may be empty //## //## \warning Returns IsInitialized()==false by default for //## compatibility reasons. Override in sub-classes that //## support distinction between empty/non-empty state. virtual bool IsEmptyTimeStep(unsigned int t) const; //##Documentation //## @brief Check whether object contains data (at //## least at one point in time), e.g., a set of points //## may be empty //## //## \warning Returns IsInitialized()==false by default for //## compatibility reasons. Override in sub-classes that //## support distinction between empty/non-empty state. virtual bool IsEmpty() const; //##Documentation //## @brief Set the requested region from this data object to match the requested //## region of the data object passed in as a parameter. //## //## This method is implemented in the concrete subclasses of BaseData. void SetRequestedRegion(itk::DataObject *data)=0; //##Documentation //##@brief overwrite if the Data can be called by an Interactor (StateMachine). //## //## Empty by default. Overwrite and implement all the necessary operations here //## and get the necessary information from the parameter operation. void ExecuteOperation(Operation* operation); //##Documentation //## @brief Set the Geometry3D of the data, which will be referenced (not copied!). //## Assumes the data object has only 1 time step ( is a 3D object ). //## //## For convenience (and historic) reasons, it is also possible to set a complete //## mitk::TimeSlicedGeometry*, which will be referenced (not copied!). //## //## @warning This method will normally be called internally by the sub-class of BaseData //## during initialization. //## \sa SetClonedGeometry virtual void SetGeometry(Geometry3D* aGeometry3D); //##Documentation //## @brief Set a clone of the provided geometry as Geometry3D of the data. //## Assumes the data object has only 1 time step ( is a 3D object ) //## //## \sa SetGeometry virtual void SetClonedGeometry(const Geometry3D* aGeometry3D); //##Documentation //## @brief Set a clone of the provided geometry as Geometry3D of a given time step. //## //## \sa SetGeometry virtual void SetClonedGeometry(const Geometry3D* aGeometry3D, unsigned int time); //##Documentation //## @brief Get the data's property list //## @sa GetProperty //## @sa m_PropertyList mitk::PropertyList::Pointer GetPropertyList() const; //##Documentation //## @brief Set the data's property list //## @sa SetProperty //## @sa m_PropertyList void SetPropertyList(PropertyList* propertyList); //##Documentation //## @brief Get the property (instance of BaseProperty) with key @a propertyKey from the PropertyList, //## and set it to this, respectively; //## @sa GetPropertyList //## @sa m_PropertyList //## @sa m_MapOfPropertyLists mitk::BaseProperty::Pointer GetProperty(const char *propertyKey) const; void SetProperty(const char *propertyKey, BaseProperty* property); //##Documentation //## @brief Convenience method for setting the origin of //## the Geometry3D instances of all time steps //## //## \warning Geometries contained in the Geometry3D will //## \em not be changed, e.g. in case the Geometry3D is a //## SlicedGeometry3D the origin will \em not be propagated //## to the contained slices. The sub-class SlicedData //## does this for the case that the SlicedGeometry3D is //## evenly spaced. virtual void SetOrigin(const Point3D& origin); /** \brief Get the process object that generated this data object. * * If there is no process object, then the data object has * been disconnected from the pipeline, or the data object * was created manually. (Note: we cannot use the GetObjectMacro() * defined in itkMacro because the mutual dependency of * DataObject and ProcessObject causes compile problems. Also, * a forward reference smart pointer is returned, not a smart pointer, * because of the circular dependency between the process and data object.) * * GetSource() returns a SmartPointerForwardReference and not a WeakPointer * because it is assumed the code calling GetSource() wants to hold a * long term reference to the source. */ itk::SmartPointerForwardReference GetSource() const; //##Documentation //## @brief Get the number of time steps from the Timeslicedgeometry //## As the base data has not a data vector given by itself, the number //## of time steps is defined over the time sliced geometry. In sub classes, //## a better implementation could be over the length of the data vector. unsigned int GetTimeSteps() const { return m_TimeSlicedGeometry->GetTimeSteps(); }; //##Documentation //## @brief Get the modified time of the last change of the contents //## this data object or its geometry. virtual unsigned long GetMTime() const; protected: BaseData(); + BaseData(const BaseData &other); ~BaseData(); //##Documentation //## @brief Initialize the TimeSlicedGeometry for a number of time steps. //## The TimeSlicedGeometry is initialized empty and evenly timed. //## In many cases it will be necessary to overwrite this in sub-classes. virtual void InitializeTimeSlicedGeometry( unsigned int timeSteps = 1 ); //##Documentation //## @brief reset to non-initialized state, release memory virtual void ClearData(); //##Documentation //## @brief Pure virtual; Must be used in subclasses to get a data object to a //## valid state. Should at least create one empty object and call //## Superclass::InitializeTimeSlicedGeometry() to ensure an existing valid geometry virtual void InitializeEmpty(){}; virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; bool m_RequestedRegionInitialized; bool m_LastRequestedRegionWasOutsideOfTheBufferedRegion; mutable itk::SmartPointer m_SmartSourcePointer; mutable unsigned int m_SourceOutputIndexDuplicate; //##Documentation //## @brief for internal use only. Helps to deal with the //## weak-pointer-problem. virtual void ConnectSource(itk::ProcessObject *arg, unsigned int idx) const; bool m_Initialized; private: //##Documentation //## @brief Helps to deal with the weak-pointer-problem. mutable bool m_Unregistering; //##Documentation //## @brief Helps to deal with the weak-pointer-problem. mutable bool m_CalculatingExternalReferenceCount; //##Documentation //## @brief Helps to deal with the weak-pointer-problem. mutable int m_ExternalReferenceCount; //##Documentation //## @brief PropertyList, f.e. to hold pic-tags, tracking-data,.. //## PropertyList::Pointer m_PropertyList; TimeSlicedGeometry::Pointer m_TimeSlicedGeometry; //##Documentation //## @brief Helps to deal with the weak-pointer-problem. friend class mitk::BaseProcess; }; } // namespace mitk #endif /* BASEDATA_H_HEADER_INCLUDED_C1EBB6FA */ diff --git a/Core/Code/DataManagement/mitkBaseDataTestImplementation.h b/Core/Code/DataManagement/mitkBaseDataTestImplementation.h index 8319fc1f0a..4d397391f0 100644 --- a/Core/Code/DataManagement/mitkBaseDataTestImplementation.h +++ b/Core/Code/DataManagement/mitkBaseDataTestImplementation.h @@ -1,59 +1,60 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision: 18127 $ 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 BASEDATAIMPLEMENTATION_H_HEADER_INCLUDED #define BASEDATAIMPLEMENTATION_H_HEADER_INCLUDED #include "mitkBaseData.h" namespace mitk { //##Documentation //## @brief Implementation of BaseData (for testing) //## //## As BaseData is an abstract class, we need an implementation for testing its methods //## @ingroup Data class BaseDataTestImplementation : public BaseData { public: mitkClassMacro(BaseDataTestImplementation, BaseData); itkNewMacro(Self); + mitkCloneMacro(BaseDataTestImplementation); virtual void InitializeTimeSlicedGeometry( unsigned int timeSteps /* = 1 */ ) { Superclass::InitializeTimeSlicedGeometry(timeSteps); } protected: virtual bool VerifyRequestedRegion(){return false;}; virtual bool RequestedRegionIsOutsideOfTheBufferedRegion(){return false;}; virtual void SetRequestedRegionToLargestPossibleRegion(){}; virtual void SetRequestedRegion(itk::DataObject * /*data*/){}; BaseDataTestImplementation(){}; virtual ~BaseDataTestImplementation(){}; }; } // namespace #endif // BASEDATA_H_HEADER_INCLUDED \ No newline at end of file diff --git a/Core/Code/DataManagement/mitkCommon.h b/Core/Code/DataManagement/mitkCommon.h index 12790d651b..67215556b3 100644 --- a/Core/Code/DataManagement/mitkCommon.h +++ b/Core/Code/DataManagement/mitkCommon.h @@ -1,123 +1,132 @@ /*========================================================================= 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 MITK_COMMON_H_DEFINED #define MITK_COMMON_H_DEFINED #ifdef _MSC_VER // This warns about truncation to 255 characters in debug/browse info #pragma warning (disable : 4786) #pragma warning (disable : 4068 ) /* disable unknown pragma warnings */ #endif //add only those headers here that are really necessary for all classes! #include "itkObject.h" #include "mitkConfig.h" #include "mitkLogMacros.h" #ifndef MITK_UNMANGLE_IPPIC #define mitkIpPicDescriptor mitkIpPicDescriptor #endif typedef unsigned int MapperSlotId; #define mitkClassMacro(className,SuperClassName) \ typedef className Self; \ typedef SuperClassName Superclass; \ typedef itk::SmartPointer Pointer; \ typedef itk::SmartPointer ConstPointer; \ itkTypeMacro(className,SuperClassName) /** * Macro for Constructors with one parameter for classes derived from itk::Lightobject **/ #define mitkNewMacro1Param(classname,type) \ static Pointer New(type _arg) \ { \ Pointer smartPtr = new classname ( _arg ); \ smartPtr->UnRegister(); \ return smartPtr; \ } \ /** * Macro for Constructors with two parameters for classes derived from itk::Lightobject **/ #define mitkNewMacro2Param(classname,typea,typeb) \ static Pointer New(typea _arga, typeb _argb) \ { \ Pointer smartPtr = new classname ( _arga, _argb ); \ smartPtr->UnRegister(); \ return smartPtr; \ } \ /** * Macro for Constructors with three parameters for classes derived from itk::Lightobject **/ #define mitkNewMacro3Param(classname,typea,typeb,typec) \ static Pointer New(typea _arga, typeb _argb, typec _argc) \ { \ Pointer smartPtr = new classname ( _arga, _argb, _argc ); \ smartPtr->UnRegister(); \ return smartPtr; \ } \ /** * Macro for Constructors with three parameters for classes derived from itk::Lightobject **/ #define mitkNewMacro4Param(classname,typea,typeb,typec,typed) \ static Pointer New(typea _arga, typeb _argb, typec _argc, typed _argd) \ { \ Pointer smartPtr = new classname ( _arga, _argb, _argc, _argd ); \ smartPtr->UnRegister(); \ return smartPtr; \ } \ /** Get a smart const pointer to an object. Creates the member * Get"name"() (e.g., GetPoints()). */ #define mitkGetObjectMacroConst(name,type) \ virtual type * Get##name () const \ { \ itkDebugMacro("returning " #name " address " << this->m_##name ); \ return this->m_##name.GetPointer(); \ } +/** Creates a Clone() method for "Classname". Returns a smartPtr of a clone of the +calling object*/ +#define mitkCloneMacro(classname) \ + virtual Pointer Clone() const \ +{ \ + Pointer smartPtr = new classname(*this); \ + return smartPtr; \ +} + /** provide a macro for adding MS specific __declspec(dllexport/-import) * to classes. * This is needed for the export of symbols, when you build a DLL. Then write * * class MITK_EXPORT ClassName : public SomeClass {}; */ #if defined(WIN32) #ifdef mitkCore_EXPORTS #define MITK_CORE_EXPORT __declspec(dllexport) #else #define MITK_CORE_EXPORT __declspec(dllimport) #endif #ifdef Qmitk_EXPORTS #define QMITK_EXPORT __declspec(dllexport) #else #define QMITK_EXPORT __declspec(dllimport) #endif #else #define MITK_CORE_EXPORT #define QMITK_EXPORT #endif // legacy support for designer plugin #define MITK_EXPORT #endif diff --git a/Core/Code/DataManagement/mitkImage.cpp b/Core/Code/DataManagement/mitkImage.cpp index 623b61e96b..92612981cc 100644 --- a/Core/Code/DataManagement/mitkImage.cpp +++ b/Core/Code/DataManagement/mitkImage.cpp @@ -1,1434 +1,1458 @@ /*========================================================================= 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 "mitkImage.h" #include "mitkHistogramGenerator.h" #include "mitkPicHelper.h" #include "mitkImageTimeSelector.h" #include "ipFunc/mitkIpFunc.h" #include "mitkIpPicTypeMultiplex.h" -#include - #include +#include template class MITK_CORE_EXPORT itk::SmartPointerForwardReference; mitk::Image::Image() : - m_Dimension(0), m_Dimensions(NULL), m_OffsetTable(NULL), - m_CompleteData(NULL), m_PixelType(NULL), - m_TimeSelectorForExtremaObject(NULL) +m_Dimension(0), m_Dimensions(NULL), m_OffsetTable(NULL), +m_CompleteData(NULL), m_PixelType(NULL), +m_TimeSelectorForExtremaObject(NULL) { m_CountOfMinValuedVoxels.resize(1, 0); m_CountOfMaxValuedVoxels.resize(1, 0); m_ScalarMin.resize(1, itk::NumericTraits::max()); m_ScalarMax.resize(1, itk::NumericTraits::NonpositiveMin()); m_Scalar2ndMin.resize(1, itk::NumericTraits::max()); m_Scalar2ndMax.resize(1, itk::NumericTraits::NonpositiveMin()); m_Initialized = false; mitk::HistogramGenerator::Pointer generator = mitk::HistogramGenerator::New(); m_HistogramGeneratorObject = generator; } +mitk::Image::Image(const Image &other) : SlicedData(other), m_Dimension(0), +m_Dimensions(NULL), m_OffsetTable(NULL), m_CompleteData(NULL), m_PixelType(NULL), +m_TimeSelectorForExtremaObject(NULL) +{ + this->Initialize(&other); + + if (this->GetDimension() > 3) + { + const unsigned int time_steps = this->GetDimension(3); + + for (unsigned int i = 0u; i < time_steps; ++i) + { + ImageDataItemPointer volume = const_cast(other).GetVolumeData(i); + + this->SetVolume(volume->GetData(), i); + } + } + else + { + ImageDataItemPointer volume = const_cast(other).GetVolumeData(0); + + this->SetVolume(volume->GetData(), 0); + } +} + mitk::Image::~Image() { Clear(); m_ReferenceCountLock.Lock(); m_ReferenceCount = 3; m_ReferenceCountLock.Unlock(); m_HistogramGeneratorObject = NULL; m_TimeSelectorForExtremaObject = NULL; m_ReferenceCountLock.Lock(); m_ReferenceCount = 0; m_ReferenceCountLock.Unlock(); delete [] m_OffsetTable; } const mitk::PixelType& mitk::Image::GetPixelType(int /*n*/) const { return m_PixelType; } unsigned int mitk::Image::GetDimension() const { return m_Dimension; } unsigned int mitk::Image::GetDimension(int i) const { if((i>=0) && (i<(int)m_Dimension)) return m_Dimensions[i]; return 1; } void* mitk::Image::GetData() { if(m_Initialized==false) { if(GetSource()==NULL) return NULL; if(GetSource()->Updating()==false) GetSource()->UpdateOutputInformation(); } m_CompleteData=GetChannelData(); return m_CompleteData->GetData(); } template void AccessPixel(mitkIpPicDescriptor* pic, const mitk::Index3D& p, double& value, int timestep) { if ( (p[0]>=0 && p[1] >=0 && p[2]>=0 && timestep>=0) && (unsigned int)p[0] < pic->n[0] && (unsigned int)p[1] < pic->n[1] && (unsigned int)p[2] < pic->n[2] && (unsigned int)timestep < pic->n[3] ) { if(pic->bpe!=24) { value = (double) (((T*) pic->data)[ p[0] + p[1]*pic->n[0] + p[2]*pic->n[0]*pic->n[1] + timestep*pic->n[0]*pic->n[1]*pic->n[2] ]); } else { double returnvalue = (((T*) pic->data)[p[0]*3 + 0 + p[1]*pic->n[0]*3 + p[2]*pic->n[0]*pic->n[1]*3 + timestep*pic->n[0]*pic->n[1]*pic->n[2]*3 ]); returnvalue += (((T*) pic->data)[p[0]*3 + 1 + p[1]*pic->n[0]*3 + p[2]*pic->n[0]*pic->n[1]*3 + timestep*pic->n[0]*pic->n[1]*pic->n[2]*3]); returnvalue += (((T*) pic->data)[p[0]*3 + 2 + p[1]*pic->n[0]*3 + p[2]*pic->n[0]*pic->n[1]*3 + timestep*pic->n[0]*pic->n[1]*pic->n[2]*3]); value = returnvalue; } } else { value = 0; } }; double mitk::Image::GetPixelValueByIndex(const mitk::Index3D &position, unsigned int timestep) { mitkIpPicDescriptor* pic = this->GetPic(); double value = 0; if (this->GetTimeSteps() < timestep) { timestep = this->GetTimeSteps(); } mitkIpPicTypeMultiplex3(AccessPixel, pic, position, value, timestep); return value; } double mitk::Image::GetPixelValueByWorldCoordinate(const mitk::Point3D& position, unsigned int timestep) { mitkIpPicDescriptor* pic = this->GetPic(); double value = 0; if (this->GetTimeSteps() < timestep) { timestep = this->GetTimeSteps(); } Index3D itkIndex; this->GetGeometry()->WorldToIndex(position,itkIndex); mitkIpPicTypeMultiplex3(AccessPixel, pic, itkIndex, value, timestep); return value; } vtkImageData* mitk::Image::GetVtkImageData(int t, int n) { if(m_Initialized==false) { if(GetSource()==NULL) return NULL; if(GetSource()->Updating()==false) GetSource()->UpdateOutputInformation(); } ImageDataItemPointer volume=GetVolumeData(t, n); if(volume.GetPointer()==NULL || volume->GetVtkImageData() == NULL) return NULL; float *fspacing = const_cast(GetSlicedGeometry(t)->GetFloatSpacing()); double dspacing[3] = {fspacing[0],fspacing[1],fspacing[2]}; volume->GetVtkImageData()->SetSpacing( dspacing ); return volume->GetVtkImageData(); } mitkIpPicDescriptor* mitk::Image::GetPic() { if(m_Initialized==false) { if(GetSource()==NULL) return NULL; if(GetSource()->Updating()==false) GetSource()->UpdateOutputInformation(); } m_CompleteData=GetChannelData(); if(m_CompleteData.GetPointer()==NULL) return NULL; return m_CompleteData->GetPicDescriptor(); } mitk::Image::ImageDataItemPointer mitk::Image::GetSliceData(int s, int t, int n, void *data, ImportMemoryManagementType importMemoryManagement) { if(IsValidSlice(s,t,n)==false) return NULL; // slice directly available? int pos=GetSliceIndex(s,t,n); if(m_Slices[pos].GetPointer()!=NULL) return m_Slices[pos]; // is slice available as part of a volume that is available? ImageDataItemPointer sl, ch, vol; vol=m_Volumes[GetVolumeIndex(t,n)]; if((vol.GetPointer()!=NULL) && (vol->IsComplete())) { sl=new ImageDataItem(*vol, 2, data, importMemoryManagement == ManageMemory, ((size_t) s)*m_OffsetTable[2]*(m_PixelType.GetBpe()/8)); sl->SetComplete(true); return m_Slices[pos]=sl; } // is slice available as part of a channel that is available? ch=m_Channels[n]; if((ch.GetPointer()!=NULL) && (ch->IsComplete())) { sl=new ImageDataItem(*ch, 2, data, importMemoryManagement == ManageMemory, (((size_t) s)*m_OffsetTable[2]+((size_t) t)*m_OffsetTable[3])*(m_PixelType.GetBpe()/8)); sl->SetComplete(true); return m_Slices[pos]=sl; } // slice is unavailable. Can we calculate it? if((GetSource()!=NULL) && (GetSource()->Updating()==false)) { // ... wir mussen rechnen!!! .... m_RequestedRegion.SetIndex(0, 0); m_RequestedRegion.SetIndex(1, 0); m_RequestedRegion.SetIndex(2, s); m_RequestedRegion.SetIndex(3, t); m_RequestedRegion.SetIndex(4, n); m_RequestedRegion.SetSize(0, m_Dimensions[0]); m_RequestedRegion.SetSize(1, m_Dimensions[1]); m_RequestedRegion.SetSize(2, 1); m_RequestedRegion.SetSize(3, 1); m_RequestedRegion.SetSize(4, 1); m_RequestedRegionInitialized=true; GetSource()->Update(); if(IsSliceSet(s,t,n)) //yes: now we can call ourselves without the risk of a endless loop (see "if" above) return GetSliceData(s,t,n,data,importMemoryManagement); else return NULL; } else { ImageDataItemPointer item = AllocateSliceData(s,t,n,data,importMemoryManagement); item->SetComplete(true); return item; } } mitk::Image::ImageDataItemPointer mitk::Image::GetVolumeData(int t, int n, void *data, ImportMemoryManagementType importMemoryManagement) { if(IsValidVolume(t,n)==false) return NULL; ImageDataItemPointer ch, vol; // volume directly available? int pos=GetVolumeIndex(t,n); vol=m_Volumes[pos]; if((vol.GetPointer()!=NULL) && (vol->IsComplete())) return vol; // is volume available as part of a channel that is available? ch=m_Channels[n]; if((ch.GetPointer()!=NULL) && (ch->IsComplete())) { vol=new ImageDataItem(*ch, 3, data, importMemoryManagement == ManageMemory, (((size_t) t)*m_OffsetTable[3])*(m_PixelType.GetBpe()/8)); vol->SetComplete(true); return m_Volumes[pos]=vol; } // let's see if all slices of the volume are set, so that we can (could) combine them to a volume bool complete=true; unsigned int s; for(s=0;sSetComplete(true); } else { vol=m_Volumes[pos]; // ok, let's combine the slices! if(vol.GetPointer()==NULL) vol=new ImageDataItem(m_PixelType, 3, m_Dimensions, NULL, true); vol->SetComplete(true); size_t size=m_OffsetTable[2]*(m_PixelType.GetBpe()/8); for(s=0;sGetParent()!=vol) { // copy data of slices in volume size_t offset = ((size_t) s)*size; std::memcpy(static_cast(vol->GetData())+offset, sl->GetData(), size); mitkIpPicDescriptor * pic = sl->GetPicDescriptor(); // replace old slice with reference to volume sl=new ImageDataItem(*vol, 2, data, importMemoryManagement == ManageMemory, ((size_t) s)*size); sl->SetComplete(true); mitkIpFuncCopyTags(sl->GetPicDescriptor(), pic); m_Slices[posSl]=sl; } } if(vol->GetPicDescriptor()->info->tags_head==NULL) mitkIpFuncCopyTags(vol->GetPicDescriptor(), m_Slices[GetSliceIndex(0,t,n)]->GetPicDescriptor()); } return m_Volumes[pos]=vol; } // volume is unavailable. Can we calculate it? if((GetSource()!=NULL) && (GetSource()->Updating()==false)) { // ... wir muessen rechnen!!! .... m_RequestedRegion.SetIndex(0, 0); m_RequestedRegion.SetIndex(1, 0); m_RequestedRegion.SetIndex(2, 0); m_RequestedRegion.SetIndex(3, t); m_RequestedRegion.SetIndex(4, n); m_RequestedRegion.SetSize(0, m_Dimensions[0]); m_RequestedRegion.SetSize(1, m_Dimensions[1]); m_RequestedRegion.SetSize(2, m_Dimensions[2]); m_RequestedRegion.SetSize(3, 1); m_RequestedRegion.SetSize(4, 1); m_RequestedRegionInitialized=true; GetSource()->Update(); if(IsVolumeSet(t,n)) //yes: now we can call ourselves without the risk of a endless loop (see "if" above) return GetVolumeData(t,n,data,importMemoryManagement); else return NULL; } else { ImageDataItemPointer item = AllocateVolumeData(t,n,data,importMemoryManagement); item->SetComplete(true); return item; } } mitk::Image::ImageDataItemPointer mitk::Image::GetChannelData(int n, void *data, ImportMemoryManagementType importMemoryManagement) { if(IsValidChannel(n)==false) return NULL; ImageDataItemPointer ch, vol; ch=m_Channels[n]; if((ch.GetPointer()!=NULL) && (ch->IsComplete())) return ch; // let's see if all volumes are set, so that we can (could) combine them to a channel if(IsChannelSet(n)) { // if there is only one time frame we do not need to combine anything if(m_Dimensions[3]<=1) { vol=GetVolumeData(0,n,data,importMemoryManagement); ch=new ImageDataItem(*vol, 3, data, importMemoryManagement == ManageMemory); ch->SetComplete(true); } else { ch=m_Channels[n]; // ok, let's combine the volumes! if(ch.GetPointer()==NULL) ch=new ImageDataItem(m_PixelType, m_Dimension, m_Dimensions, NULL, true); ch->SetComplete(true); size_t size=m_OffsetTable[m_Dimension-1]*(m_PixelType.GetBpe()/8); unsigned int t; ImageDataItemPointerArray::iterator slicesIt = m_Slices.begin()+n*m_Dimensions[2]*m_Dimensions[3]; for(t=0;tGetParent()!=ch) { // copy data of volume in channel size_t offset = ((size_t) t)*m_OffsetTable[3]*(m_PixelType.GetBpe()/8); std::memcpy(static_cast(ch->GetData())+offset, vol->GetData(), size); mitkIpPicDescriptor * pic = vol->GetPicDescriptor(); // replace old volume with reference to channel vol=new ImageDataItem(*ch, 3, data, importMemoryManagement == ManageMemory, offset); vol->SetComplete(true); mitkIpFuncCopyTags(vol->GetPicDescriptor(), pic); m_Volumes[posVol]=vol; // get rid of slices - they may point to old volume ImageDataItemPointer dnull=NULL; for(unsigned int i = 0; i < m_Dimensions[2]; ++i, ++slicesIt) { assert(slicesIt != m_Slices.end()); *slicesIt = dnull; } } } if(ch->GetPicDescriptor()->info->tags_head==NULL) mitkIpFuncCopyTags(ch->GetPicDescriptor(), m_Volumes[GetVolumeIndex(0,n)]->GetPicDescriptor()); } return m_Channels[n]=ch; } // channel is unavailable. Can we calculate it? if((GetSource()!=NULL) && (GetSource()->Updating()==false)) { // ... wir muessen rechnen!!! .... m_RequestedRegion.SetIndex(0, 0); m_RequestedRegion.SetIndex(1, 0); m_RequestedRegion.SetIndex(2, 0); m_RequestedRegion.SetIndex(3, 0); m_RequestedRegion.SetIndex(4, n); m_RequestedRegion.SetSize(0, m_Dimensions[0]); m_RequestedRegion.SetSize(1, m_Dimensions[1]); m_RequestedRegion.SetSize(2, m_Dimensions[2]); m_RequestedRegion.SetSize(3, m_Dimensions[3]); m_RequestedRegion.SetSize(4, 1); m_RequestedRegionInitialized=true; GetSource()->Update(); // did it work? if(IsChannelSet(n)) //yes: now we can call ourselves without the risk of a endless loop (see "if" above) return GetChannelData(n,data,importMemoryManagement); else return NULL; } else { ImageDataItemPointer item = AllocateChannelData(n,data,importMemoryManagement); item->SetComplete(true); return item; } } bool mitk::Image::IsSliceSet(int s, int t, int n) const { if(IsValidSlice(s,t,n)==false) return false; if(m_Slices[GetSliceIndex(s,t,n)].GetPointer()!=NULL) return true; ImageDataItemPointer ch, vol; vol=m_Volumes[GetVolumeIndex(t,n)]; if((vol.GetPointer()!=NULL) && (vol->IsComplete())) return true; ch=m_Channels[n]; if((ch.GetPointer()!=NULL) && (ch->IsComplete())) return true; return false; } bool mitk::Image::IsVolumeSet(int t, int n) const { if(IsValidVolume(t,n)==false) return false; ImageDataItemPointer ch, vol; // volume directly available? vol=m_Volumes[GetVolumeIndex(t,n)]; if((vol.GetPointer()!=NULL) && (vol->IsComplete())) return true; // is volume available as part of a channel that is available? ch=m_Channels[n]; if((ch.GetPointer()!=NULL) && (ch->IsComplete())) return true; // let's see if all slices of the volume are set, so that we can (could) combine them to a volume unsigned int s; for(s=0;sIsComplete())) return true; // let's see if all volumes are set, so that we can (could) combine them to a channel unsigned int t; for(t=0;t(data), s, t, n, CopyMemory); } bool mitk::Image::SetVolume(const void *data, int t, int n) { // const_cast is no risk for ImportMemoryManagementType == CopyMemory return SetImportVolume(const_cast(data), t, n, CopyMemory); } bool mitk::Image::SetChannel(const void *data, int n) { // const_cast is no risk for ImportMemoryManagementType == CopyMemory return SetImportChannel(const_cast(data), n, CopyMemory); } bool mitk::Image::SetImportSlice(void *data, int s, int t, int n, ImportMemoryManagementType importMemoryManagement) { if(IsValidSlice(s,t,n)==false) return false; ImageDataItemPointer sl; if(IsSliceSet(s,t,n)) { sl=GetSliceData(s,t,n,data,importMemoryManagement); if(sl->GetManageMemory()==false) { sl=AllocateSliceData(s,t,n,data,importMemoryManagement); if(sl.GetPointer()==NULL) return false; } if ( sl->GetData() != data ) std::memcpy(sl->GetData(), data, m_OffsetTable[2]*(m_PixelType.GetBpe()/8)); sl->Modified(); //we have changed the data: call Modified()! Modified(); } else { sl=AllocateSliceData(s,t,n,data,importMemoryManagement); if(sl.GetPointer()==NULL) return false; if ( sl->GetData() != data ) std::memcpy(sl->GetData(), data, m_OffsetTable[2]*(m_PixelType.GetBpe()/8)); //we just added a missing slice, which is not regarded as modification. //Therefore, we do not call Modified()! } return true; } bool mitk::Image::SetImportVolume(void *data, int t, int n, ImportMemoryManagementType importMemoryManagement) { if(IsValidVolume(t,n)==false) return false; ImageDataItemPointer vol; if(IsVolumeSet(t,n)) { vol=GetVolumeData(t,n,data,importMemoryManagement); if(vol->GetManageMemory()==false) { vol=AllocateVolumeData(t,n,data,importMemoryManagement); if(vol.GetPointer()==NULL) return false; } if ( vol->GetData() != data ) std::memcpy(vol->GetData(), data, m_OffsetTable[3]*(m_PixelType.GetBpe()/8)); vol->Modified(); vol->SetComplete(true); //we have changed the data: call Modified()! Modified(); } else { vol=AllocateVolumeData(t,n,data,importMemoryManagement); if(vol.GetPointer()==NULL) return false; if ( vol->GetData() != data ) { std::memcpy(vol->GetData(), data, m_OffsetTable[3]*(m_PixelType.GetBpe()/8)); } vol->SetComplete(true); //we just added a missing Volume, which is not regarded as modification. //Therefore, we do not call Modified()! } return true; } bool mitk::Image::SetImportChannel(void *data, int n, ImportMemoryManagementType importMemoryManagement) { if(IsValidChannel(n)==false) return false; ImageDataItemPointer ch; if(IsChannelSet(n)) { ch=GetChannelData(n,data,importMemoryManagement); if(ch->GetManageMemory()==false) { ch=AllocateChannelData(n,data,importMemoryManagement); if(ch.GetPointer()==NULL) return false; } if ( ch->GetData() != data ) std::memcpy(ch->GetData(), data, m_OffsetTable[4]*(m_PixelType.GetBpe()/8)); ch->Modified(); ch->SetComplete(true); //we have changed the data: call Modified()! Modified(); } else { ch=AllocateChannelData(n,data,importMemoryManagement); if(ch.GetPointer()==NULL) return false; if ( ch->GetData() != data ) std::memcpy(ch->GetData(), data, m_OffsetTable[4]*(m_PixelType.GetBpe()/8)); ch->SetComplete(true); //we just added a missing Channel, which is not regarded as modification. //Therefore, we do not call Modified()! } return true; } bool mitk::Image::SetPicSlice(const mitkIpPicDescriptor *pic, int s, int t, int n, ImportMemoryManagementType /*importMemoryManagement*/) { if(pic==NULL) return false; if(pic->dim!=2) return false; if((pic->n[0]!=m_Dimensions[0]) || (pic->n[1]!=m_Dimensions[1])) return false; if(SetSlice(pic->data,s,t,n)) //@todo: add geometry! { ImageDataItemPointer sl; sl=GetSliceData(s,t,n,NULL,CopyMemory); mitkIpFuncCopyTags(sl->GetPicDescriptor(), const_cast(pic)); return true; } else return false; } bool mitk::Image::SetPicVolume(const mitkIpPicDescriptor *pic, int t, int n, ImportMemoryManagementType /*importMemoryManagement*/) { if(pic==NULL) return false; if((pic->dim==2) && ((m_Dimension==2) || ((m_Dimension>2) && (m_Dimensions[2]==1)))) return SetPicSlice(pic, 0, t, n); if(pic->dim!=3) return false; if((pic->n[0]!=m_Dimensions[0]) || (pic->n[1]!=m_Dimensions[1]) || (pic->n[2]!=m_Dimensions[2])) return false; if(SetVolume(pic->data,t,n)) //@todo: add geometry! { ImageDataItemPointer vol; vol=GetVolumeData(t,n,NULL,CopyMemory); mitkIpFuncCopyTags(vol->GetPicDescriptor(), const_cast(pic)); return true; } else return false; } bool mitk::Image::SetPicChannel(const mitkIpPicDescriptor *pic, int n, ImportMemoryManagementType /*importMemoryManagement*/) { if(pic==NULL) return false; if(pic->dim<=3) return SetPicVolume(pic, 0, n); if(pic->dim!=m_Dimension) return false; unsigned int i; for(i=0;in[i]!=m_Dimensions[i]) return false; } if(SetChannel(pic->data,n)) //@todo: add geometry! { ImageDataItemPointer ch; ch=GetChannelData(n,NULL,CopyMemory); // commented the next line, because // it crashes when called from mitkDICOMFileReader for the Live3D data // mitkIpFuncCopyTags(ch->GetPicDescriptor(), pic); return true; } else return false; } void mitk::Image::Initialize() { ImageDataItemPointerArray::iterator it, end; for( it=m_Slices.begin(), end=m_Slices.end(); it!=end; ++it ) { (*it)=NULL; } for( it=m_Volumes.begin(), end=m_Volumes.end(); it!=end; ++it ) { (*it)=NULL; } for( it=m_Channels.begin(), end=m_Channels.end(); it!=end; ++it ) { (*it)=NULL; } m_CompleteData = NULL; this->GetTimeSelector(); // just to create m_TimeSelectorForExtremaObject SetRequestedRegionToLargestPossibleRegion(); } mitk::ImageTimeSelector* mitk::Image::GetTimeSelector() const { if(m_TimeSelectorForExtremaObject.IsNull()) { m_TimeSelectorForExtremaObject = ImageTimeSelector::New(); ImageTimeSelector* timeSelector = static_cast( m_TimeSelectorForExtremaObject.GetPointer() ); timeSelector->SetInput(this); this->UnRegister(); } return static_cast( m_TimeSelectorForExtremaObject.GetPointer() ); } void mitk::Image::Initialize(const mitk::PixelType& type, unsigned int dimension, unsigned int *dimensions, unsigned int channels) { Clear(); m_Dimension=dimension; if(!dimensions) itkExceptionMacro(<< "invalid zero dimension image"); unsigned int i; for(i=0;i4?m_Dimension:4]; std::memcpy(m_Dimensions, dimensions, sizeof(unsigned int)*m_Dimension); if(m_Dimension<4) { unsigned int *p; for(i=0,p=m_Dimensions+m_Dimension;i<4-m_Dimension;++i, ++p) *p=1; } for(i=0;i<4;++i) { m_LargestPossibleRegion.SetIndex(i, 0); m_LargestPossibleRegion.SetSize (i, m_Dimensions[i]); } m_LargestPossibleRegion.SetIndex(i, 0); m_LargestPossibleRegion.SetSize(i, channels); if(m_LargestPossibleRegion.GetNumberOfPixels()==0) { delete [] m_Dimensions; m_Dimensions = NULL; return; } m_PixelType=type; PlaneGeometry::Pointer planegeometry = PlaneGeometry::New(); planegeometry->InitializeStandardPlane(m_Dimensions[0], m_Dimensions[1]); SlicedGeometry3D::Pointer slicedGeometry = SlicedGeometry3D::New(); slicedGeometry->InitializeEvenlySpaced(planegeometry, m_Dimensions[2]); if(dimension>=4) { TimeBounds timebounds; timebounds[0] = 0.0; timebounds[1] = 1.0; slicedGeometry->SetTimeBounds(timebounds); } TimeSlicedGeometry::Pointer timeSliceGeometry = TimeSlicedGeometry::New(); timeSliceGeometry->InitializeEvenlyTimed(slicedGeometry, m_Dimensions[3]); timeSliceGeometry->ImageGeometryOn(); SetGeometry(timeSliceGeometry); ImageDataItemPointer dnull=NULL; m_Channels.assign(GetNumberOfChannels(), dnull); m_Volumes.assign(GetNumberOfChannels()*m_Dimensions[3], dnull); m_Slices.assign(GetNumberOfChannels()*m_Dimensions[3]*m_Dimensions[2], dnull); ComputeOffsetTable(); Initialize(); m_Initialized = true; } void mitk::Image::Initialize(const mitk::PixelType& type, const mitk::Geometry3D& geometry, unsigned int channels, int tDim ) { unsigned int dimensions[5]; dimensions[0] = (unsigned int)(geometry.GetExtent(0)+0.5); dimensions[1] = (unsigned int)(geometry.GetExtent(1)+0.5); dimensions[2] = (unsigned int)(geometry.GetExtent(2)+0.5); dimensions[3] = 0; dimensions[4] = 0; unsigned int dimension = 2; if ( dimensions[2] > 1 ) dimension = 3; if ( tDim > 0) { dimensions[3] = tDim; } else { const mitk::TimeSlicedGeometry* timeGeometry = dynamic_cast(&geometry); if ( timeGeometry != NULL ) { dimensions[3] = timeGeometry->GetTimeSteps(); } } if ( dimensions[3] > 1 ) dimension = 4; Initialize( type, dimension, dimensions, channels ); SetGeometry(static_cast(geometry.Clone().GetPointer())); mitk::BoundingBox::BoundsArrayType bounds = geometry.GetBoundingBox()->GetBounds(); if( (bounds[0] != 0.0) || (bounds[2] != 0.0) || (bounds[4] != 0.0) ) { SlicedGeometry3D* slicedGeometry = GetSlicedGeometry(0); mitk::Point3D origin; origin.Fill(0.0); slicedGeometry->IndexToWorld(origin, origin); bounds[1]-=bounds[0]; bounds[3]-=bounds[2]; bounds[5]-=bounds[4]; bounds[0] = 0.0; bounds[2] = 0.0; bounds[4] = 0.0; slicedGeometry->SetBounds(bounds); slicedGeometry->GetIndexToWorldTransform()->SetOffset(origin.Get_vnl_vector().data_block()); GetTimeSlicedGeometry()->InitializeEvenlyTimed(slicedGeometry, m_Dimensions[3]); } } void mitk::Image::Initialize(const mitk::PixelType& type, int sDim, const mitk::Geometry2D& geometry2d, bool flipped, unsigned int channels, int tDim ) { SlicedGeometry3D::Pointer slicedGeometry = SlicedGeometry3D::New(); slicedGeometry->InitializeEvenlySpaced(static_cast(geometry2d.Clone().GetPointer()), sDim, flipped); Initialize(type, *slicedGeometry, channels, tDim); } void mitk::Image::Initialize(const mitk::Image* image) { Initialize(*image->GetPixelType().GetTypeId(), *image->GetTimeSlicedGeometry()); } void mitk::Image::Initialize(vtkImageData* vtkimagedata, int channels, int tDim, int sDim) { if(vtkimagedata==NULL) return; m_Dimension=vtkimagedata->GetDataDimension(); unsigned int i, *tmpDimensions=new unsigned int[m_Dimension>4?m_Dimension:4]; for(i=0;iGetDimensions()[i]; if(m_Dimension<4) { unsigned int *p; for(i=0,p=tmpDimensions+m_Dimension;i<4-m_Dimension;++i, ++p) *p=1; } if(sDim>=0) { tmpDimensions[2]=sDim; if(m_Dimension < 3) m_Dimension = 3; } if(tDim>=0) { tmpDimensions[3]=tDim; if(m_Dimension < 4) m_Dimension = 4; } mitk::PixelType pixelType; switch ( vtkimagedata->GetScalarType() ) { case VTK_BIT: case VTK_CHAR: pixelType.Initialize(typeid(char), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_UNSIGNED_CHAR: pixelType.Initialize(typeid(unsigned char), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_SHORT: pixelType.Initialize(typeid(short), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_UNSIGNED_SHORT: pixelType.Initialize(typeid(unsigned short), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_INT: pixelType.Initialize(typeid(int), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_UNSIGNED_INT: pixelType.Initialize(typeid(unsigned int), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_LONG: pixelType.Initialize(typeid(long), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_UNSIGNED_LONG: pixelType.Initialize(typeid(unsigned long), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_FLOAT: pixelType.Initialize(typeid(float), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_DOUBLE: pixelType.Initialize(typeid(double), vtkimagedata->GetNumberOfScalarComponents()); break; default: break; } Initialize(pixelType, m_Dimension, tmpDimensions, channels); const double *spacinglist = vtkimagedata->GetSpacing(); Vector3D spacing; FillVector3D(spacing, spacinglist[0], 1.0, 1.0); if(m_Dimension>=2) spacing[1]=spacinglist[1]; if(m_Dimension>=3) spacing[2]=spacinglist[2]; // access origin of vtkImage Point3D origin; vtkFloatingPointType vtkorigin[3]; vtkimagedata->GetOrigin(vtkorigin); FillVector3D(origin, vtkorigin[0], 0.0, 0.0); if(m_Dimension>=2) origin[1]=vtkorigin[1]; if(m_Dimension>=3) origin[2]=vtkorigin[2]; SlicedGeometry3D* slicedGeometry = GetSlicedGeometry(0); // re-initialize PlaneGeometry with origin and direction PlaneGeometry* planeGeometry = static_cast(slicedGeometry->GetGeometry2D(0)); planeGeometry->SetOrigin(origin); // re-initialize SlicedGeometry3D slicedGeometry->SetOrigin(origin); slicedGeometry->SetSpacing(spacing); GetTimeSlicedGeometry()->InitializeEvenlyTimed(slicedGeometry, m_Dimensions[3]); delete [] tmpDimensions; } void mitk::Image::Initialize(const mitkIpPicDescriptor* pic, int channels, int tDim, int sDim) { if(pic==NULL) return; Clear(); m_Dimension=pic->dim; m_Dimensions=new unsigned int[m_Dimension>4?m_Dimension:4]; std::memcpy(m_Dimensions, pic->n, sizeof(unsigned int)*m_Dimension); if(m_Dimension<4) { unsigned int i, *p; for(i=0,p=m_Dimensions+m_Dimension;i<4-m_Dimension;++i, ++p) *p=1; } if(sDim>=0) { m_Dimensions[2]=sDim; if(m_Dimension < 3) m_Dimension = 3; } if(tDim>=0) { m_Dimensions[3]=tDim; if(m_Dimension < 4) m_Dimension = 4; } unsigned int i; for(i=0;i<4;++i) { m_LargestPossibleRegion.SetIndex(i, 0); m_LargestPossibleRegion.SetSize (i, m_Dimensions[i]); } m_LargestPossibleRegion.SetIndex(i, 0); m_LargestPossibleRegion.SetSize(i, channels); m_PixelType=PixelType(pic); SlicedGeometry3D::Pointer slicedGeometry = SlicedGeometry3D::New(); PicHelper::InitializeEvenlySpaced(pic, m_Dimensions[2], slicedGeometry); TimeSlicedGeometry::Pointer timeSliceGeometry = TimeSlicedGeometry::New(); timeSliceGeometry->InitializeEvenlyTimed(slicedGeometry, m_Dimensions[3]); timeSliceGeometry->ImageGeometryOn(); SetGeometry(timeSliceGeometry); ImageDataItemPointer dnull=NULL; m_Channels.assign(GetNumberOfChannels(), dnull); m_Volumes.assign(GetNumberOfChannels()*m_Dimensions[3], dnull); m_Slices.assign(GetNumberOfChannels()*m_Dimensions[3]*m_Dimensions[2], dnull); ComputeOffsetTable(); Initialize(); m_Initialized = true; } bool mitk::Image::IsValidSlice(int s, int t, int n) const { if(m_Initialized) return ((s>=0) && (s<(int)m_Dimensions[2]) && (t>=0) && (t< (int) m_Dimensions[3]) && (n>=0) && (n< (int)GetNumberOfChannels())); else return false; } bool mitk::Image::IsValidVolume(int t, int n) const { if(m_Initialized) return IsValidSlice(0, t, n); else return false; } bool mitk::Image::IsValidChannel(int n) const { if(m_Initialized) return IsValidSlice(0, 0, n); else return false; } void mitk::Image::ComputeOffsetTable() { if(m_OffsetTable!=NULL) delete [] m_OffsetTable; m_OffsetTable=new size_t[m_Dimension>4 ? m_Dimension+1 : 4+1]; unsigned int i; size_t num=1; m_OffsetTable[0] = 1; for (i=0; i < m_Dimension; ++i) { num *= m_Dimensions[i]; m_OffsetTable[i+1] = num; } for (;i < 4; ++i) m_OffsetTable[i+1] = num; } int mitk::Image::GetSliceIndex(int s, int t, int n) const { if(IsValidSlice(s,t,n)==false) return false; return ((size_t)s)+((size_t) t)*m_Dimensions[2]+((size_t) n)*m_Dimensions[3]*m_Dimensions[2]; //?? } int mitk::Image::GetVolumeIndex(int t, int n) const { if(IsValidVolume(t,n)==false) return false; return ((size_t)t)+((size_t) n)*m_Dimensions[3]; //?? } mitk::Image::ImageDataItemPointer mitk::Image::AllocateSliceData(int s, int t, int n, void *data, ImportMemoryManagementType importMemoryManagement) { int pos; pos=GetSliceIndex(s,t,n); // is slice available as part of a volume that is available? ImageDataItemPointer sl, ch, vol; vol=m_Volumes[GetVolumeIndex(t,n)]; if(vol.GetPointer()!=NULL) { sl=new ImageDataItem(*vol, 2, data, importMemoryManagement == ManageMemory, ((size_t) s)*m_OffsetTable[2]*(m_PixelType.GetBpe()/8)); sl->SetComplete(true); return m_Slices[pos]=sl; } // is slice available as part of a channel that is available? ch=m_Channels[n]; if(ch.GetPointer()!=NULL) { sl=new ImageDataItem(*ch, 2, data, importMemoryManagement == ManageMemory, (((size_t) s)*m_OffsetTable[2]+((size_t) t)*m_OffsetTable[3])*(m_PixelType.GetBpe()/8)); sl->SetComplete(true); return m_Slices[pos]=sl; } // allocate new volume (instead of a single slice to keep data together!) m_Volumes[GetVolumeIndex(t,n)]=vol=AllocateVolumeData(t,n,NULL,importMemoryManagement); sl=new ImageDataItem(*vol, 2, data, importMemoryManagement == ManageMemory, ((size_t) s)*m_OffsetTable[2]*(m_PixelType.GetBpe()/8)); sl->SetComplete(true); return m_Slices[pos]=sl; ////ALTERNATIVE: //// allocate new slice //sl=new ImageDataItem(m_PixelType, 2, m_Dimensions); //m_Slices[pos]=sl; //return vol; } mitk::Image::ImageDataItemPointer mitk::Image::AllocateVolumeData(int t, int n, void *data, ImportMemoryManagementType importMemoryManagement) { int pos; pos=GetVolumeIndex(t,n); // is volume available as part of a channel that is available? ImageDataItemPointer ch, vol; ch=m_Channels[n]; if(ch.GetPointer()!=NULL) { vol=new ImageDataItem(*ch, 3, data, importMemoryManagement == ManageMemory, (((size_t) t)*m_OffsetTable[3])*(m_PixelType.GetBpe()/8)); return m_Volumes[pos]=vol; } // allocate new volume if(importMemoryManagement == CopyMemory) { vol=new ImageDataItem(m_PixelType, 3, m_Dimensions, NULL, true); if(data != NULL) std::memcpy(vol->GetData(), data, m_OffsetTable[3]*(m_PixelType.GetBpe()/8)); } else { vol=new ImageDataItem(m_PixelType, 3, m_Dimensions, data, importMemoryManagement == ManageMemory); } m_Volumes[pos]=vol; return vol; } mitk::Image::ImageDataItemPointer mitk::Image::AllocateChannelData(int n, void *data, ImportMemoryManagementType importMemoryManagement) { ImageDataItemPointer ch; // allocate new channel if(importMemoryManagement == CopyMemory) { ch=new ImageDataItem(m_PixelType, m_Dimension, m_Dimensions, NULL, true); if(data != NULL) std::memcpy(ch->GetData(), data, m_OffsetTable[4]*(m_PixelType.GetBpe()/8)); } else { ch=new ImageDataItem(m_PixelType, m_Dimension, m_Dimensions, data, importMemoryManagement == ManageMemory); } m_Channels[n]=ch; return ch; } unsigned int* mitk::Image::GetDimensions() const { return m_Dimensions; } void mitk::Image::Clear() { Superclass::Clear(); delete [] m_Dimensions; m_Dimensions = NULL; } void mitk::Image::SetGeometry(Geometry3D* aGeometry3D) { // Please be aware of the 0.5 offset/pixel-center issue! See Geometry documentation for further information if(aGeometry3D->GetImageGeometry()==false) { MITK_INFO << "WARNING: Applied a non-image geometry onto an image. Please be SURE that this geometry is pixel-center-based! If it is not, you need to call Geometry3D->ChangeImageGeometryConsideringOriginOffset(true) before calling image->setGeometry(..)\n"; } Superclass::SetGeometry(aGeometry3D); GetTimeSlicedGeometry()->ImageGeometryOn(); } const mitk::Image::HistogramType* mitk::Image::GetScalarHistogram(int t) const { mitk::ImageTimeSelector* timeSelector = this->GetTimeSelector(); if(timeSelector!=NULL) { timeSelector->SetTimeNr(t); timeSelector->UpdateLargestPossibleRegion(); mitk::HistogramGenerator* generator = static_cast(m_HistogramGeneratorObject.GetPointer()); generator->SetImage(timeSelector->GetOutput()); generator->ComputeHistogram(); return static_cast(generator->GetHistogram()); } return NULL; } #include "mitkImageAccessByItk.h" //#define BOUNDINGOBJECT_IGNORE template < typename ItkImageType > void mitk::_ComputeExtremaInItkImage(ItkImageType* itkImage, mitk::Image* mitkImage, int t) { typename ItkImageType::RegionType region; region = itkImage->GetBufferedRegion(); if(region.Crop(itkImage->GetRequestedRegion()) == false) return; if(region != itkImage->GetRequestedRegion()) return; itk::ImageRegionConstIterator it(itkImage, region); typedef typename ItkImageType::PixelType TPixel; TPixel value = 0; if ( !mitkImage || !mitkImage->IsValidTimeStep( t ) ) return; mitkImage->Expand(t+1); // make sure we have initialized all arrays mitkImage->m_CountOfMinValuedVoxels[t] = 0; mitkImage->m_CountOfMaxValuedVoxels[t] = 0; mitkImage->m_Scalar2ndMin[t]= mitkImage->m_ScalarMin[t] = itk::NumericTraits::max(); mitkImage->m_Scalar2ndMax[t]= mitkImage->m_ScalarMax[t] = itk::NumericTraits::NonpositiveMin(); while( !it.IsAtEnd() ) { value = it.Get(); // if ( (value > mitkImage->m_ScalarMin) && (value < mitkImage->m_Scalar2ndMin) ) mitkImage->m_Scalar2ndMin = value; // else if ( (value < mitkImage->m_ScalarMax) && (value > mitkImage->m_Scalar2ndMax) ) mitkImage->m_Scalar2ndMax = value; // else if (value > mitkImage->m_ScalarMax) mitkImage->m_ScalarMax = value; // else if (value < mitkImage->m_ScalarMin) mitkImage->m_ScalarMin = value; // if numbers start with 2ndMin or 2ndMax and never have that value again, the previous above logic failed #ifdef BOUNDINGOBJECT_IGNORE if( value > -32765) { #endif // update min if ( value < mitkImage->m_ScalarMin[t] ) { mitkImage->m_Scalar2ndMin[t] = mitkImage->m_ScalarMin[t]; mitkImage->m_ScalarMin[t] = value; mitkImage->m_CountOfMinValuedVoxels[t] = 1; } else if ( value == mitkImage->m_ScalarMin[t] ) { ++mitkImage->m_CountOfMinValuedVoxels[t]; } else if ( value < mitkImage->m_Scalar2ndMin[t] ) { mitkImage->m_Scalar2ndMin[t] = value; } // update max if ( value > mitkImage->m_ScalarMax[t] ) { mitkImage->m_Scalar2ndMax[t] = mitkImage->m_ScalarMax[t]; mitkImage->m_ScalarMax[t] = value; mitkImage->m_CountOfMaxValuedVoxels[t] = 1; } else if ( value == mitkImage->m_ScalarMax[t] ) { ++mitkImage->m_CountOfMaxValuedVoxels[t]; } else if ( value > mitkImage->m_Scalar2ndMax[t] ) { mitkImage->m_Scalar2ndMax[t] = value; } #ifdef BOUNDINGOBJECT_IGNORE } #endif ++it; } //// guard for wrong 2dMin/Max on single constant value images if (mitkImage->m_ScalarMax[t] == mitkImage->m_ScalarMin[t]) { mitkImage->m_Scalar2ndMax[t] = mitkImage->m_Scalar2ndMin[t] = mitkImage->m_ScalarMax[t]; } mitkImage->m_LastRecomputeTimeStamp.Modified(); //MITK_DEBUG <<"extrema "<::NonpositiveMin()<<" "<m_ScalarMin<<" "<m_Scalar2ndMin<<" "<m_Scalar2ndMax<<" "<m_ScalarMax<<" "<::max(); } bool mitk::Image::IsValidTimeStep(int t) const { return ( ( m_Dimension >= 4 && t <= (int)m_Dimensions[3] && t > 0 ) || (t == 0) ); } void mitk::Image::Expand( unsigned int timeSteps ) { if(timeSteps < 1) itkExceptionMacro(<< "Invalid timestep in Image!"); if(! IsValidTimeStep( timeSteps-1 ) ) return; Superclass::Expand(timeSteps); if(timeSteps > m_ScalarMin.size() ) { m_ScalarMin.resize(timeSteps, itk::NumericTraits::max()); m_ScalarMax.resize(timeSteps, itk::NumericTraits::NonpositiveMin()); m_Scalar2ndMin.resize(timeSteps, itk::NumericTraits::max()); m_Scalar2ndMax.resize(timeSteps, itk::NumericTraits::NonpositiveMin()); m_CountOfMinValuedVoxels.resize(timeSteps, 0); m_CountOfMaxValuedVoxels.resize(timeSteps, 0); } } void mitk::Image::ResetImageStatistics() const { m_ScalarMin.assign(1, itk::NumericTraits::max()); m_ScalarMax.assign(1, itk::NumericTraits::NonpositiveMin()); m_Scalar2ndMin.assign(1, itk::NumericTraits::max()); m_Scalar2ndMax.assign(1, itk::NumericTraits::NonpositiveMin()); m_CountOfMinValuedVoxels.assign(1, 0); m_CountOfMaxValuedVoxels.assign(1, 0); } void mitk::Image::ComputeImageStatistics(int t) const { // timestep valid? if (!IsValidTimeStep(t)) return; // image modified? if (this->GetMTime() > m_LastRecomputeTimeStamp.GetMTime()) this->ResetImageStatistics(); // adapt vector length // the const_cast is necessary since the whole statistics are provided // with const-methods but are actually stored inside the object with mutable // members. This should be resolved in a redesign of the image class. const_cast(this)->Expand(t+1); // do we have valid information already? if( m_ScalarMin[t] != itk::NumericTraits::max() || m_Scalar2ndMin[t] != itk::NumericTraits::max() ) return; // Values already calculated before... if(this->m_PixelType.GetNumberOfComponents() == 1) { // recompute mitk::ImageTimeSelector* timeSelector = this->GetTimeSelector(); if(timeSelector!=NULL) { timeSelector->SetTimeNr(t); timeSelector->UpdateLargestPossibleRegion(); mitk::Image* image = timeSelector->GetOutput(); mitk::Image* thisImage = const_cast(this); AccessByItk_2( image, _ComputeExtremaInItkImage, thisImage, t ); } } else if(this->m_PixelType.GetNumberOfComponents() > 1) { m_ScalarMin[t] = 0; m_ScalarMax[t] = 255; } } mitk::ScalarType mitk::Image::GetScalarValueMin(int t) const { ComputeImageStatistics(t); return m_ScalarMin[t]; } mitk::ScalarType mitk::Image::GetScalarValueMax(int t) const { ComputeImageStatistics(t); return m_ScalarMax[t]; } mitk::ScalarType mitk::Image::GetScalarValue2ndMin(int t) const { ComputeImageStatistics(t); return m_Scalar2ndMin[t]; } mitk::ScalarType mitk::Image::GetScalarValue2ndMax(int t) const { ComputeImageStatistics(t); return m_Scalar2ndMax[t]; } mitk::ScalarType mitk::Image::GetCountOfMinValuedVoxels(int t) const { ComputeImageStatistics(t); return m_CountOfMinValuedVoxels[t]; } mitk::ScalarType mitk::Image::GetCountOfMaxValuedVoxels(int t) const { ComputeImageStatistics(t); return m_CountOfMaxValuedVoxels[t]; } void mitk::Image::PrintSelf(std::ostream& os, itk::Indent indent) const { unsigned char i; if(m_Initialized) { os << indent << " PixelType: " << m_PixelType.GetTypeId()->name() << std::endl; os << indent << " BitsPerElement: " << m_PixelType.GetBpe() << std::endl; os << indent << " NumberOfComponents: " << m_PixelType.GetNumberOfComponents() << std::endl; os << indent << " BitsPerComponent: " << m_PixelType.GetBitsPerComponent() << std::endl; os << indent << " Dimension: " << m_Dimension << std::endl; os << indent << " Dimensions: "; for(i=0; i < m_Dimension; ++i) os << GetDimension(i) << " "; os << std::endl; } else { os << indent << " Image not initialized: m_Initialized: false" << std::endl; } Superclass::PrintSelf(os,indent); } bool mitk::Image::IsRotated() const { const mitk::Geometry3D* geo = this->GetGeometry(); bool ret = false; if(geo) { const vnl_matrix_fixed & mx = geo->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix(); float ref = 0; for(short k = 0; k < 3; ++k) ref += mx[k][k]; ref/=1000; // Arbitrary value; if a non-diagonal (nd) element is bigger then this, matrix is considered nd. for(short i = 0; i < 3; ++i) { for(short j = 0; j < 3; ++j) { if(i != j) { if(abs(mx[i][j]) > ref) // matrix is nd ret = true; } } } } return ret; } diff --git a/Core/Code/DataManagement/mitkImage.h b/Core/Code/DataManagement/mitkImage.h index 3c2dc23d4d..2889acfde0 100644 --- a/Core/Code/DataManagement/mitkImage.h +++ b/Core/Code/DataManagement/mitkImage.h @@ -1,658 +1,663 @@ /*========================================================================= 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 MITKIMAGE_H_HEADER_INCLUDED_C1C2FCD2 #define MITKIMAGE_H_HEADER_INCLUDED_C1C2FCD2 #include "mitkCommon.h" #include "mitkSlicedData.h" #include "mitkPixelType.h" #include "mitkBaseData.h" #include "mitkLevelWindow.h" #include "mitkPlaneGeometry.h" +#include "mitkImageDataItem.h" #ifndef __itkHistogram_h #include #endif class vtkImageData; namespace mitk { class SubImageSelector; -class ImageDataItem; +//class ImageDataItem; class ImageTimeSelector; //##Documentation //## @brief Image class for storing images //## //## Can be asked for header information, the data vector, //## the mitkIpPicDescriptor struct or vtkImageData objects. If not the complete //## data is required, the appropriate SubImageSelector class should be used //## for access. //## Image organizes sets of slices (s x 2D), volumes (t x 3D) and channels (n //## x ND). Channels are for different kind of data, e.g., morphology in //## channel 0, velocities in channel 1. All channels must have the same Geometry! In //## particular, the dimensions of all channels are the same, only the pixel-type //## may differ between channels. //## //## For importing ITK images use of mitk::ITKImageImport is recommended, see //## \ref Adaptor. //## //## For ITK v3.8 and older: Converting coordinates from the ITK physical //## coordinate system (which does not support rotated images) to the MITK world //## coordinate system should be performed via the Geometry3D of the Image, see //## Geometry3D::WorldToItkPhysicalPoint. //## @ingroup Data class MITK_CORE_EXPORT Image : public SlicedData { friend class SubImageSelector; public: mitkClassMacro(Image, SlicedData); itkNewMacro(Self); + mitkCloneMacro(Image); + /** Smart Pointer type to a ImageDataItem. */ typedef itk::SmartPointerForwardReference ImageDataItemPointer; //## @param ImportMemoryManagementType This parameter is evaluated when setting new data to an image. //## The different options are: //## CopyMemory: Data to be set is copied and assigned to a new memory block. Data memory block will be freed on deletion of mitk::Image. //## MamageMemory: Data to be set will be referenced, and Data memory block will be freed on deletion of mitk::Image. //## Reference Memory: Data to be set will be referenced, but Data memory block will not be freed on deletion of mitk::Image. //## DontManageMemory = ReferenceMemory. enum ImportMemoryManagementType { CopyMemory, ManageMemory, ReferenceMemory, DontManageMemory = ReferenceMemory }; //##Documentation //## @brief Vector container of SmartPointers to ImageDataItems; //## Class is only for internal usage to allow convenient access to all slices over iterators; //## See documentation of ImageDataItem for details. typedef std::vector ImageDataItemPointerArray; typedef itk::Statistics::Histogram HistogramType; public: //##Documentation //## @brief Returns the PixelType of channel @a n. const mitk::PixelType& GetPixelType(int n = 0) const; //##Documentation //## @brief Get dimension of the image //## unsigned int GetDimension() const; //##Documentation //## @brief Get the size of dimension @a i (e.g., i=0 results in the number of pixels in x-direction). //## //## @sa GetDimensions() unsigned int GetDimension(int i) const; //## @brief Get the data vector of the complete image, i.e., of all channels linked together. //## //## If you only want to access a slice, volume at a specific time or single channel //## use one of the SubImageSelector classes. virtual void* GetData(); //## @brief Get the pixel value at one specific index position. //## @brief Get the pixel value at one specific position. //## //## The pixel type is always being converted to double. double GetPixelValueByIndex(const mitk::Index3D& position, unsigned int timestep = 0); //## @brief Get the pixel value at one specific world position. //## //## The pixel type is always being converted to double. double GetPixelValueByWorldCoordinate(const mitk::Point3D& position, unsigned int timestep = 0); //##Documentation //## @brief Get a volume at a specific time @a t of channel @a n as a vtkImageData. virtual vtkImageData* GetVtkImageData(int t = 0, int n = 0); //##Documentation //## @brief Get the complete image, i.e., all channels linked together, as a @a mitkIpPicDescriptor. //## //## If you only want to access a slice, volume at a specific time or single channel //## use one of the SubImageSelector classes. virtual mitkIpPicDescriptor* GetPic(); //##Documentation //## @brief Check whether slice @a s at time @a t in channel @a n is set virtual bool IsSliceSet(int s = 0, int t = 0, int n = 0) const; //##Documentation //## @brief Check whether volume at time @a t in channel @a n is set virtual bool IsVolumeSet(int t = 0, int n = 0) const; //##Documentation //## @brief Check whether the channel @a n is set virtual bool IsChannelSet(int n = 0) const; //##Documentation //## @brief Set @a data as slice @a s at time @a t in channel @a n. It is in //## the responsibility of the caller to ensure that the data vector @a data //## is really a slice (at least is not smaller than a slice), since there is //## no chance to check this. //## //## The data is copied to an array managed by the image. If the image shall //## reference the data, use SetImportSlice with ImportMemoryManagementType //## set to ReferenceMemory. For importing ITK images use of mitk:: //## ITKImageImport is recommended. //## @sa SetPicSlice, SetImportSlice, SetImportVolume virtual bool SetSlice(const void *data, int s = 0, int t = 0, int n = 0); //##Documentation //## @brief Set @a data as volume at time @a t in channel @a n. It is in //## the responsibility of the caller to ensure that the data vector @a data //## is really a volume (at least is not smaller than a volume), since there is //## no chance to check this. //## //## The data is copied to an array managed by the image. If the image shall //## reference the data, use SetImportVolume with ImportMemoryManagementType //## set to ReferenceMemory. For importing ITK images use of mitk:: //## ITKImageImport is recommended. //## @sa SetPicVolume, SetImportVolume virtual bool SetVolume(const void *data, int t = 0, int n = 0); //##Documentation //## @brief Set @a data in channel @a n. It is in //## the responsibility of the caller to ensure that the data vector @a data //## is really a channel (at least is not smaller than a channel), since there is //## no chance to check this. //## //## The data is copied to an array managed by the image. If the image shall //## reference the data, use SetImportChannel with ImportMemoryManagementType //## set to ReferenceMemory. For importing ITK images use of mitk:: //## ITKImageImport is recommended. //## @sa SetPicChannel, SetImportChannel virtual bool SetChannel(const void *data, int n = 0); //##Documentation //## @brief Set @a data as slice @a s at time @a t in channel @a n. It is in //## the responsibility of the caller to ensure that the data vector @a data //## is really a slice (at least is not smaller than a slice), since there is //## no chance to check this. //## //## The data is managed according to the parameter \a importMemoryManagement. //## @sa SetPicSlice virtual bool SetImportSlice(void *data, int s = 0, int t = 0, int n = 0, ImportMemoryManagementType importMemoryManagement = CopyMemory ); //##Documentation //## @brief Set @a data as volume at time @a t in channel @a n. It is in //## the responsibility of the caller to ensure that the data vector @a data //## is really a volume (at least is not smaller than a volume), since there is //## no chance to check this. //## //## The data is managed according to the parameter \a importMemoryManagement. //## @sa SetPicVolume virtual bool SetImportVolume(void *data, int t = 0, int n = 0, ImportMemoryManagementType importMemoryManagement = CopyMemory ); //##Documentation //## @brief Set @a data in channel @a n. It is in //## the responsibility of the caller to ensure that the data vector @a data //## is really a channel (at least is not smaller than a channel), since there is //## no chance to check this. //## //## The data is managed according to the parameter \a importMemoryManagement. //## @sa SetPicChannel virtual bool SetImportChannel(void *data, int n = 0, ImportMemoryManagementType importMemoryManagement = CopyMemory ); //##Documentation //## @brief Set @a pic as slice @a s at time @a t in channel @a n. //## //## The data is copied to an array managed by the image. //## @todo The corresponding @a Geomety3D and depending @a Geometry2D entries //## are updated according to the information provided in the tags of @a pic. //## @return @a false : dimensions and/or data-type of @a pic does not //## comply with image //## @a true success virtual bool SetPicSlice(const mitkIpPicDescriptor *pic, int s = 0, int t = 0, int n = 0, ImportMemoryManagementType importMemoryManagement = CopyMemory ); //##Documentation //## @brief Set @a pic as volume at time @a t in channel @a n. //## //## The data is copied to an array managed by the image. //## @todo The corresponding @a Geomety3D and depending @a Geometry2D entries //## are updated according to the information provided in the tags of @a pic. //## @return @a false : dimensions and/or data-type of @a pic does not //## comply with image //## @a true success virtual bool SetPicVolume(const mitkIpPicDescriptor *pic, int t = 0, int n = 0, ImportMemoryManagementType importMemoryManagement = CopyMemory ); //##Documentation //## @brief Set @a pic in channel @a n. //## //## The data is copied to an array managed by the image. //## @todo The corresponding @a Geomety3D and depending @a Geometry2D entries //## are updated according to the information provided in the tags of @a pic. //## @return @a false : dimensions and/or data-type of @a pic does not //## comply with image //## @a true success virtual bool SetPicChannel(const mitkIpPicDescriptor *pic, int n = 0, ImportMemoryManagementType importMemoryManagement = CopyMemory ); //##Documentation //## initialize new (or re-initialize) image information //## @warning Initialize() by pic assumes a plane, evenly spaced geometry starting at (0,0,0). virtual void Initialize(const mitk::PixelType& type, unsigned int dimension, unsigned int *dimensions, unsigned int channels = 1); //##Documentation //## initialize new (or re-initialize) image information by a Geometry3D //## //## @param tDim override time dimension (@a n[3]) if @a geometry is a TimeSlicedGeometry (if >0) virtual void Initialize(const mitk::PixelType& type, const mitk::Geometry3D& geometry, unsigned int channels = 1, int tDim=-1); //##Documentation //## initialize new (or re-initialize) image information by a Geometry2D and number of slices //## //## Initializes the bounding box according to the width/height of the //## Geometry2D and @a sDim via SlicedGeometry3D::InitializeEvenlySpaced. //## The spacing is calculated from the Geometry2D. //## @param tDim override time dimension (@a n[3]) if @a geometry is a TimeSlicedGeometry (if >0) //## \sa SlicedGeometry3D::InitializeEvenlySpaced virtual void Initialize(const mitk::PixelType& type, int sDim, const mitk::Geometry2D& geometry2d, bool flipped = false, unsigned int channels = 1, int tDim=-1); //##Documentation //## initialize new (or re-initialize) image information by another //## mitk-image. //## Only the header is used, not the data vector! //## virtual void Initialize(const mitk::Image* image); //##Documentation //## initialize new (or re-initialize) image information by @a pic. //## Dimensions and @a Geometry3D /@a Geometry2D are set according //## to the tags in @a pic. //## Only the header is used, not the data vector! Use SetPicVolume(pic) //## to set the data vector. //## //## @param tDim override time dimension (@a n[3]) in @a pic (if >0) //## @param sDim override z-space dimension (@a n[2]) in @a pic (if >0) //## @warning Initialize() by pic assumes a plane, evenly spaced geometry starting at (0,0,0). virtual void Initialize(const mitkIpPicDescriptor* pic, int channels = 1, int tDim = -1, int sDim = -1); //##Documentation //## initialize new (or re-initialize) image information by @a vtkimagedata, //## a vtk-image. //## Only the header is used, not the data vector! Use //## SetVolume(vtkimage->GetScalarPointer()) to set the data vector. //## //## @param tDim override time dimension in @a vtkimagedata (if >0 and <) //## @param sDim override z-space dimension in @a vtkimagedata (if >0 and <) virtual void Initialize(vtkImageData* vtkimagedata, int channels = 1, int tDim = -1, int sDim = -1); //##Documentation //## initialize new (or re-initialize) image information by @a itkimage, //## a templated itk-image. //## Only the header is used, not the data vector! Use //## SetVolume(itkimage->GetBufferPointer()) to set the data vector. //## //## @param tDim override time dimension in @a itkimage (if >0 and <) //## @param sDim override z-space dimension in @a itkimage (if >0 and <) template void InitializeByItk(const itkImageType* itkimage, int channels = 1, int tDim = -1, int sDim=-1) { if(itkimage==NULL) return; MITK_DEBUG << "Initializing MITK image from ITK image."; // build array with dimensions in each direction with at least 4 entries m_Dimension=itkimage->GetImageDimension(); unsigned int i, *tmpDimensions=new unsigned int[m_Dimension>4?m_Dimension:4]; for(i=0;iGetLargestPossibleRegion().GetSize().GetSize()[i]; if(m_Dimension<4) { unsigned int *p; for(i=0,p=tmpDimensions+m_Dimension;i<4-m_Dimension;++i, ++p) *p=1; } // overwrite number of slices if sDim is set if((m_Dimension>2) && (sDim>=0)) tmpDimensions[2]=sDim; // overwrite number of time points if tDim is set if((m_Dimension>3) && (tDim>=0)) tmpDimensions[3]=tDim; // rough initialization of Image Initialize(mitk::PixelType(typeid(typename itkImageType::PixelType)), m_Dimension, tmpDimensions, channels); const typename itkImageType::SpacingType & itkspacing = itkimage->GetSpacing(); MITK_DEBUG << "ITK spacing " << itkspacing; // access spacing of itk::Image Vector3D spacing; FillVector3D(spacing, itkspacing[0], 1.0, 1.0); if(m_Dimension >= 2) spacing[1]=itkspacing[1]; if(m_Dimension >= 3) spacing[2]=itkspacing[2]; // access origin of itk::Image Point3D origin; const typename itkImageType::PointType & itkorigin = itkimage->GetOrigin(); MITK_DEBUG << "ITK origin " << itkorigin; FillVector3D(origin, itkorigin[0], 0.0, 0.0); if(m_Dimension>=2) origin[1]=itkorigin[1]; if(m_Dimension>=3) origin[2]=itkorigin[2]; // access direction of itk::Image and include spacing const typename itkImageType::DirectionType & itkdirection = itkimage->GetDirection(); MITK_DEBUG << "ITK direction " << itkdirection; mitk::Matrix3D matrix; matrix.SetIdentity(); unsigned int j, itkDimMax3 = (m_Dimension >= 3? 3 : m_Dimension); // check if spacing has no zero entry and itkdirection has no zero columns bool itkdirectionOk = true; mitk::ScalarType columnSum; for( j=0; j < itkDimMax3; ++j ) { columnSum = 0.0; for ( i=0; i < itkDimMax3; ++i) { columnSum += fabs(itkdirection[i][j]); } if(columnSum < mitk::eps) { itkdirectionOk = false; } if ( (spacing[j] < - mitk::eps) // (normally sized) negative value && (j==2) && (m_Dimensions[2] == 1) ) { // Negative spacings can occur when reading single DICOM slices with ITK via GDCMIO // In these cases spacing is not determind by ITK correctly (because it distinguishes correctly // between slice thickness and inter slice distance -- slice distance is meaningless for // single slices). // I experienced that ITK produced something meaningful nonetheless because is is // evaluating the tag "(0018,0088) Spacing between slices" as a fallback. This tag is not // reliable (http://www.itk.org/pipermail/insight-users/2005-September/014711.html) // but gives at least a hint. // In real world cases I experienced that this tag contained the correct inter slice distance // with a negative sign, so we just invert such negative spacings. MITK_WARN << "Illegal value of itk::Image::GetSpacing()[" << j <<"]=" << spacing[j] << ". Using inverted value " << -spacing[j]; spacing[j] = -spacing[j]; } else if (spacing[j] < mitk::eps) // value near zero { MITK_ERROR << "Illegal value of itk::Image::GetSpacing()[" << j <<"]=" << spacing[j] << ". Using 1.0 instead."; spacing[j] = 1.0; } } if(itkdirectionOk == false) { MITK_ERROR << "Illegal matrix returned by itk::Image::GetDirection():" << itkdirection << " Using identity instead."; for ( i=0; i < itkDimMax3; ++i) for( j=0; j < itkDimMax3; ++j ) if ( i == j ) matrix[i][j] = spacing[j]; else matrix[i][j] = 0.0; } else { for ( i=0; i < itkDimMax3; ++i) for( j=0; j < itkDimMax3; ++j ) matrix[i][j] = itkdirection[i][j]*spacing[j]; } // re-initialize PlaneGeometry with origin and direction PlaneGeometry* planeGeometry = static_cast(GetSlicedGeometry(0)->GetGeometry2D(0)); planeGeometry->SetOrigin(origin); planeGeometry->GetIndexToWorldTransform()->SetMatrix(matrix); // re-initialize SlicedGeometry3D SlicedGeometry3D* slicedGeometry = GetSlicedGeometry(0); slicedGeometry->InitializeEvenlySpaced(planeGeometry, m_Dimensions[2]); slicedGeometry->SetSpacing(spacing); // re-initialize TimeSlicedGeometry GetTimeSlicedGeometry()->InitializeEvenlyTimed(slicedGeometry, m_Dimensions[3]); // clean-up delete [] tmpDimensions; this->Initialize(); }; //##Documentation //## @brief Check whether slice @a s at time @a t in channel @a n is valid, i.e., //## is (or can be) inside of the image virtual bool IsValidSlice(int s = 0, int t = 0, int n = 0) const; //##Documentation //## @brief Check whether volume at time @a t in channel @a n is valid, i.e., //## is (or can be) inside of the image virtual bool IsValidVolume(int t = 0, int n = 0) const; //##Documentation //## @brief Check whether the channel @a n is valid, i.e., //## is (or can be) inside of the image virtual bool IsValidChannel(int n = 0) const; //##Documentation //## @brief Returns true if an image is rotated, i.e. its geometry's //## transformation matrix has nonzero elements besides the diagonal. //## Non-diagonal elements are checked if larger then 1/1000 of the matrix' trace. bool IsRotated() const; //##Documentation //## @brief Get the sizes of all dimensions as an integer-array. //## //## @sa GetDimension(int i); unsigned int* GetDimensions() const; //##Documentation //## @brief Sets a geometry to an image. virtual void SetGeometry(Geometry3D* aGeometry3D); virtual const HistogramType* GetScalarHistogram(int t=0) const; //##Documentation //## \brief Get the minimum for scalar images virtual ScalarType GetScalarValueMin(int t=0) const; //##Documentation //## \brief Get the maximum for scalar images virtual ScalarType GetScalarValueMax(int t=0) const; //##Documentation //## \brief Get the second smallest value for scalar images virtual ScalarType GetScalarValue2ndMin(int t=0) const; //##Documentation //## \brief Get the smallest value for scalar images, but do not recompute it first virtual mitk::ScalarType GetScalarValueMinNoRecompute( unsigned int t = 0 ) const { if ( t < m_ScalarMin.size() ) return m_ScalarMin[t]; else return itk::NumericTraits::max(); } //##Documentation //## \brief Get the second smallest value for scalar images, but do not recompute it first virtual mitk::ScalarType GetScalarValue2ndMinNoRecompute( unsigned int t = 0 ) const { if ( t < m_Scalar2ndMin.size() ) return m_Scalar2ndMin[t]; else return itk::NumericTraits::max(); } //##Documentation //## \brief Get the second largest value for scalar images virtual ScalarType GetScalarValue2ndMax(int t=0) const; //##Documentation //## \brief Get the largest value for scalar images, but do not recompute it first virtual mitk::ScalarType GetScalarValueMaxNoRecompute( unsigned int t = 0 ) const { if ( t < m_ScalarMax.size() ) return m_ScalarMax[t]; else return itk::NumericTraits::NonpositiveMin(); } //##Documentation //## \brief Get the second largest value for scalar images, but do not recompute it first virtual mitk::ScalarType GetScalarValue2ndMaxNoRecompute( unsigned int t = 0 ) const { if ( t < m_Scalar2ndMax.size() ) return m_Scalar2ndMax[t]; else return itk::NumericTraits::NonpositiveMin(); } //##Documentation //## \brief Get the count of voxels with the smallest scalar value in the dataset mitk::ScalarType GetCountOfMinValuedVoxels(int t = 0) const; //##Documentation //## \brief Get the count of voxels with the largest scalar value in the dataset mitk::ScalarType GetCountOfMaxValuedVoxels(int t = 0) const; //##Documentation //## \brief Get the count of voxels with the largest scalar value in the dataset virtual unsigned int GetCountOfMaxValuedVoxelsNoRecompute( unsigned int t = 0 ) const { if ( t < m_CountOfMaxValuedVoxels.size() ) return m_CountOfMaxValuedVoxels[t]; else return 0; } //##Documentation //## \brief Get the count of voxels with the smallest scalar value in the dataset virtual unsigned int GetCountOfMinValuedVoxelsNoRecompute( unsigned int t = 0 ) const { if ( t < m_CountOfMinValuedVoxels.size() ) return m_CountOfMinValuedVoxels[t]; else return 0; } //##Documentation //## @warning for internal use only virtual ImageDataItemPointer GetSliceData(int s = 0, int t = 0, int n = 0, void *data = NULL, ImportMemoryManagementType importMemoryManagement = CopyMemory); //##Documentation //## @warning for internal use only virtual ImageDataItemPointer GetVolumeData(int t = 0, int n = 0, void *data = NULL, ImportMemoryManagementType importMemoryManagement = CopyMemory); //##Documentation //## @warning for internal use only virtual ImageDataItemPointer GetChannelData(int n = 0, void *data = NULL, ImportMemoryManagementType importMemoryManagement = CopyMemory); template < typename ItkImageType > friend void _ComputeExtremaInItkImage(ItkImageType* itkImage, mitk::Image * mitkImage, int t); protected: int GetSliceIndex(int s = 0, int t = 0, int n = 0) const; int GetVolumeIndex(int t = 0, int n = 0) const; void ComputeOffsetTable(); virtual void Expand( unsigned int timeSteps ); virtual bool IsValidTimeStep(int t) const; virtual void ResetImageStatistics() const; virtual void ComputeImageStatistics(int t=0) const; virtual ImageDataItemPointer AllocateSliceData(int s = 0, int t = 0, int n = 0, void *data = NULL, ImportMemoryManagementType importMemoryManagement = CopyMemory); virtual ImageDataItemPointer AllocateVolumeData(int t = 0, int n = 0, void *data = NULL, ImportMemoryManagementType importMemoryManagement = CopyMemory); virtual ImageDataItemPointer AllocateChannelData(int n = 0, void *data = NULL, ImportMemoryManagementType importMemoryManagement = CopyMemory); Image(); + Image(const Image &other); + virtual ~Image(); virtual void Clear(); //## @warning Has to be called by every Initialize method! virtual void Initialize(); ImageTimeSelector* GetTimeSelector() const; virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; mutable ImageDataItemPointerArray m_Channels; mutable ImageDataItemPointerArray m_Volumes; mutable ImageDataItemPointerArray m_Slices; unsigned int m_Dimension; unsigned int *m_Dimensions; size_t *m_OffsetTable; ImageDataItemPointer m_CompleteData; PixelType m_PixelType; mutable itk::Object::Pointer m_HistogramGeneratorObject; mutable itk::Object::Pointer m_TimeSelectorForExtremaObject; mutable std::vector m_CountOfMinValuedVoxels; mutable std::vector m_CountOfMaxValuedVoxels; mutable std::vector m_ScalarMin; mutable std::vector m_ScalarMax; mutable std::vector m_Scalar2ndMin; mutable std::vector m_Scalar2ndMax; itk::TimeStamp m_LastRecomputeTimeStamp; }; //##Documentation //## @brief Cast an itk::Image (with a specific type) to an mitk::Image. //## //## CastToMitkImage does not cast pixel types etc., just image data //## Needs "mitkImage.h" header included. //## If you get a compile error, try image.GetPointer(); //## @ingroup Adaptor //## \sa mitkITKImageImport template void CastToMitkImage(const itk::SmartPointer& itkimage, itk::SmartPointer& mitkoutputimage) { if(mitkoutputimage.IsNull()) { mitkoutputimage = mitk::Image::New(); } mitkoutputimage->InitializeByItk(itkimage.GetPointer()); mitkoutputimage->SetChannel(itkimage->GetBufferPointer()); } //##Documentation //## @brief Cast an itk::Image (with a specific type) to an mitk::Image. //## //## CastToMitkImage does not cast pixel types etc., just image data //## Needs "mitkImage.h" header included. //## If you get a compile error, try image.GetPointer(); //## @ingroup Adaptor //## \sa mitkITKImageImport template void CastToMitkImage(const ItkOutputImageType* itkimage, itk::SmartPointer& mitkoutputimage) { if(mitkoutputimage.IsNull()) { mitkoutputimage = mitk::Image::New(); } mitkoutputimage->InitializeByItk(itkimage); mitkoutputimage->SetChannel(itkimage->GetBufferPointer()); } } // namespace mitk #endif /* MITKIMAGE_H_HEADER_INCLUDED_C1C2FCD2 */ diff --git a/Core/Code/DataManagement/mitkImageDataItem.cpp b/Core/Code/DataManagement/mitkImageDataItem.cpp index 08634d1fdb..569cff7471 100644 --- a/Core/Code/DataManagement/mitkImageDataItem.cpp +++ b/Core/Code/DataManagement/mitkImageDataItem.cpp @@ -1,224 +1,231 @@ /*========================================================================= 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 "mitkImageDataItem.h" #include "mitkMemoryUtilities.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ipFunc/mitkIpFunc.h" mitk::ImageDataItem::ImageDataItem(const ImageDataItem& aParent, unsigned int dimension, void *data, bool manageMemory, size_t offset) : m_Data(NULL), m_ManageMemory(false), m_PicDescriptor(NULL), m_VtkImageData(NULL), m_Offset(offset), m_IsComplete(false), m_Size(0), m_Parent(&aParent) { m_PixelType = aParent.GetPixelType(); m_PicDescriptor=mitkIpPicNew(); m_PicDescriptor->bpe=m_PixelType.GetBpe(); m_PicDescriptor->type=m_PixelType.GetType(); m_PicDescriptor->dim=dimension; memcpy(m_PicDescriptor->n, aParent.GetPicDescriptor()->n, sizeof(mitkIpUInt4_t)*_mitkIpPicNDIM); m_PicDescriptor->data=m_Data=static_cast(aParent.GetData())+offset; mitkIpFuncCopyTags(m_PicDescriptor, aParent.GetPicDescriptor()); m_Size = _mitkIpPicSize(m_PicDescriptor); if(data != NULL) { memcpy(m_Data, data, m_Size); if(manageMemory) { delete [] (unsigned char*) data; } } m_ReferenceCountLock.Lock(); m_ReferenceCount = 0; m_ReferenceCountLock.Unlock(); } mitk::ImageDataItem::~ImageDataItem() { if(m_VtkImageData!=NULL) m_VtkImageData->Delete(); if(m_PicDescriptor!=NULL) { m_PicDescriptor->data=NULL; mitkIpPicFree(m_PicDescriptor); } if(m_Parent.IsNull()) { if(m_ManageMemory) delete [] m_Data; } } mitk::ImageDataItem::ImageDataItem(const mitk::PixelType& type, unsigned int dimension, unsigned int *dimensions, void *data, bool manageMemory) : m_Data((unsigned char*)data), m_ManageMemory(manageMemory), m_PicDescriptor(NULL), m_VtkImageData(NULL), m_Offset(0), m_IsComplete(false), m_Size(0), m_Parent(NULL) { //const std::type_info & typeId=*type.GetTypeId(); m_PixelType = type; m_PicDescriptor=mitkIpPicNew(); m_PicDescriptor->bpe=m_PixelType.GetBpe(); m_PicDescriptor->type=m_PixelType.GetType(); m_PicDescriptor->dim=dimension; memcpy(m_PicDescriptor->n, dimensions, sizeof(mitkIpUInt4_t)*(dimension<=_mitkIpPicNDIM?dimension:_mitkIpPicNDIM)); unsigned char i; for(i=dimension; i < _mitkIpPicNDIM; ++i) m_PicDescriptor->n[i] = 1; m_Size = _mitkIpPicSize(m_PicDescriptor); if(m_Data == NULL) { m_Data = mitk::MemoryUtilities::AllocateElements( m_Size ); m_ManageMemory = true; } m_PicDescriptor->data=m_Data; m_ReferenceCountLock.Lock(); m_ReferenceCount = 0; m_ReferenceCountLock.Unlock(); } +mitk::ImageDataItem::ImageDataItem(const ImageDataItem &other) + : m_PixelType(other.m_PixelType), m_ManageMemory(other.m_ManageMemory), m_Offset(other.m_Offset), + m_IsComplete(other.m_IsComplete), m_Size(other.m_Size) +{ + +} + void mitk::ImageDataItem::ConstructVtkImageData() const { vtkImageData *inData = vtkImageData::New(); vtkDataArray *scalars = NULL; unsigned long size = 0; if ( m_PicDescriptor->dim == 1 ) { inData->SetDimensions( m_PicDescriptor->n[0] -1, 1, 1); size = m_PicDescriptor->n[0]; inData->SetOrigin( ((float) m_PicDescriptor->n[0]) / 2.0f, 0, 0 ); } else if ( m_PicDescriptor->dim == 2 ) { inData->SetDimensions( m_PicDescriptor->n[0] , m_PicDescriptor->n[1] , 1 ); size = m_PicDescriptor->n[0] * m_PicDescriptor->n[1]; inData->SetOrigin( ((float) m_PicDescriptor->n[0]) / 2.0f, ((float) m_PicDescriptor->n[1]) / 2.0f, 0 ); } else if ( m_PicDescriptor->dim >= 3 ) { inData->SetDimensions( m_PicDescriptor->n[0], m_PicDescriptor->n[1], m_PicDescriptor->n[2] ); size = m_PicDescriptor->n[0] * m_PicDescriptor->n[1] * m_PicDescriptor->n[2]; // Test //inData->SetOrigin( (float) m_PicDescriptor->n[0] / 2.0f, (float) m_PicDescriptor->n[1] / 2.0f, (float) m_PicDescriptor->n[2] / 2.0f ); inData->SetOrigin( 0, 0, 0 ); } else { inData->Delete () ; return; } inData->SetNumberOfScalarComponents(m_PixelType.GetNumberOfComponents()); if ( ( m_PixelType.GetType() == mitkIpPicInt || m_PixelType.GetType() == mitkIpPicUInt ) && m_PixelType.GetBitsPerComponent() == 1 ) { inData->SetScalarType( VTK_BIT ); scalars = vtkBitArray::New(); } else if ( m_PixelType.GetType() == mitkIpPicInt && m_PixelType.GetBitsPerComponent() == 8 ) { inData->SetScalarType( VTK_CHAR ); scalars = vtkCharArray::New(); } else if ( m_PixelType.GetType() == mitkIpPicUInt && m_PixelType.GetBitsPerComponent() == 8 ) { inData->SetScalarType( VTK_UNSIGNED_CHAR ); scalars = vtkUnsignedCharArray::New(); } else if ( m_PixelType.GetType() == mitkIpPicInt && m_PixelType.GetBitsPerComponent() == 16 ) { inData->SetScalarType( VTK_SHORT ); scalars = vtkShortArray::New(); } else if ( m_PixelType.GetType() == mitkIpPicUInt && m_PixelType.GetBitsPerComponent() == 16 ) { inData->SetScalarType( VTK_UNSIGNED_SHORT ); scalars = vtkUnsignedShortArray::New(); } else if ( m_PixelType.GetType() == mitkIpPicInt && m_PixelType.GetBitsPerComponent() == 32 ) { inData->SetScalarType( VTK_INT ); scalars = vtkIntArray::New(); } else if ( m_PixelType.GetType() == mitkIpPicUInt && m_PixelType.GetBitsPerComponent() == 32 ) { inData->SetScalarType( VTK_UNSIGNED_INT ); scalars = vtkUnsignedIntArray::New(); } else if ( m_PixelType.GetType() == mitkIpPicInt && m_PixelType.GetBitsPerComponent() == 64 ) { inData->SetScalarType( VTK_LONG ); scalars = vtkLongArray::New(); } else if ( m_PixelType.GetType() == mitkIpPicUInt && m_PixelType.GetBitsPerComponent() == 64 ) { inData->SetScalarType( VTK_UNSIGNED_LONG ); scalars = vtkUnsignedLongArray::New(); } else if ( m_PixelType.GetType() == mitkIpPicFloat && m_PixelType.GetBitsPerComponent() == 32 ) { inData->SetScalarType( VTK_FLOAT ); scalars = vtkFloatArray::New(); } else if ( m_PixelType.GetType() == mitkIpPicFloat && m_PixelType.GetBitsPerComponent() == 64 ) { inData->SetScalarType( VTK_DOUBLE ); scalars = vtkDoubleArray::New(); } else { inData->Delete(); return; } m_VtkImageData = inData; // allocate the new scalars scalars->SetNumberOfComponents(m_VtkImageData->GetNumberOfScalarComponents()); scalars->SetVoidArray(m_PicDescriptor->data, _mitkIpPicElements(m_PicDescriptor)*m_VtkImageData->GetNumberOfScalarComponents(), 1); m_VtkImageData->GetPointData()->SetScalars(scalars); scalars->Delete(); } void mitk::ImageDataItem::Modified() const { if(m_VtkImageData) m_VtkImageData->Modified(); } diff --git a/Core/Code/DataManagement/mitkImageDataItem.h b/Core/Code/DataManagement/mitkImageDataItem.h index b1bad1d95f..9cc0ad757d 100644 --- a/Core/Code/DataManagement/mitkImageDataItem.h +++ b/Core/Code/DataManagement/mitkImageDataItem.h @@ -1,136 +1,137 @@ /*========================================================================= 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 IMAGEDATAITEM_H #define IMAGEDATAITEM_H #include "mitkCommon.h" #include "mitkPixelType.h" class vtkImageData; namespace mitk { //##Documentation //## @brief Internal class for managing references on sub-images //## //## ImageDataItem is a container for image data which is used internal in //## mitk::Image to handle the communication between the different data types for images //## used in MITK (ipPicDescriptor, mitk::Image, vtkImageData). Common for these image data //## types is the actual image data, but they differ in representation of pixel type etc. //## The class is also used to convert ipPic images to vtkImageData. //## //## The class is mainly used to extract sub-images inside of mitk::Image, like single slices etc. //## It should not be used outside of this. //## //## @param manageMemory Determines if image data is removed while destruction of ImageDataItem or not. //## @ingroup Data class MITK_CORE_EXPORT ImageDataItem : public itk::LightObject { public: mitkClassMacro(ImageDataItem, itk::LightObject); ImageDataItem(const ImageDataItem& aParent, unsigned int dimension, void *data = NULL, bool manageMemory = false, size_t offset = 0); ~ImageDataItem(); ImageDataItem(const mitk::PixelType& type, unsigned int dimension, unsigned int *dimensions, void *data, bool manageMemory); + ImageDataItem(const ImageDataItem &other); void* GetData() const { return m_Data; } bool IsComplete() const { return m_IsComplete; } void SetComplete(bool complete) { m_IsComplete = complete; } int GetOffset() const { return m_Offset; } PixelType GetPixelType() const { return m_PixelType; } ImageDataItem::ConstPointer GetParent() const { return m_Parent; } mitkIpPicDescriptor* GetPicDescriptor() const { return m_PicDescriptor; } //## Returns a vtkImageData; if non is present, a new one is constructed. vtkImageData* GetVtkImageData() const { if(m_VtkImageData==NULL) ConstructVtkImageData(); return m_VtkImageData; } // Returns if image data should be deleted on destruction of ImageDataItem. bool GetManageMemory() const { return m_ManageMemory; } virtual void ConstructVtkImageData() const; unsigned long GetSize() const { return m_Size; } virtual void Modified() const; protected: unsigned char* m_Data; PixelType m_PixelType; bool m_ManageMemory; mitkIpPicDescriptor* m_PicDescriptor; mutable vtkImageData* m_VtkImageData; int m_Offset; bool m_IsComplete; unsigned long m_Size; private: ImageDataItem::ConstPointer m_Parent; template unsigned char *ConvertTensorsToRGB() const; }; } // namespace mitk #endif /* IMAGEDATAITEM_H */ diff --git a/Core/Code/DataManagement/mitkPointSet.cpp b/Core/Code/DataManagement/mitkPointSet.cpp index 1e74465ea7..9919675ed7 100755 --- a/Core/Code/DataManagement/mitkPointSet.cpp +++ b/Core/Code/DataManagement/mitkPointSet.cpp @@ -1,776 +1,782 @@ /*========================================================================= 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 "mitkPointSet.h" #include "mitkPointOperation.h" #include "mitkInteractionConst.h" #include mitk::PointSet::PointSet() { this->InitializeEmpty(); } +mitk::PointSet::PointSet(const PointSet &other): BaseData(other), +m_PointSetSeries(other.m_PointSetSeries), +m_CalculateBoundingBox(other.m_CalculateBoundingBox) +{ +} + mitk::PointSet::~PointSet() { this->ClearData(); } void mitk::PointSet::ClearData() { m_PointSetSeries.clear(); Superclass::ClearData(); } void mitk::PointSet::InitializeEmpty() { m_PointSetSeries.resize( 1 ); m_PointSetSeries[0] = DataType::New(); PointDataContainer::Pointer pointData = PointDataContainer::New(); m_PointSetSeries[0]->SetPointData( pointData ); m_CalculateBoundingBox = false; Superclass::InitializeTimeSlicedGeometry(1); m_Initialized = true; } bool mitk::PointSet::IsEmptyTimeStep(unsigned int t) const { return IsInitialized() && (GetSize(t) == 0); } void mitk::PointSet::Expand( unsigned int timeSteps ) { // Check if the vector is long enough to contain the new element // at the given position. If not, expand it with sufficient pre-initialized // elements. // // NOTE: This method will never REDUCE the vector size; it should only // be used to make sure that the vector has enough elements to include the // specified time step. unsigned int oldSize = m_PointSetSeries.size(); if ( timeSteps > oldSize ) { Superclass::Expand( timeSteps ); m_PointSetSeries.resize( timeSteps ); for ( unsigned int i = oldSize; i < timeSteps; ++i ) { m_PointSetSeries[i] = DataType::New(); PointDataContainer::Pointer pointData = PointDataContainer::New(); m_PointSetSeries[i]->SetPointData( pointData ); } //if the size changes, then compute the bounding box m_CalculateBoundingBox = true; this->InvokeEvent( PointSetExtendTimeRangeEvent() ); } } unsigned int mitk::PointSet::GetPointSetSeriesSize() const { return m_PointSetSeries.size(); } int mitk::PointSet::GetSize( unsigned int t ) const { if ( t < m_PointSetSeries.size() ) { return m_PointSetSeries[t]->GetNumberOfPoints(); } else { return 0; } } mitk::PointSet::DataType::Pointer mitk::PointSet::GetPointSet( int t ) const { if ( t < (int)m_PointSetSeries.size() ) { return m_PointSetSeries[t]; } else { return NULL; } } int mitk::PointSet::SearchPoint( Point3D point, float distance, int t ) const { if ( t >= (int)m_PointSetSeries.size() ) { return -1; } // Out is the point which is checked to be the searched point PointType out; out.Fill( 0 ); PointType indexPoint; this->GetGeometry( t )->WorldToIndex(point, indexPoint); // Searching the first point in the Set, that is +- distance far away fro // the given point unsigned int i; PointsContainer::Iterator it, end; end = m_PointSetSeries[t]->GetPoints()->End(); int bestIndex = -1; distance = distance * distance; // To correct errors from converting index to world and world to index if (distance == 0.0) { distance = 0.000001; } ScalarType bestDist = distance; ScalarType dist, tmp; for ( it = m_PointSetSeries[t]->GetPoints()->Begin(), i = 0; it != end; ++it, ++i ) { bool ok = m_PointSetSeries[t]->GetPoints() ->GetElementIfIndexExists( it->Index(), &out ); if ( !ok ) { return -1; } else if ( indexPoint == out ) //if totally equal { return it->Index(); } //distance calculation tmp = out[0] - indexPoint[0]; dist = tmp * tmp; tmp = out[1] - indexPoint[1]; dist += tmp * tmp; tmp = out[2] - indexPoint[2]; dist += tmp * tmp; if ( dist < bestDist ) { bestIndex = it->Index(); bestDist = dist; } } return bestIndex; } mitk::PointSet::PointType mitk::PointSet::GetPoint( PointIdentifier id, int t ) const { PointType out; out.Fill(0); if ( (unsigned int) t >= m_PointSetSeries.size() ) { return out; } if ( m_PointSetSeries[t]->GetPoints()->IndexExists(id) ) { m_PointSetSeries[t]->GetPoint( id, &out ); this->GetGeometry(t)->IndexToWorld( out, out ); return out; } else { return out; } } bool mitk::PointSet ::GetPointIfExists( PointIdentifier id, PointType* point, int t ) const { if ( (unsigned int) t >= m_PointSetSeries.size() ) { return false; } if ( m_PointSetSeries[t]->GetPoints()->GetElementIfIndexExists(id, point) ) { this->GetGeometry( t )->IndexToWorld( *point, *point ); return true; } else { return false; } } void mitk::PointSet::SetPoint( PointIdentifier id, PointType point, int t ) { // Adapt the size of the data vector if necessary this->Expand( t+1 ); mitk::Point3D indexPoint; this->GetGeometry( t )->WorldToIndex( point, indexPoint ); m_PointSetSeries[t]->SetPoint( id, indexPoint ); PointDataType defaultPointData; defaultPointData.id = id; defaultPointData.selected = false; defaultPointData.pointSpec = mitk::PTUNDEFINED; m_PointSetSeries[t]->SetPointData( id, defaultPointData ); //boundingbox has to be computed anyway m_CalculateBoundingBox = true; this->Modified(); } void mitk::PointSet::SetPoint( PointIdentifier id, PointType point, PointSpecificationType spec, int t ) { // Adapt the size of the data vector if necessary this->Expand( t+1 ); mitk::Point3D indexPoint; this->GetGeometry( t )->WorldToIndex( point, indexPoint ); m_PointSetSeries[t]->SetPoint( id, indexPoint ); PointDataType defaultPointData; defaultPointData.id = id; defaultPointData.selected = false; defaultPointData.pointSpec = spec; m_PointSetSeries[t]->SetPointData( id, defaultPointData ); //boundingbox has to be computed anyway m_CalculateBoundingBox = true; this->Modified(); } void mitk::PointSet::InsertPoint( PointIdentifier id, PointType point, int t ) { if ( (unsigned int) t < m_PointSetSeries.size() ) { mitk::Point3D indexPoint; mitk::Geometry3D* tempGeometry = this->GetGeometry( t ); if (tempGeometry == NULL) { MITK_INFO<< __FILE__ << ", l." << __LINE__ << ": GetGeometry of "<< t <<" returned NULL!" << std::endl; return; } tempGeometry->WorldToIndex( point, indexPoint ); m_PointSetSeries[t]->GetPoints()->InsertElement( id, indexPoint ); PointDataType defaultPointData; defaultPointData.id = id; defaultPointData.selected = false; defaultPointData.pointSpec = mitk::PTUNDEFINED; m_PointSetSeries[t]->GetPointData()->InsertElement(id, defaultPointData); //boundingbox has to be computed anyway m_CalculateBoundingBox = true; this->Modified(); } } void mitk::PointSet::InsertPoint( PointIdentifier id, PointType point, PointSpecificationType spec, int t ) { if ( (unsigned int) t < m_PointSetSeries.size() ) { mitk::Point3D indexPoint; mitk::Geometry3D* tempGeometry = this->GetGeometry( t ); if (tempGeometry == NULL) { MITK_INFO<< __FILE__ << ", l." << __LINE__ << ": GetGeometry of "<< t <<" returned NULL!" << std::endl; return; } tempGeometry->WorldToIndex( point, indexPoint ); m_PointSetSeries[t]->GetPoints()->InsertElement( id, indexPoint ); PointDataType defaultPointData; defaultPointData.id = id; defaultPointData.selected = false; defaultPointData.pointSpec = spec; m_PointSetSeries[t]->GetPointData()->InsertElement(id, defaultPointData); //boundingbox has to be computed anyway m_CalculateBoundingBox = true; this->Modified(); } } bool mitk::PointSet::SwapPointPosition( PointIdentifier id, bool moveUpwards, int t ) { if(IndexExists(id, t) ) { PointType point = GetPoint(id,t); if(moveUpwards) {//up if(IndexExists(id-1,t)) { InsertPoint(id, GetPoint(id - 1, t), t); InsertPoint(id-1,point,t); this->Modified(); return true; } } else {//down if(IndexExists(id+1,t)) { InsertPoint(id, GetPoint(id + 1, t), t); InsertPoint(id+1,point,t); this->Modified(); return true; } } } return false; } bool mitk::PointSet::IndexExists( int position, int t ) const { if ( (unsigned int) t < m_PointSetSeries.size() ) { return m_PointSetSeries[t]->GetPoints()->IndexExists( position ); } else { return false; } } bool mitk::PointSet::GetSelectInfo( int position, int t ) const { if ( this->IndexExists( position, t ) ) { PointDataType pointData = { 0, false, PTUNDEFINED }; m_PointSetSeries[t]->GetPointData( position, &pointData ); return pointData.selected; } else { return false; } } void mitk::PointSet::SetSelectInfo( int position, bool selected, int t ) { if ( this->IndexExists( position, t ) ) { // timeStep to ms ScalarType timeInMS = this->GetTimeSlicedGeometry()->TimeStepToMS( t ); // point Point3D point = this->GetPoint( position, t ); PointOperation* op; if (selected) { op = new mitk::PointOperation(OpSELECTPOINT, timeInMS, point, position ); } else { op = new mitk::PointOperation(OpDESELECTPOINT, timeInMS, point, position ); } this->ExecuteOperation( op ); } } mitk::PointSpecificationType mitk::PointSet::GetSpecificationTypeInfo( int position, int t ) const { if ( this->IndexExists( position, t ) ) { PointDataType pointData = { 0, false, PTUNDEFINED }; m_PointSetSeries[t]->GetPointData( position, &pointData ); return pointData.pointSpec; } else { return PTUNDEFINED; } } int mitk::PointSet::GetNumberOfSelected( int t ) const { if ( (unsigned int) t >= m_PointSetSeries.size() ) { return 0; } int numberOfSelected = 0; PointDataIterator it; for ( it = m_PointSetSeries[t]->GetPointData()->Begin(); it != m_PointSetSeries[t]->GetPointData()->End(); it++ ) { if (it->Value().selected == true) { ++numberOfSelected; } } return numberOfSelected; } int mitk::PointSet::SearchSelectedPoint( int t ) const { if ( (unsigned int) t >= m_PointSetSeries.size() ) { return -1; } PointDataIterator it; for ( it = m_PointSetSeries[t]->GetPointData()->Begin(); it != m_PointSetSeries[t]->GetPointData()->End(); it++ ) { if ( it->Value().selected == true ) { return it->Index(); } } return -1; } void mitk::PointSet::ExecuteOperation( Operation* operation ) { int timeStep = -1; mitkCheckOperationTypeMacro(PointOperation, operation, pointOp); if ( pointOp ) { timeStep = this->GetTimeSlicedGeometry() ->MSToTimeStep( pointOp->GetTimeInMS() ); } if ( timeStep < 0 ) { MITK_ERROR << "Time step (" << timeStep << ") outside of PointSet time bounds" << std::endl; return; } switch (operation->GetOperationType()) { case OpNOTHING: break; case OpINSERT://inserts the point at the given position and selects it. { int position = pointOp->GetIndex(); PointType pt; pt.CastFrom(pointOp->GetPoint()); //transfer from world to index coordinates mitk::Geometry3D* geometry = this->GetGeometry( timeStep ); if (geometry == NULL) { MITK_INFO<<"GetGeometry returned NULL!\n"; return; } geometry->WorldToIndex(pt, pt); m_PointSetSeries[timeStep]->GetPoints()->InsertElement(position, pt); PointDataType pointData = { pointOp->GetIndex(), pointOp->GetSelected(), pointOp->GetPointType() }; m_PointSetSeries[timeStep]->GetPointData() ->InsertElement(position, pointData); this->Modified(); //boundingbox has to be computed m_CalculateBoundingBox = true; this->InvokeEvent( PointSetAddEvent() ); this->OnPointSetChange(); } break; case OpMOVE://moves the point given by index { PointType pt; pt.CastFrom(pointOp->GetPoint()); //transfer from world to index coordinates this->GetGeometry( timeStep )->WorldToIndex(pt, pt); // Copy new point into container m_PointSetSeries[timeStep]->SetPoint(pointOp->GetIndex(), pt); // Insert a default point data object to keep the containers in sync // (if no point data object exists yet) PointDataType pointData; if ( !m_PointSetSeries[timeStep]->GetPointData( pointOp->GetIndex(), &pointData ) ) { m_PointSetSeries[timeStep]->SetPointData( pointOp->GetIndex(), pointData ); } this->OnPointSetChange(); this->Modified(); //boundingbox has to be computed anyway m_CalculateBoundingBox = true; this->InvokeEvent( PointSetMoveEvent() ); } break; case OpREMOVE://removes the point at given by position { m_PointSetSeries[timeStep]->GetPoints()->DeleteIndex((unsigned)pointOp->GetIndex()); m_PointSetSeries[timeStep]->GetPointData()->DeleteIndex((unsigned)pointOp->GetIndex()); this->OnPointSetChange(); this->Modified(); //boundingbox has to be computed anyway m_CalculateBoundingBox = true; this->InvokeEvent( PointSetRemoveEvent() ); } break; case OpSELECTPOINT://select the given point { PointDataType pointData = {0, false, PTUNDEFINED}; m_PointSetSeries[timeStep]->GetPointData(pointOp->GetIndex(), &pointData); pointData.selected = true; m_PointSetSeries[timeStep]->SetPointData(pointOp->GetIndex(), pointData); this->Modified(); } break; case OpDESELECTPOINT://unselect the given point { PointDataType pointData = {0, false, PTUNDEFINED}; m_PointSetSeries[timeStep]->GetPointData(pointOp->GetIndex(), &pointData); pointData.selected = false; m_PointSetSeries[timeStep]->SetPointData(pointOp->GetIndex(), pointData); this->Modified(); } break; case OpSETPOINTTYPE: { PointDataType pointData = {0, false, PTUNDEFINED}; m_PointSetSeries[timeStep]->GetPointData(pointOp->GetIndex(), &pointData); pointData.pointSpec = pointOp->GetPointType(); m_PointSetSeries[timeStep]->SetPointData(pointOp->GetIndex(), pointData); this->Modified(); } break; case OpMOVEPOINTUP: // swap content of point with ID pointOp->GetIndex() with the point preceding it in the container // move point position within the pointset { PointIdentifier currentID = pointOp->GetIndex(); /* search for point with this id and point that precedes this one in the data container */ PointsContainer::STLContainerType points = m_PointSetSeries[timeStep]->GetPoints()->CastToSTLContainer(); PointsContainer::STLContainerType::iterator it = points.find(currentID); if (it == points.end()) // ID not found break; if (it == points.begin()) // we are at the first element, there is no previous element break; /* get and cache current point & pointdata and previous point & pointdata */ --it; PointIdentifier prevID = it->first; if (this->SwapPointContents(prevID, currentID, timeStep) == true) this->Modified(); } break; case OpMOVEPOINTDOWN: // move point position within the pointset { PointIdentifier currentID = pointOp->GetIndex(); /* search for point with this id and point that succeeds this one in the data container */ PointsContainer::STLContainerType points = m_PointSetSeries[timeStep]->GetPoints()->CastToSTLContainer(); PointsContainer::STLContainerType::iterator it = points.find(currentID); if (it == points.end()) // ID not found break; ++it; if (it == points.end()) // ID is already the last element, there is no succeeding element break; /* get and cache current point & pointdata and previous point & pointdata */ PointIdentifier nextID = it->first; if (this->SwapPointContents(nextID, currentID, timeStep) == true) this->Modified(); } break; default: itkWarningMacro("mitkPointSet could not understrand the operation. Please check!"); break; } //to tell the mappers, that the data is modified and has to be updated //only call modified if anything is done, so call in cases //this->Modified(); mitk::OperationEndEvent endevent(operation); ((const itk::Object*)this)->InvokeEvent(endevent); //*todo has to be done here, cause of update-pipeline not working yet // As discussed lately, don't mess with the rendering from inside data structures //mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::PointSet::UpdateOutputInformation() { if ( this->GetSource( ) ) { this->GetSource( )->UpdateOutputInformation( ); } // // first make sure, that the associated time sliced geometry has // the same number of geometry 3d's as PointSets are present // mitk::TimeSlicedGeometry* timeGeometry = GetTimeSlicedGeometry(); if ( timeGeometry->GetTimeSteps() != m_PointSetSeries.size() ) { itkExceptionMacro(<<"timeGeometry->GetTimeSteps() != m_PointSetSeries.size() -- use Initialize(timeSteps) with correct number of timeSteps!"); } // This is needed to detect zero objects mitk::ScalarType nullpoint[]={0,0,0,0,0,0}; BoundingBox::BoundsArrayType itkBoundsNull(nullpoint); // // Iterate over the PointSets and update the Geometry // information of each of the items. // if (m_CalculateBoundingBox) { for ( unsigned int i = 0 ; i < m_PointSetSeries.size() ; ++i ) { const DataType::BoundingBoxType *bb = m_PointSetSeries[i]->GetBoundingBox(); BoundingBox::BoundsArrayType itkBounds = bb->GetBounds(); if ( m_PointSetSeries[i].IsNull() || (m_PointSetSeries[i]->GetNumberOfPoints() == 0) || (itkBounds == itkBoundsNull) ) { itkBounds = itkBoundsNull; continue; } // Ensure minimal bounds of 1.0 in each dimension for ( unsigned int j = 0; j < 3; ++j ) { if ( itkBounds[j*2+1] - itkBounds[j*2] < 1.0 ) { BoundingBox::CoordRepType center = (itkBounds[j*2] + itkBounds[j*2+1]) / 2.0; itkBounds[j*2] = center - 0.5; itkBounds[j*2+1] = center + 0.5; } } this->GetGeometry(i)->SetBounds(itkBounds); } m_CalculateBoundingBox = false; } this->GetTimeSlicedGeometry()->UpdateInformation(); } void mitk::PointSet::SetRequestedRegionToLargestPossibleRegion() { } bool mitk::PointSet::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } bool mitk::PointSet::VerifyRequestedRegion() { return true; } void mitk::PointSet::SetRequestedRegion( itk::DataObject * ) { } void mitk::PointSet::PrintSelf( std::ostream& os, itk::Indent indent ) const { Superclass::PrintSelf(os, indent); os << indent << "Number timesteps: " << m_PointSetSeries.size() << "\n"; unsigned int i = 0; for (PointSetSeries::const_iterator it = m_PointSetSeries.begin(); it != m_PointSetSeries.end(); ++it) { os << indent << "Timestep " << i++ << ": \n"; MeshType::Pointer ps = *it; itk::Indent nextIndent = indent.GetNextIndent(); ps->Print(os, nextIndent); MeshType::PointsContainer* points = ps->GetPoints(); MeshType::PointDataContainer* datas = ps->GetPointData(); MeshType::PointDataContainer::Iterator dataIterator = datas->Begin(); for (MeshType::PointsContainer::Iterator pointIterator = points->Begin(); pointIterator != points->End(); ++pointIterator, ++dataIterator) { os << nextIndent << "Point " << pointIterator->Index() << ": ["; os << pointIterator->Value().GetElement(0); for (unsigned int i = 1; i < PointType::GetPointDimension(); ++i) { os << ", " << pointIterator->Value().GetElement(i); } os << "]"; os << ", selected: " << dataIterator->Value().selected << ", point spec: " << dataIterator->Value().pointSpec << "\n"; } } } bool mitk::PointSet::SwapPointContents(PointIdentifier id1, PointIdentifier id2, int timeStep) { /* search and cache contents */ PointType p1; if (m_PointSetSeries[timeStep]->GetPoint(id1, &p1) == false) return false; PointDataType data1; if (m_PointSetSeries[timeStep]->GetPointData(id1, &data1) == false) return false; PointType p2; if (m_PointSetSeries[timeStep]->GetPoint(id2, &p2) == false) return false; PointDataType data2; if (m_PointSetSeries[timeStep]->GetPointData(id2, &data2) == false) return false; /* now swap contents */ m_PointSetSeries[timeStep]->SetPoint(id1, p2); m_PointSetSeries[timeStep]->SetPointData(id1, data2); m_PointSetSeries[timeStep]->SetPoint(id2, p1); m_PointSetSeries[timeStep]->SetPointData(id2, data1); return true; } diff --git a/Core/Code/DataManagement/mitkPointSet.h b/Core/Code/DataManagement/mitkPointSet.h index 2b701dce27..c868f44b30 100755 --- a/Core/Code/DataManagement/mitkPointSet.h +++ b/Core/Code/DataManagement/mitkPointSet.h @@ -1,273 +1,274 @@ /*========================================================================= 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 MITKPointSet_H_HEADER_INCLUDED #define MITKPointSet_H_HEADER_INCLUDED #include "mitkBaseData.h" #include #include namespace mitk { /** * \brief Data structure which stores a set of points. Superclass of * mitk::Mesh. * * 3D points are grouped within a point set; for time resolved usage, one point * set is created and maintained per time step. A point entry consists of the * point coordinates and point data. * * The point data includes a point ID (unique identifier to address this point * within the point set), the selection state of the point and the type of * the point. * * For further information about different point types see * mitk::PointSpecificationType in mitkVector.h. * * Inserting a point is accompanied by an event, containing an index. The new * point is inserted into the list at the specified position. At the same time * an internal ID is generated and stored for the point. Points at specific time * steps are accessed by specifying the time step number (which defaults to 0). * * The points of itk::PointSet stores the points in a pointContainer * (MapContainer). The points are best accessed by using a ConstIterator (as * defined in MapContainer); avoid access via index. * * The class internally uses an itk::Mesh for each time step, because * mitk::Mesh is derived from mitk::PointSet and needs the itk::Mesh structure * which is also derived from itk::PointSet. Thus several typedefs which seem * to be in wrong place, are declared here (for example SelectedLinesType). * * \section mitkPointSetDisplayOptions * * The default mappers for this data structure are mitk::PointSetGLMapper2D and * mitk::PointSetVtkMapper3D. See these classes for display options which can * can be set via properties. * * \section Events * * PointSet issues the following events, for which observers can register * (the below events are grouped into a class hierarchy as indicated by * identation level; e.g. PointSetSizeChangeEvent comprises PointSetAddEvent * and PointSetRemoveEvent): * * * PointSetEvent subsumes all PointSet events * PointSetMoveEvent issued when a point of the PointSet is moved * PointSetSizeChangeEvent subsumes add and remove events * PointSetAddEvent issued when a point is added to the PointSet * PointSetRemoveEvent issued when a point is removed from the PointSet * * \ingroup PSIO * \ingroup Data */ class MITK_CORE_EXPORT PointSet : public BaseData { public: mitkClassMacro(PointSet, BaseData); itkNewMacro(Self); - + mitkCloneMacro(PointSet); typedef mitk::ScalarType CoordinateType; typedef mitk::ScalarType InterpolationWeightType; static const unsigned int PointDimension = 3; static const unsigned int MaxTopologicalDimension = 3; /** * \brief struct for data of a point */ struct PointDataType { unsigned int id; //to give the point a special ID bool selected; //information about if the point is selected mitk::PointSpecificationType pointSpec; //specifies the type of the point }; /** * \brief cellDataType, that stores all indexes of the lines, that are * selected e.g.: points A,B and C.Between A and B there is a line with * index 0. If vector of cellData contains 1 and 2, then the lines between * B and C and C and A is selected. */ typedef std::vector SelectedLinesType; typedef SelectedLinesType::iterator SelectedLinesIter; struct CellDataType { //used to set the whole cell on selected bool selected; //indexes of selected lines. 0 is between pointId 0 and 1 SelectedLinesType selectedLines; //is the polygon already finished and closed bool closed; }; typedef itk::DefaultDynamicMeshTraits< PointDataType, PointDimension, MaxTopologicalDimension, CoordinateType, InterpolationWeightType, CellDataType > MeshTraits; typedef itk::Mesh MeshType; typedef MeshType DataType; typedef DataType::PointType PointType; typedef DataType::PointIdentifier PointIdentifier; typedef DataType::PointsContainer PointsContainer; typedef DataType::PointsContainerIterator PointsIterator; typedef DataType::PointsContainer::ConstIterator PointsConstIterator; typedef DataType::PointDataContainer PointDataContainer; typedef DataType::PointDataContainerIterator PointDataIterator; virtual void Expand( unsigned int timeSteps ); /** \brief executes the given Operation */ virtual void ExecuteOperation(Operation* operation); /** \brief returns the current size of the point-list */ virtual int GetSize( unsigned int t = 0 ) const; virtual unsigned int GetPointSetSeriesSize() const; /** \brief returns the pointset */ virtual DataType::Pointer GetPointSet( int t = 0 ) const; /** * \brief Get the point with ID id in world coordinates * * check if the ID exists. If it doesn't exist, then return 0,0,0 */ PointType GetPoint( PointIdentifier id, int t = 0 ) const; /** * \brief Get the point with ID id in world coordinates * * If a point exists for the ID id, the point is returned in the parameter point * and the method returns true. If the ID does not exist, the method returns false */ bool GetPointIfExists( PointIdentifier id, PointType* point, int t = 0 ) const; /** * \brief Set the given point in world coordinate system into the itkPointSet. */ void SetPoint( PointIdentifier id, PointType point, int t = 0 ); /** * \brief Set the given point in world coordinate system with the given PointSpecificationType */ void SetPoint( PointIdentifier id, PointType point, PointSpecificationType spec, int t = 0 ); /** * \brief Set the given point in world coordinate system into the itkPointSet. */ void InsertPoint( PointIdentifier id, PointType point, int t = 0 ); /** * \brief Set the given point in world coordinate system with given PointSpecificationType */ void InsertPoint( PointIdentifier id, PointType point, PointSpecificationType spec, int t ); /** * \brief Swap a point at the given position (id) with the upper point (moveUpwards=true) or with the lower point (moveUpwards=false). * If upper or lower index does not exist false is returned, if swap was successful true. */ bool SwapPointPosition( PointIdentifier id, bool moveUpwards, int t = 0 ); /** * \brief searches a selected point and returns the id of that point. * If no point is found, then -1 is returned */ virtual int SearchSelectedPoint( int t = 0 ) const; /** \brief returns true if a point exists at this position */ virtual bool IndexExists( int position, int t = 0 ) const; /** \brief to get the state selected/unselected of the point on the * position */ virtual bool GetSelectInfo( int position, int t = 0 ) const; virtual void SetSelectInfo( int position, bool selected, int t = 0 ); /** \brief to get the type of the point at the position and the moment */ virtual PointSpecificationType GetSpecificationTypeInfo( int position, int t ) const; /** \brief returns the number of selected points */ virtual int GetNumberOfSelected( int t = 0 ) const; /** * \brief searches a point in the list == point +/- distance * * \param point is in world coordinates. * \param distance is in mm. * returns -1 if no point is found * or the position in the list of the first match */ int SearchPoint( Point3D point, float distance, int t = 0 ) const; virtual bool IsEmptyTimeStep(unsigned int t) const; //virtual methods, that need to be implemented virtual void UpdateOutputInformation(); virtual void SetRequestedRegionToLargestPossibleRegion(); virtual bool RequestedRegionIsOutsideOfTheBufferedRegion(); virtual bool VerifyRequestedRegion(); virtual void SetRequestedRegion(itk::DataObject *data); //Method for subclasses virtual void OnPointSetChange(){}; protected: PointSet(); + PointSet(const PointSet &other); virtual ~PointSet(); virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; ///< print content of the object to os virtual void ClearData(); virtual void InitializeEmpty(); /** \brief swaps point coordinates and point data of the points with identifiers id1 and id2 */ bool SwapPointContents(PointIdentifier id1, PointIdentifier id2, int t = 0 ); typedef std::vector< DataType::Pointer > PointSetSeries; PointSetSeries m_PointSetSeries; /** * @brief flag to indicate the right time to call SetBounds **/ bool m_CalculateBoundingBox; }; itkEventMacro( PointSetEvent, itk::AnyEvent ); itkEventMacro( PointSetMoveEvent, PointSetEvent ); itkEventMacro( PointSetSizeChangeEvent, PointSetEvent ); itkEventMacro( PointSetAddEvent, PointSetSizeChangeEvent ); itkEventMacro( PointSetRemoveEvent, PointSetSizeChangeEvent ); itkEventMacro( PointSetExtendTimeRangeEvent, PointSetEvent ); } // namespace mitk #endif /* MITKPointSet_H_HEADER_INCLUDED */ diff --git a/Core/Code/DataManagement/mitkSlicedData.cpp b/Core/Code/DataManagement/mitkSlicedData.cpp index 7e7a5c36bd..3f3cf38351 100644 --- a/Core/Code/DataManagement/mitkSlicedData.cpp +++ b/Core/Code/DataManagement/mitkSlicedData.cpp @@ -1,346 +1,354 @@ /*========================================================================= 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 "mitkSlicedData.h" #include "mitkBaseProcess.h" #include mitk::SlicedData::SlicedData() : m_UseLargestPossibleRegion(false) { unsigned int i; for(i=0;i<4;++i) { m_LargestPossibleRegion.SetIndex(i, 0); m_LargestPossibleRegion.SetSize (i, 1); } } +mitk::SlicedData::SlicedData( const SlicedData &other ): BaseData(other), +m_UseLargestPossibleRegion(other.m_UseLargestPossibleRegion), +m_LargestPossibleRegion(other.m_LargestPossibleRegion), +m_RequestedRegion(other.m_RequestedRegion), +m_BufferedRegion(other.m_BufferedRegion) +{ + +} mitk::SlicedData::~SlicedData() { } void mitk::SlicedData::UpdateOutputInformation() { Superclass::UpdateOutputInformation(); if (this->GetSource() == false) // If we don't have a source, then let's make our Image // span our buffer { m_UseLargestPossibleRegion = true; } // Now we should know what our largest possible region is. If our // requested region was not set yet, (or has been set to something // invalid - with no data in it ) then set it to the largest possible // region. if ( ! m_RequestedRegionInitialized) { this->SetRequestedRegionToLargestPossibleRegion(); m_RequestedRegionInitialized = true; } m_LastRequestedRegionWasOutsideOfTheBufferedRegion = 0; } void mitk::SlicedData::PrepareForNewData() { if ( GetUpdateMTime() < GetPipelineMTime() || GetDataReleased() ) { ReleaseData(); } } void mitk::SlicedData::SetRequestedRegionToLargestPossibleRegion() { m_UseLargestPossibleRegion = true; if(GetGeometry()==NULL) return; unsigned int i; const RegionType::IndexType & index = GetLargestPossibleRegion().GetIndex(); const RegionType::SizeType & size = GetLargestPossibleRegion().GetSize(); for(i=0;i(requestedRegionSize[4]); if(requestedRegionSize[3] == largestPossibleRegionSize[3]) { for (; c< cEnd; ++c) if(IsChannelSet(c)==false) return true; return false; } // are whole volumes requested? int t, tEnd; t=requestedRegionIndex[3]; tEnd=t+static_cast(requestedRegionSize[3]); if(requestedRegionSize[2] == largestPossibleRegionSize[2]) { for (; c< cEnd; ++c) for (; t< tEnd; ++t) if(IsVolumeSet(t, c)==false) return true; return false; } // ok, only slices are requested. Check if they are available. int s, sEnd; s=requestedRegionIndex[2]; sEnd=s+static_cast(requestedRegionSize[2]); for (; c< cEnd; ++c) for (; t< tEnd; ++t) for (; s< sEnd; ++s) if(IsSliceSet(s, t, c)==false) return true; return false; } bool mitk::SlicedData::VerifyRequestedRegion() { if(GetTimeSlicedGeometry() == NULL) return false; unsigned int i; // Is the requested region within the LargestPossibleRegion? // Note that the test is indeed against the largest possible region // rather than the buffered region; see DataObject::VerifyRequestedRegion. const IndexType &requestedRegionIndex = m_RequestedRegion.GetIndex(); const IndexType &largestPossibleRegionIndex = GetLargestPossibleRegion().GetIndex(); const SizeType& requestedRegionSize = m_RequestedRegion.GetSize(); const SizeType& largestPossibleRegionSize = GetLargestPossibleRegion().GetSize(); for (i=0; i< RegionDimension; ++i) { if ( (requestedRegionIndex[i] < largestPossibleRegionIndex[i]) || ((requestedRegionIndex[i] + static_cast(requestedRegionSize[i])) > (largestPossibleRegionIndex[i]+static_cast(largestPossibleRegionSize[i])))) { return false; } } return true; } void mitk::SlicedData::SetRequestedRegion(itk::DataObject *data) { m_UseLargestPossibleRegion=false; mitk::SlicedData *slicedData; slicedData = dynamic_cast(data); if (slicedData) { m_RequestedRegion = slicedData->GetRequestedRegion(); m_RequestedRegionInitialized = true; } else { // pointer could not be cast back down itkExceptionMacro( << "mitk::SlicedData::SetRequestedRegion(DataObject*) cannot cast " << typeid(data).name() << " to " << typeid(SlicedData*).name() ); } } void mitk::SlicedData::SetRequestedRegion(SlicedData::RegionType *region) { m_UseLargestPossibleRegion=false; if(region!=NULL) { m_RequestedRegion = *region; m_RequestedRegionInitialized = true; } else { // pointer could not be cast back down itkExceptionMacro( << "mitk::SlicedData::SetRequestedRegion(SlicedData::RegionType*) cannot cast " << typeid(region).name() << " to " << typeid(SlicedData*).name() ); } } void mitk::SlicedData::CopyInformation(const itk::DataObject *data) { // Standard call to the superclass' method Superclass::CopyInformation(data); const mitk::SlicedData *slicedData; slicedData = dynamic_cast(data); if (slicedData) { m_LargestPossibleRegion = slicedData->GetLargestPossibleRegion(); } else { // pointer could not be cast back down itkExceptionMacro( << "mitk::SlicedData::CopyInformation(const DataObject *data) cannot cast " << typeid(data).name() << " to " << typeid(SlicedData*).name() ); } } //const mitk::Geometry2D* mitk::SlicedData::GetGeometry2D(int s, int t) const //{ // const_cast(this)->SetRequestedRegionToLargestPossibleRegion(); // // const_cast(this)->UpdateOutputInformation(); // // return GetSlicedGeometry(t)->GetGeometry2D(s); //} // mitk::SlicedGeometry3D* mitk::SlicedData::GetSlicedGeometry(unsigned int t) const { if(GetTimeSlicedGeometry() == NULL) return NULL; return dynamic_cast(GetTimeSlicedGeometry()->GetGeometry3D(t)); } const mitk::SlicedGeometry3D* mitk::SlicedData::GetUpdatedSlicedGeometry(unsigned int t) { SetRequestedRegionToLargestPossibleRegion(); UpdateOutputInformation(); return GetSlicedGeometry(t); } void mitk::SlicedData::SetGeometry(Geometry3D* aGeometry3D) { if(aGeometry3D!=NULL) { TimeSlicedGeometry::Pointer timeSlicedGeometry = dynamic_cast(aGeometry3D); if(timeSlicedGeometry.IsNull()) { SlicedGeometry3D::Pointer slicedGeometry = dynamic_cast(aGeometry3D); if(slicedGeometry.IsNull()) { Geometry2D* geometry2d = dynamic_cast(aGeometry3D); if(geometry2d!=NULL) { if((GetSlicedGeometry()->GetGeometry2D(0)==geometry2d) && (GetSlicedGeometry()->GetSlices()==1)) return; slicedGeometry = SlicedGeometry3D::New(); slicedGeometry->InitializeEvenlySpaced(geometry2d, 1); } else { slicedGeometry = SlicedGeometry3D::New(); PlaneGeometry::Pointer planeGeometry = PlaneGeometry::New(); planeGeometry->InitializeStandardPlane(aGeometry3D); slicedGeometry->InitializeEvenlySpaced(planeGeometry, (unsigned int)(aGeometry3D->GetExtent(2))); } } assert(slicedGeometry.IsNotNull()); timeSlicedGeometry = TimeSlicedGeometry::New(); timeSlicedGeometry->InitializeEvenlyTimed(slicedGeometry, 1); } Superclass::SetGeometry(timeSlicedGeometry); } else { if(GetGeometry()==NULL) return; Superclass::SetGeometry(NULL); } } void mitk::SlicedData::SetSpacing(const float aSpacing[3]) { this->SetSpacing((mitk::Vector3D)aSpacing); } void mitk::SlicedData::SetOrigin(const mitk::Point3D& origin) { mitk::TimeSlicedGeometry* timeSlicedGeometry = GetTimeSlicedGeometry(); assert(timeSlicedGeometry!=NULL); mitk::SlicedGeometry3D* slicedGeometry; unsigned int steps = timeSlicedGeometry->GetTimeSteps(); for(unsigned int timestep = 0; timestep < steps; ++timestep) { slicedGeometry = GetSlicedGeometry(timestep); if(slicedGeometry != NULL) { slicedGeometry->SetOrigin(origin); if(slicedGeometry->GetEvenlySpaced()) { mitk::Geometry2D* geometry2D = slicedGeometry->GetGeometry2D(0); geometry2D->SetOrigin(origin); slicedGeometry->InitializeEvenlySpaced(geometry2D, slicedGeometry->GetSlices()); } } if(GetTimeSlicedGeometry()->GetEvenlyTimed()) { GetTimeSlicedGeometry()->InitializeEvenlyTimed(slicedGeometry, steps); break; } } } void mitk::SlicedData::SetSpacing(mitk::Vector3D aSpacing) { mitk::TimeSlicedGeometry* timeSlicedGeometry = GetTimeSlicedGeometry(); assert(timeSlicedGeometry!=NULL); mitk::SlicedGeometry3D* slicedGeometry; unsigned int steps = timeSlicedGeometry->GetTimeSteps(); for(unsigned int timestep = 0; timestep < steps; ++timestep) { slicedGeometry = GetSlicedGeometry(timestep); if(slicedGeometry != NULL) { slicedGeometry->SetSpacing(aSpacing); } if(GetTimeSlicedGeometry()->GetEvenlyTimed()) { GetTimeSlicedGeometry()->InitializeEvenlyTimed(slicedGeometry, steps); break; } } } diff --git a/Core/Code/DataManagement/mitkSlicedData.h b/Core/Code/DataManagement/mitkSlicedData.h index eb8deb2faa..1320cd43f1 100644 --- a/Core/Code/DataManagement/mitkSlicedData.h +++ b/Core/Code/DataManagement/mitkSlicedData.h @@ -1,222 +1,223 @@ /*========================================================================= 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 SLICEDDATA_H_HEADER_INCLUDED #define SLICEDDATA_H_HEADER_INCLUDED #include "mitkCommon.h" #include "mitkBaseData.h" #include "mitkTimeSlicedGeometry.h" #include "mitkSlicedGeometry3D.h" #include "itkIndex.h" #include "itkOffset.h" #include "itkSize.h" #include "itkImageRegion.h" namespace mitk { class SlicedGeometry3D; //##Documentation //## @brief Super class of data objects consisting of slices //## //## Super class of data objects consisting of slices, e.g., images or a stack //## of contours. (GetGeometry will return a Geometry3D containing Geometry2D //## objects). //## //## SlicedData-objects have geometries of type SlicedGeometry3D or sub-classes. //## @ingroup Data class MITK_CORE_EXPORT SlicedData : public BaseData { public: mitkClassMacro(SlicedData, BaseData); itkStaticConstMacro(RegionDimension, unsigned int, 5); /** Region typedef support. A region is used to specify a subset of a @a SlicedData. */ typedef itk::ImageRegion RegionType; /** Index typedef support. An index is used to access pixel values. */ typedef itk::Index IndexType; typedef IndexType::IndexValueType IndexValueType; /** Offset typedef support. An offset represent relative position * between indices. */ typedef itk::Offset OffsetType; typedef OffsetType::OffsetValueType OffsetValueType; /** Size typedef support. A size is used to define region bounds. */ typedef itk::Size SizeType; typedef SizeType::SizeValueType SizeValueType; //##Documentation //## Update the information for this DataObject so that it can be used as //## an output of a ProcessObject. This method is used in the pipeline //## mechanism to propagate information and initialize the meta data //## associated with a itk::DataObject. Any implementation of this method //## in a derived class of itk::DataObject is assumed to call its source's //## ProcessObject::UpdateOutputInformation() which determines modified //## times, LargestPossibleRegions, and any extra meta data like spacing, //## origin, etc. virtual void UpdateOutputInformation(); virtual void PrepareForNewData(); //##Documentation //## Set the RequestedRegion to the LargestPossibleRegion. This forces a //## filter to produce all of the output in one execution (i.e. not //## streaming) on the next call to Update(). virtual void SetRequestedRegionToLargestPossibleRegion(); //##Documentation //## Determine whether the RequestedRegion is outside of the //## BufferedRegion. This method returns true if the RequestedRegion is //## outside the BufferedRegion (true if at least one pixel is outside). //## This is used by the pipeline mechanism to determine whether a filter //## needs to re-execute in order to satisfy the current request. If the //## current RequestedRegion is already inside the BufferedRegion from the //## previous execution (and the current filter is up to date), then a //## given filter does not need to re-execute virtual bool RequestedRegionIsOutsideOfTheBufferedRegion(); //##Documentation //## @brief Verify that the RequestedRegion is within the //## LargestPossibleRegion. //## //## Verify that the RequestedRegion is within the LargestPossibleRegion. //## If the RequestedRegion is not within the LargestPossibleRegion, //## then the filter cannot possibly satisfy the request. This method //## returns true if the request can be satisfied (even if it will be //## necessary to process the entire LargestPossibleRegion) and //## returns false otherwise. This method is used by //## PropagateRequestedRegion(). PropagateRequestedRegion() throws a //## InvalidRequestedRegionError exception if the requested region is //## not within the LargestPossibleRegion. virtual bool VerifyRequestedRegion(); //##Documentation //## Set the requested region from this data object to match the requested //## region of the data object passed in as a parameter. This method is //## implemented in the concrete subclasses of DataObject. virtual void SetRequestedRegion(itk::DataObject *data); //##Documentation //## Set the requested region from this data object to match the requested //## region of the data object passed in as a parameter. This method is //## implemented in the concrete subclasses of DataObject. virtual void SetRequestedRegion(SlicedData::RegionType *region); const RegionType& GetLargestPossibleRegion() const { return m_LargestPossibleRegion; } //##Documentation //## Get the region object that defines the size and starting index //## for the region of the image requested (i.e., the region of the //## image to be operated on by a filter). virtual const RegionType& GetRequestedRegion() const { return m_RequestedRegion; } virtual bool IsSliceSet(int s = 0, int t = 0, int n = 0) const = 0; virtual bool IsVolumeSet(int t = 0, int n = 0) const = 0; virtual bool IsChannelSet(int n = 0) const = 0; virtual void CopyInformation(const itk::DataObject *data); //##Documentation //## @brief Get the number of channels unsigned int GetNumberOfChannels() const { return m_LargestPossibleRegion.GetSize(4); } ////##Documentation ////## @brief Return the Geometry2D of the slice (@a s, @a t). ////## ////## The method does not simply call GetGeometry()->GetGeometry2D(). Before doing this, it ////## makes sure that the Geometry2D is up-to-date before returning it (by ////## setting the update extent appropriately and calling ////## UpdateOutputInformation). ////## ////## @warning GetGeometry2D not yet completely implemented. ////## @todo Appropriate setting of the update extent is missing. //virtual const mitk::Geometry2D* GetGeometry2D(int s, int t=0) const; //##Documentation //## @brief Convenience access method for the geometry, which is of type SlicedGeometry3D (or a sub-class of it). //## //## @em No update will be called. Normally used in GenerateOutputInformation of //## subclasses of BaseProcess. SlicedGeometry3D* GetSlicedGeometry(unsigned int t=0) const; //##Documentation //## @brief Convenience access method for the geometry, which is of type SlicedGeometry3D (or a sub-class of it). //## //## The method does not simply return the value of the m_Geometry3D member. //## Before doing this, it makes sure that the Geometry3D is up-to-date before //## returning it (by setting the update extent appropriately and calling //## UpdateOutputInformation). //## //## @warning GetGeometry not yet completely implemented. //## @todo Appropriate setting of the update extent is missing. const SlicedGeometry3D* GetUpdatedSlicedGeometry(unsigned int t=0); //##Documentation //## @brief Set the Geometry3D of the data, which will be referenced (not copied!). It //## has to be a sub-class of SlicedGeometry3D. //## //## @warning This method will normally be called internally by the sub-class of SlicedData //## during initialization. virtual void SetGeometry(Geometry3D* aGeometry3D); //##Documentation //## @brief Convenience method for setting the origin of //## the SlicedGeometry3D instances of all time steps //## //## In case the SlicedGeometry3D is evenly spaced, //## the origin of the first slice is set to \a origin. //## \sa mitk::BaseData::SetOrigin virtual void SetOrigin(const Point3D& origin); //##Documentation //## @brief Convenience method for setting the spacing of //## the SlicedGeometry3D instances of all time steps virtual void SetSpacing(const float aSpacing[3]); //##Documentation //## @brief Convenience method for setting the spacing of //## the SlicedGeometry3D instances of all time steps virtual void SetSpacing(mitk::Vector3D aSpacing); protected: SlicedData(); + SlicedData(const SlicedData &other); virtual ~SlicedData(); RegionType m_LargestPossibleRegion; RegionType m_RequestedRegion; RegionType m_BufferedRegion; bool m_UseLargestPossibleRegion; }; } // namespace mitk #endif /* SLICEDDATA_H_HEADER_INCLUDED */ diff --git a/Core/Code/DataManagement/mitkSurface.cpp b/Core/Code/DataManagement/mitkSurface.cpp index 7553de5c43..c769ff7c15 100644 --- a/Core/Code/DataManagement/mitkSurface.cpp +++ b/Core/Code/DataManagement/mitkSurface.cpp @@ -1,362 +1,384 @@ /*========================================================================= 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 "mitkSurface.h" #include "mitkInteractionConst.h" #include "mitkSurfaceOperation.h" #include +#include "vtkSmartPointer.h" #include mitk::Surface::Surface() : m_CalculateBoundingBox( false ) { this->InitializeEmpty(); } +mitk::Surface::Surface(const mitk::Surface& other) : BaseData(other), +m_CalculateBoundingBox(other.m_CalculateBoundingBox), +m_RequestedRegion(other.m_RequestedRegion), +m_LargestPossibleRegion(other.m_LargestPossibleRegion) +{ + if(other.m_PolyDataSeries.at(0) != NULL) + { + m_PolyDataSeries = std::vector(); + for ( VTKPolyDataSeries::const_iterator it = other.m_PolyDataSeries.begin(); it != other.m_PolyDataSeries.end(); ++it ) + { + vtkSmartPointer poly = vtkSmartPointer::New(); + poly->DeepCopy(*it); + m_PolyDataSeries.push_back(poly.GetPointer()); + } + } + else + { + this->InitializeEmpty(); + } +} + mitk::Surface::~Surface() { this->ClearData(); } void mitk::Surface::ClearData() { for ( VTKPolyDataSeries::iterator it = m_PolyDataSeries.begin(); it != m_PolyDataSeries.end(); ++it ) { if ( ( *it ) != NULL ) ( *it )->Delete(); } m_PolyDataSeries.clear(); Superclass::ClearData(); } void mitk::Surface::InitializeEmpty() { vtkPolyData* pdnull = NULL; m_PolyDataSeries.resize( 1, pdnull ); Superclass::InitializeTimeSlicedGeometry(1); m_Initialized = true; } void mitk::Surface::SetVtkPolyData( vtkPolyData* polydata, unsigned int t ) { // Adapt the size of the data vector if necessary this->Expand( t+1 ); if(m_PolyDataSeries[ t ] != NULL) { if ( m_PolyDataSeries[ t ] == polydata ) return; // we do not need the reference on the object any longer m_PolyDataSeries[ t ]->Delete(); } m_PolyDataSeries[ t ] = polydata; // call m_VtkPolyData->Register(NULL) to tell // the reference counting that we want to keep a // reference on the object if(m_PolyDataSeries[ t ] != NULL) { m_PolyDataSeries[ t ]->Register( NULL ); } this->Modified(); m_CalculateBoundingBox = true; } bool mitk::Surface::IsEmptyTimeStep(unsigned int t) const { if(!IsInitialized()) return false; vtkPolyData* polydata = const_cast(this)->GetVtkPolyData(t); return (polydata == NULL) || ( (polydata->GetNumberOfVerts() <= 0) && (polydata->GetNumberOfPolys() <= 0) && (polydata->GetNumberOfStrips() <= 0) && (polydata->GetNumberOfLines() <= 0) ); } vtkPolyData* mitk::Surface::GetVtkPolyData( unsigned int t ) { if ( t < m_PolyDataSeries.size() ) { vtkPolyData* polydata = m_PolyDataSeries[ t ]; if((polydata==NULL) && (GetSource().GetPointer()!=NULL)) { RegionType requestedregion; requestedregion.SetIndex(3, t); requestedregion.SetSize(3, 1); SetRequestedRegion(&requestedregion); GetSource()->Update(); } polydata = m_PolyDataSeries[ t ]; return polydata; } else return NULL; } void mitk::Surface::UpdateOutputInformation() { if ( this->GetSource() ) { this->GetSource()->UpdateOutputInformation(); } if ( ( m_CalculateBoundingBox ) && ( m_PolyDataSeries.size() > 0 ) ) CalculateBoundingBox(); else GetTimeSlicedGeometry()->UpdateInformation(); } void mitk::Surface::CalculateBoundingBox() { // // first make sure, that the associated time sliced geometry has // the same number of geometry 3d's as vtkPolyDatas are present // mitk::TimeSlicedGeometry* timeGeometry = GetTimeSlicedGeometry(); if ( timeGeometry->GetTimeSteps() != m_PolyDataSeries.size() ) { itkExceptionMacro(<<"timeGeometry->GetTimeSteps() != m_PolyDataSeries.size() -- use Initialize(timeSteps) with correct number of timeSteps!"); } // // Iterate over the vtkPolyDatas and update the Geometry // information of each of the items. // for ( unsigned int i = 0 ; i < m_PolyDataSeries.size() ; ++i ) { vtkPolyData* polyData = m_PolyDataSeries[ i ]; vtkFloatingPointType bounds[ ] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; if ( ( polyData != NULL ) && ( polyData->GetNumberOfPoints() > 0 ) ) { polyData->Update(); polyData->ComputeBounds(); polyData->GetBounds( bounds ); } mitk::Geometry3D::Pointer g3d = timeGeometry->GetGeometry3D( i ); assert( g3d.IsNotNull() ); g3d->SetFloatBounds( bounds ); } timeGeometry->UpdateInformation(); mitk::BoundingBox::Pointer bb = const_cast( timeGeometry->GetBoundingBox() ); itkDebugMacro( << "boundingbox min: "<< bb->GetMinimum()); itkDebugMacro( << "boundingbox max: "<< bb->GetMaximum()); m_CalculateBoundingBox = false; } void mitk::Surface::SetRequestedRegionToLargestPossibleRegion() { m_RequestedRegion = GetLargestPossibleRegion(); } bool mitk::Surface::RequestedRegionIsOutsideOfTheBufferedRegion() { RegionType::IndexValueType end = m_RequestedRegion.GetIndex(3)+m_RequestedRegion.GetSize(3); if(((RegionType::IndexValueType)m_PolyDataSeries.size())=0) && (m_RequestedRegion.GetIndex(3)+m_RequestedRegion.GetSize(3)<=m_PolyDataSeries.size()) ) return true; return false; } void mitk::Surface::SetRequestedRegion( itk::DataObject *data ) { mitk::Surface *surfaceData; surfaceData = dynamic_cast(data); if (surfaceData) { m_RequestedRegion = surfaceData->GetRequestedRegion(); } else { // pointer could not be cast back down itkExceptionMacro( << "mitk::Surface::SetRequestedRegion(DataObject*) cannot cast " << typeid(data).name() << " to " << typeid(Surface*).name() ); } } void mitk::Surface::SetRequestedRegion(Surface::RegionType *region) //by arin { if(region!=NULL) { m_RequestedRegion = *region; } else { // pointer could not be cast back down itkExceptionMacro( << "mitk::Surface::SetRequestedRegion(Surface::RegionType*) cannot cast " << typeid(region).name() << " to " << typeid(Surface*).name() ); } } void mitk::Surface::CopyInformation( const itk::DataObject * data) { Superclass::CopyInformation( data ); const mitk::Surface* surfaceData; surfaceData = dynamic_cast( data ); if ( surfaceData ) { m_LargestPossibleRegion = surfaceData->GetLargestPossibleRegion(); } else { // pointer could not be cast back down itkExceptionMacro( << "mitk::Surface::CopyInformation(const DataObject *data) cannot cast " << typeid(data).name() << " to " << typeid(surfaceData).name() ); } } void mitk::Surface::Update() { if ( GetSource() == NULL ) { for ( VTKPolyDataSeries::iterator it = m_PolyDataSeries.begin() ; it != m_PolyDataSeries.end() ; ++it ) { if ( ( *it ) != NULL ) ( *it )->Update(); } } Superclass::Update(); } void mitk::Surface::Expand( unsigned int timeSteps ) { // check if the vector is long enough to contain the new element // at the given position. If not, expand it with sufficient zero-filled elements. if ( timeSteps > m_PolyDataSeries.size() ) { Superclass::Expand( timeSteps ); vtkPolyData* pdnull = NULL; m_PolyDataSeries.resize( timeSteps, pdnull ); m_CalculateBoundingBox = true; } } void mitk::Surface::ExecuteOperation(Operation *operation) { switch ( operation->GetOperationType() ) { case OpSURFACECHANGED: mitk::SurfaceOperation* surfOp = dynamic_cast(operation); if( ! surfOp ) break; unsigned int time = surfOp->GetTimeStep(); if(m_PolyDataSeries[ time ] != NULL) { vtkPolyData* updatePoly = surfOp->GetVtkPolyData(); if( updatePoly ){ this->SetVtkPolyData( updatePoly, time ); this->CalculateBoundingBox(); } } break; } this->Modified(); } unsigned int mitk::Surface::GetSizeOfPolyDataSeries() const { return m_PolyDataSeries.size(); } void mitk::Surface::Graft( const DataObject* data ) { const Self* surface; try { surface = dynamic_cast( data ); } catch(...) { itkExceptionMacro( << "mitk::Surface::Graft cannot cast " << typeid(data).name() << " to " << typeid(const Self *).name() ); return; } if(!surface) { // pointer could not be cast back down itkExceptionMacro( << "mitk::Surface::Graft cannot cast " << typeid(data).name() << " to " << typeid(const Self *).name() ); return; } this->CopyInformation( data ); //clear list of PolyData's m_PolyDataSeries.clear(); // do copy for (unsigned int i=0; iGetSizeOfPolyDataSeries(); i++) { m_PolyDataSeries.push_back(vtkPolyData::New()); m_PolyDataSeries.back()->DeepCopy( const_cast(surface)->GetVtkPolyData( i ) ); //CopyStructure( const_cast(surface)->GetVtkPolyData( i ) ); } } void mitk::Surface::PrintSelf( std::ostream& os, itk::Indent indent ) const { Superclass::PrintSelf(os, indent); os << indent << "\nNumber PolyDatas: " << m_PolyDataSeries.size() << "\n"; unsigned int count = 0; for (VTKPolyDataSeries::const_iterator it = m_PolyDataSeries.begin(); it != m_PolyDataSeries.end(); ++it) { vtkPolyData* pd = *it; if(pd != NULL) { os << "\n"; os << indent << "PolyData at time step " << count << ". \n"; os << indent << "Number of cells " << pd->GetNumberOfCells() << ": \n"; os << indent << "Number of points " << pd->GetNumberOfPoints() << ": \n\n"; os << indent << "VTKPolyData : \n"; pd->Print(os); } else os << indent << "\nEmpty PolyData at time step " << count << ".\n"; count++; } } diff --git a/Core/Code/DataManagement/mitkSurface.h b/Core/Code/DataManagement/mitkSurface.h index 0608b10e22..7eeae09582 100644 --- a/Core/Code/DataManagement/mitkSurface.h +++ b/Core/Code/DataManagement/mitkSurface.h @@ -1,117 +1,116 @@ /*========================================================================= 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 MITKSURFACEDATA_H_HEADER_INCLUDED #define MITKSURFACEDATA_H_HEADER_INCLUDED #include "mitkBaseData.h" #include "itkImageRegion.h" class vtkPolyData; namespace mitk { //##Documentation //## @brief Class for storing surfaces (vtkPolyData) //## @ingroup Data class MITK_CORE_EXPORT Surface : public BaseData { protected: public: // not yet the best chioce of a region-type for surfaces, but it works for the time being typedef itk::ImageRegion< 5 > RegionType; mitkClassMacro(Surface, BaseData); - itkNewMacro(Self); + mitkCloneMacro(Surface); virtual void SetVtkPolyData(vtkPolyData* polydata, unsigned int t = 0); virtual vtkPolyData* GetVtkPolyData(unsigned int t = 0); virtual void UpdateOutputInformation(); virtual void SetRequestedRegionToLargestPossibleRegion(); virtual bool RequestedRegionIsOutsideOfTheBufferedRegion(); virtual bool VerifyRequestedRegion(); virtual void SetRequestedRegion(itk::DataObject *data); virtual void SetRequestedRegion(Surface::RegionType *region); virtual void CopyInformation(const itk::DataObject *data); virtual bool IsEmptyTimeStep(unsigned int t) const; unsigned int GetSizeOfPolyDataSeries() const; virtual void Update(); virtual void Expand( unsigned int timeSteps = 1 ); virtual void Graft( const DataObject* data ); const RegionType& GetLargestPossibleRegion() const { m_LargestPossibleRegion.SetIndex(3, 0); m_LargestPossibleRegion.SetSize(3, GetTimeSlicedGeometry()->GetTimeSteps()); return m_LargestPossibleRegion; } //##Documentation //## Get the region object that defines the size and starting index //## for the region of the image requested (i.e., the region of the //## image to be operated on by a filter). virtual const RegionType& GetRequestedRegion() const { return m_RequestedRegion; } void CalculateBoundingBox(); virtual void PrintSelf( std::ostream& os, itk::Indent indent ) const; virtual void ExecuteOperation(Operation *operation); protected: typedef std::vector< vtkPolyData* > VTKPolyDataSeries; Surface(); + Surface(const Surface& other); virtual ~Surface(); virtual void ClearData(); virtual void InitializeEmpty(); - VTKPolyDataSeries m_PolyDataSeries; - - mutable RegionType m_LargestPossibleRegion; - + //member variables + VTKPolyDataSeries m_PolyDataSeries; /// variable holds the poly datas of the surface + mutable RegionType m_LargestPossibleRegion; /// variable holds the largest possible region the surface is contained in RegionType m_RequestedRegion; - - bool m_CalculateBoundingBox; + bool m_CalculateBoundingBox; /// flag to calculate the bounding box }; } // namespace mitk #endif /* MITKSURFACEDATA_H_HEADER_INCLUDED */ diff --git a/Core/Code/DataManagement/mitkTimeSlicedGeometry.h b/Core/Code/DataManagement/mitkTimeSlicedGeometry.h index 6f2e098320..27726dad24 100644 --- a/Core/Code/DataManagement/mitkTimeSlicedGeometry.h +++ b/Core/Code/DataManagement/mitkTimeSlicedGeometry.h @@ -1,178 +1,178 @@ /*========================================================================= 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 TIMESLICEDGEOMETRY_H_HEADER_INCLUDED_C1EBD0AD #define TIMESLICEDGEOMETRY_H_HEADER_INCLUDED_C1EBD0AD #include "mitkGeometry3D.h" namespace mitk { //##Documentation //## @brief Describes a geometry consisting of several geometries which //## exist at different times. //## //## The geometry contains m_TimeSteps geometries, which can be accessed //## using GetGeometry3D(int t). To convert between world-time in //## milliseconds and the integer timestep-number use MSToTimeStep. //## The hull (in space and time) of the TimeSlicedGeometry contains all //## contained geometries. //## @warning The hull (i.e., transform, bounding-box and //## time-bounds) is only guaranteed to be up-to-date after calling //## UpdateInformation(). //## //## TimeSlicedGeometry and the associated Geometry3Ds have to be //## initialized in the method GenerateOutputInformation() of BaseProcess (or //## CopyInformation/ UpdateOutputInformation of BaseData, if possible, e.g., //## by analyzing pic tags in Image) subclasses. See also //## itk::ProcessObject::GenerateOutputInformation(), //## itk::DataObject::CopyInformation() and //## itk::DataObject::UpdateOutputInformation(). //## //## @ingroup Geometry class MITK_CORE_EXPORT TimeSlicedGeometry : public Geometry3D { public: mitkClassMacro(TimeSlicedGeometry, Geometry3D); itkNewMacro(Self); //##Documentation //## @brief Re-calculate the hull of the contained geometries. //## //## The transforms, bounding-box and time-bounds of this //## geometry (stored in members of the super-class Geometry3D) //## are re-calculated from the contained geometries. void UpdateInformation(); //##Documentation //## @brief Get the number of time-steps itkGetConstMacro(TimeSteps, unsigned int); //##Documentation //## @brief Set/Get whether the TimeSlicedGeometry is evenly-timed (m_EvenlyTimed) //## //## If (a) we don't have a Geometry3D stored for the requested time, //## (b) m_EvenlyTimed is activated and (c) the first geometry (t=0) //## is set, then we clone the geometry and set the m_TimeBounds accordingly. //## \sa GetGeometry3D itkGetConstMacro(EvenlyTimed, bool); virtual void SetEvenlyTimed(bool on = true); //##Documentation //## @brief Set the Geometry3D for time @a t virtual bool SetGeometry3D(mitk::Geometry3D* geometry3D, int t); //##Documentation //## @brief When switching from an Image Geometry to a normal Geometry (and the other way around), you have to change the origin as well (See Geometry Documentation)! This function will change the "isImageGeometry" bool flag and changes the origin respectively. virtual void ChangeImageGeometryConsideringOriginOffset( const bool isAnImageGeometry ); //##Documentation //## @brief Get the Geometry3D at time @a t virtual mitk::Geometry3D* GetGeometry3D(int t) const; //##Documentation //## @brief Test whether @a t is a valid time step virtual bool IsValidTime(int t) const; //##Documentation //## @brief Convert time in ms to a time step virtual int MSToTimeStep(mitk::ScalarType time_in_ms) const; //##Documentation //## @brief Convert time step to time in ms virtual mitk::ScalarType TimeStepToMS(int timestep) const; //##Documentation //## @brief Convert time step in the reference TimeSlicedGeometry to time step //## in this TimeSlicedGeometry. virtual int TimeStepToTimeStep(const mitk::TimeSlicedGeometry *referenceGeometry, int t) const; //##Documentation //## @brief Completely initialize this instance as evenly-timed with //## \a timeSteps geometries of type Geometry3D, each initialized by //## Geometry3D::Initialize(). virtual void InitializeEvenlyTimed(unsigned int timeSteps); //##Documentation //## @brief Completely initialize this instance as evenly-timed with //## \a timeSteps geometries identical to the provided Geometry3D //## except for the time bounds virtual void InitializeEvenlyTimed(mitk::Geometry3D* geometry3D, unsigned int timeSteps); //##Documentation //## @brief Initialize this instance to contain \a timeSteps //## geometries, but without setting them yet virtual void InitializeEmpty(unsigned int timeSteps); //##Documentation //## @brief Expand the number of time steps contained //## to \a timeSteps. //## //## New, additional time steps will be initialized empty. //## Only enlargement of the time steps vector is intended and possible. virtual void ExpandToNumberOfTimeSteps( unsigned int timeSteps ); virtual void SetImageGeometry(const bool isAnImageGeometry); //##Documentation //## @brief Copy the m_TimeBounds of the geometries contained //## in timeslicedgeometry into the geometries contained in this //## TimeSlicedGeometry object. //## //## Useful for initialization of the TimeSlicedGeometry of the //## output in GenerateOutputInformation() methods of process objects, //## see for example BoundingObjectCutter::GenerateOutputInformation(). //## @param t start time index //## @param endtimeindex (endtimeindex) is the time index of //## the last geometry whose time-bounds are copied. If //## timeslicedgeometry or this TimeSlicedGeometry object does //## not contain enough geometries, endtimeindex is reduced //## appropriately. void CopyTimes(const mitk::TimeSlicedGeometry* timeslicedgeometry, unsigned int t=0, unsigned int endtimeindex = itk::NumericTraits::max()); //##Documentation //## @brief duplicates the geometry virtual AffineGeometryFrame3D::Pointer Clone() const; - + TimeSlicedGeometry::Pointer CloneCopy() const; virtual void ExecuteOperation(Operation* operation); protected: TimeSlicedGeometry(); TimeSlicedGeometry(const TimeSlicedGeometry& other); virtual ~TimeSlicedGeometry(); virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; mutable std::vector m_Geometry3Ds; //##Documentation //## @brief Number of time steps unsigned int m_TimeSteps; //##Documentation //## @brief \a true in case the time steps have equal length bool m_EvenlyTimed; static const std::string EVENLY_TIMED; static const std::string TIME_STEPS; }; } // namespace mitk #endif /* TIMESLICEDGEOMETRY_H_HEADER_INCLUDED_C1EBD0AD */ diff --git a/Core/Code/Testing/CMakeLists.txt b/Core/Code/Testing/CMakeLists.txt index 926bca8168..0dc1fbdf1d 100644 --- a/Core/Code/Testing/CMakeLists.txt +++ b/Core/Code/Testing/CMakeLists.txt @@ -1,34 +1,36 @@ MITK_CREATE_MODULE_TESTS(LABELS MITK-Core) # MITK_INSTALL_TARGETS(EXECUTABLES MitkTestDriver) mitkAddCustomModuleTest(mitkPicFileReaderTest_emptyFile mitkPicFileReaderTest ${CMAKE_CURRENT_SOURCE_DIR}/Data/emptyFile.pic) mitkAddCustomModuleTest(mitkPicFileReaderTest_emptyGzipFile mitkPicFileReaderTest ${CMAKE_CURRENT_SOURCE_DIR}/Data/emptyFile.pic.gz) mitkAddCustomModuleTest(mitkDICOMLocaleTest_spacingOk_CT mitkDICOMLocaleTest ${MITK_DATA_DIR}/spacing-ok-ct.dcm) mitkAddCustomModuleTest(mitkDICOMLocaleTest_spacingOk_MR mitkDICOMLocaleTest ${MITK_DATA_DIR}/spacing-ok-mr.dcm) mitkAddCustomModuleTest(mitkDICOMLocaleTest_spacingOk_SC mitkDICOMLocaleTest ${MITK_DATA_DIR}/spacing-ok-sc.dcm) mitkAddCustomModuleTest(mitkEventMapperTest_Test1And2 mitkEventMapperTest ${MITK_DATA_DIR}/TestStateMachine1.xml ${MITK_DATA_DIR}/TestStateMachine2.xml) mitkAddCustomModuleTest(mitkNodeDependentPointSetInteractorTest mitkNodeDependentPointSetInteractorTest ${MITK_DATA_DIR}/Pic3D.pic.gz ${MITK_DATA_DIR}/BallBinary30x30x30.pic.gz) mitkAddCustomModuleTest(mitkDataStorageTest_US4DCyl mitkDataStorageTest ${MITK_DATA_DIR}/US4DCyl.pic.gz) mitkAddCustomModuleTest(mitkStateMachineFactoryTest_TestStateMachine1_2 mitkStateMachineFactoryTest ${MITK_DATA_DIR}/TestStateMachine1.xml ${MITK_DATA_DIR}/TestStateMachine2.xml) mitkAddCustomModuleTest(mitkDicomSeriesReaderTest_CTImage mitkDicomSeriesReaderTest ${MITK_DATA_DIR}/TinyCTAbdomen) ADD_TEST(mitkPointSetLocaleTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkPointSetLocaleTest ${MITK_DATA_DIR}/pointSet.mps) SET_PROPERTY(TEST mitkPointSetLocaleTest PROPERTY LABELS MITK-Core) ADD_TEST(mitkPicFileReaderTest_emptyGzipFile ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkPicFileReaderTest ${CMAKE_CURRENT_SOURCE_DIR}/Data/emptyFile.pic.gz) SET_PROPERTY(TEST mitkPicFileReaderTest_emptyGzipFile PROPERTY LABELS MITK-Core) ADD_TEST(mitkImageTest_brainImage ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkImageTest ${MITK_DATA_DIR}/brain.mhd) SET_PROPERTY(TEST mitkImageTest_brainImage PROPERTY LABELS MITK-Core) +ADD_TEST(mitkImageTest_4DImageData ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkImageTest ${MITK_DATA_DIR}/US4DCyl.pic.gz) +SET_PROPERTY(TEST mitkImageTest_4DImageData PROPERTY LABELS MITK-Core) ADD_TEST(mitkImageWriterTest_nrrdImage ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkImageWriterTest ${MITK_DATA_DIR}/NrrdWritingTestImage.jpg) SET_PROPERTY(TEST mitkImageWriterTest_nrrdImage PROPERTY LABELS MITK-Core) add_subdirectory(DICOMTesting) diff --git a/Core/Code/Testing/mitkBaseDataTest.cpp b/Core/Code/Testing/mitkBaseDataTest.cpp index e8994ee97d..4b02e21e4f 100644 --- a/Core/Code/Testing/mitkBaseDataTest.cpp +++ b/Core/Code/Testing/mitkBaseDataTest.cpp @@ -1,112 +1,121 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision: 17495 $ 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 "mitkBaseDataTestImplementation.h" #include "mitkStringProperty.h" #include "mitkTestingMacros.h" #include "itkImage.h" int mitkBaseDataTest(int /*argc*/, char* /*argv*/[]) { MITK_TEST_BEGIN("BaseData") //Create a BaseData implementation - std::cout << "Creating a base data instance..." << std::endl; + MITK_INFO << "Creating a base data instance..."; mitk::BaseDataTestImplementation::Pointer baseDataImpl = mitk::BaseDataTestImplementation::New(); MITK_TEST_CONDITION_REQUIRED(baseDataImpl.IsNotNull(),"Testing instantiation"); MITK_TEST_CONDITION(baseDataImpl->IsInitialized(), "BaseDataTestImplementation is initialized"); MITK_TEST_CONDITION(baseDataImpl->IsEmpty(), "BaseDataTestImplementation is initialized and empty"); MITK_TEST_CONDITION(baseDataImpl->GetExternalReferenceCount()== baseDataImpl->GetReferenceCount(), "Checks external reference count!"); + mitk::BaseDataTestImplementation::Pointer cloneBaseData = baseDataImpl->Clone(); + MITK_TEST_CONDITION_REQUIRED(cloneBaseData.IsNotNull(),"Testing instantiation of base data clone"); + MITK_TEST_CONDITION(cloneBaseData->IsInitialized(), "Clone of BaseDataTestImplementation is initialized"); + MITK_TEST_CONDITION(cloneBaseData->IsEmpty(), "Clone of BaseDataTestImplementation is initialized and empty"); + MITK_TEST_CONDITION(cloneBaseData->GetExternalReferenceCount()== cloneBaseData->GetReferenceCount(), "Checks external reference count of base data clone!"); - - std::cout << "Testing setter and getter for geometries..." << std::endl; + MITK_INFO << "Testing setter and getter for geometries..."; //test method GetTimeSlicedGeometry() MITK_TEST_CONDITION(baseDataImpl->GetTimeSlicedGeometry(), "Testing creation of TimeSlicedGeometry"); mitk::TimeSlicedGeometry* geo = NULL; baseDataImpl->SetGeometry(geo); MITK_TEST_CONDITION(baseDataImpl->GetTimeSlicedGeometry() == NULL, "Reset Geometry"); mitk::TimeSlicedGeometry::Pointer geo2 = mitk::TimeSlicedGeometry::New(); baseDataImpl->SetGeometry(geo2); baseDataImpl->InitializeTimeSlicedGeometry(2); - MITK_TEST_CONDITION(baseDataImpl->GetTimeSlicedGeometry() == geo2, "Correct Reinit of TimeslicedGeometry"); //test method GetGeometry(int timeStep) MITK_TEST_CONDITION(baseDataImpl->GetGeometry(1) != NULL, "... and single Geometries"); //test method Expand(unsigned int timeSteps) baseDataImpl->Expand(5); MITK_TEST_CONDITION(baseDataImpl->GetTimeSteps() == 5, "Expand the geometry to further time slices!"); //test method GetUpdatedGeometry(int timeStep); mitk::Geometry3D::Pointer geo3 = mitk::Geometry3D::New(); mitk::TimeSlicedGeometry::Pointer timeSlicedGeometry = baseDataImpl->GetTimeSlicedGeometry(); if (timeSlicedGeometry.IsNotNull() ) { timeSlicedGeometry->SetGeometry3D(geo3, 1); } MITK_TEST_CONDITION(baseDataImpl->GetUpdatedGeometry(1) == geo3, "Set Geometry for time step 1"); MITK_TEST_CONDITION(baseDataImpl->GetMTime()!= 0, "Check if modified time is set"); baseDataImpl->SetClonedGeometry(geo3, 1); float x[3]; x[0] = 2; x[1] = 4; x[2] = 6; mitk::Point3D p3d(x); baseDataImpl->SetOrigin(p3d); geo3->SetOrigin(p3d); MITK_TEST_CONDITION(baseDataImpl->GetGeometry(1)->GetOrigin() == geo3->GetOrigin(), "Testing Origin set"); + + cloneBaseData = baseDataImpl->Clone(); + MITK_TEST_CONDITION(cloneBaseData->GetGeometry(1)->GetOrigin() == geo3->GetOrigin(), "Testing origin set in clone!"); MITK_TEST_CONDITION(!baseDataImpl->IsEmptyTimeStep(1), "Is not empty before clear()!"); baseDataImpl->Clear(); MITK_TEST_CONDITION(baseDataImpl->IsEmptyTimeStep(1), "...but afterwards!"); //test method Set-/GetProperty() baseDataImpl->SetProperty("property38", mitk::StringProperty::New("testproperty")); //baseDataImpl->SetProperty("visibility", mitk::BoolProperty::New()); MITK_TEST_CONDITION(baseDataImpl->GetProperty("property38")->GetValueAsString() == "testproperty","Check if base property is set correctly!"); + + cloneBaseData = baseDataImpl->Clone(); + MITK_TEST_CONDITION(cloneBaseData->GetProperty("property38")->GetValueAsString() == "testproperty", "Testing origin set in clone!"); //test method Set-/GetPropertyList mitk::PropertyList::Pointer propertyList = mitk::PropertyList::New(); propertyList->SetFloatProperty("floatProperty1", 123.45); propertyList->SetBoolProperty("visibility",true); propertyList->SetStringProperty("nameXY","propertyName"); baseDataImpl->SetPropertyList(propertyList); bool value = false; MITK_TEST_CONDITION(baseDataImpl->GetPropertyList() == propertyList, "Check if base property list is set correctly!"); MITK_TEST_CONDITION(baseDataImpl->GetPropertyList()->GetBoolProperty("visibility", value) == true, "Check if base property is set correctly in the property list!"); //test method UpdateOutputInformation() baseDataImpl->UpdateOutputInformation(); MITK_TEST_CONDITION(baseDataImpl->GetUpdatedTimeSlicedGeometry() == geo2, "TimeSlicedGeometry update!"); //Test method CopyInformation() mitk::BaseDataTestImplementation::Pointer newBaseData = mitk::BaseDataTestImplementation::New(); newBaseData->CopyInformation(baseDataImpl); - MITK_TEST_CONDITION( newBaseData->GetTimeSlicedGeometry()->GetTimeSteps() == 5, "Check copying of of Basedata Data Object!"); - + MITK_TEST_CONDITION_REQUIRED( newBaseData->GetTimeSlicedGeometry()->GetTimeSteps() == 5, "Check copying of of Basedata Data Object!"); + MITK_TEST_END() } diff --git a/Core/Code/Testing/mitkImageTest.cpp b/Core/Code/Testing/mitkImageTest.cpp index 976c0185e0..aa8eae560b 100644 --- a/Core/Code/Testing/mitkImageTest.cpp +++ b/Core/Code/Testing/mitkImageTest.cpp @@ -1,486 +1,496 @@ /*========================================================================= 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 #include #include #include #include #include #include int mitkImageTest(int argc, char* argv[]) { MITK_TEST_BEGIN(mitkImageTest); //Create Image out of nowhere mitk::Image::Pointer imgMem; mitk::PixelType pt(typeid(int)); unsigned int dim[]={100,100,20}; std::cout << "Testing creation of Image: "; imgMem=mitk::Image::New(); if(imgMem.IsNull()) { std::cout<<"[FAILED]"<Initialize(mitk::PixelType(typeid(int)), 3, dim); std::cout<<"[PASSED]"<IsInitialized()==false) { std::cout<<"[FAILED]"<GetData(); if(p==NULL) { std::cout<<"[FAILED]"<GetData(); if(p2==NULL) { std::cout<<"[FAILED]"<IsInitialized()==false) { std::cout<<"[FAILED]"<GetSliceData(dim[2]/2)->GetData(); unsigned int xy_size = dim[0]*dim[1]; unsigned int start_mid_slice = (dim[2]/2)*xy_size; for(i=0; iGetSliceData(dim[2]/2)->GetPicDescriptor()); imgMem=mitk::Image::New(); std::cout << "Testing reinitializing via Initialize(const mitk::PixelType& type, unsigned int dimension, unsigned int *dimensions): "; imgMem->Initialize(mitk::PixelType(typeid(int)), 3, dim); std::cout<<"[PASSED]"<SetPicSlice(pic_slice, i, 0, 0); } std::cout<<"[PASSED]"<GetData(); if(p2==NULL) { std::cout<<"[FAILED]"<IsInitialized()==false) { std::cout<<"[FAILED]"<SetPicVolume(mitkIpPicClone(imgMem->GetVolumeData(0)->GetPicDescriptor()),0); std::cout<<"[PASSED]"<data,0,xy_size*sizeof(int)); imgMem->SetPicSlice(pic_slice, 1); std::cout << "Getting the volume again and compare the check the changed slice: "; p2 = (int*)imgMem->GetData(); if(p2==NULL) { std::cout<<"[FAILED]"<SetVolume(imgMem->GetData()); std::cout<<"[PASSED]"<data,0,xy_size*sizeof(int)); imgMem->SetSlice(pic_slice->data, 0); std::cout << "Getting the volume again and compare the check the changed slice: "; p2 = (int*)imgMem->GetData(); if(p2==NULL) { std::cout<<"[FAILED]"<SetVolume(data); //std::cout<<"[PASSED]"<InitializeStandardPlane(100, 100, right, bottom, &spacing); planegeometry->SetOrigin(origin); std::cout << "done" << std::endl; std::cout << "Testing Initialize(const mitk::PixelType& type, const mitk::Geometry3D& geometry, unsigned int slices) with PlaneGeometry and GetData(): "; imgMem->Initialize(mitk::PixelType(typeid(int)), *planegeometry); p = (int*)imgMem->GetData(); if(p==NULL) { std::cout<<"[FAILED]"<Initialize(mitk::PixelType(typeid(int)), 40, *planegeometry); p = (int*)imgMem->GetData(); if(p==NULL) { std::cout<<"[FAILED]"<GetOrigin(): "; if( mitk::Equal(imgMem->GetGeometry()->GetOrigin(), origin) == false) { std::cout<<"[FAILED]"<GetOrigin(): "; if( mitk::Equal(imgMem->GetTimeSlicedGeometry()->GetOrigin(), origin) == false) { std::cout<<"[FAILED]"<SetOrigin(origin); std::cout<<"[PASSED]"<GetOrigin(): "; if( mitk::Equal(imgMem->GetGeometry()->GetOrigin(), origin) == false) { std::cout<<"[FAILED]"<GetOrigin(): "; if( mitk::Equal(imgMem->GetTimeSlicedGeometry()->GetOrigin(), origin) == false) { std::cout<<"[FAILED]"<GetGeometry2D(0)->GetOrigin(): "; if( mitk::Equal(imgMem->GetSlicedGeometry()->GetGeometry2D(0)->GetOrigin(), origin) == false) { std::cout<<"[FAILED]"<GetSpacing(): "; if( mitk::Equal(imgMem->GetGeometry()->GetSpacing(), spacing) == false) { std::cout<<"[FAILED]"<GetSpacing(): "; if( mitk::Equal(imgMem->GetTimeSlicedGeometry()->GetSpacing(), spacing) == false) { std::cout<<"[FAILED]"<SetSpacing(spacing); std::cout<<"[PASSED]"<GetSpacing(): "; if( mitk::Equal(imgMem->GetGeometry()->GetSpacing(), spacing) == false) { std::cout<<"[FAILED]"<GetSpacing(): "; if( mitk::Equal(imgMem->GetTimeSlicedGeometry()->GetSpacing(), spacing) == false) { std::cout<<"[FAILED]"<GetGeometry2D(0)->GetSpacing(): "; if( mitk::Equal(imgMem->GetSlicedGeometry()->GetGeometry2D(0)->GetSpacing(), spacing) == false) { std::cout<<"[FAILED]"<Initialize(*imgMem->GetPixelType().GetTypeId(), *imgMem->GetGeometry(), 2 /* #channels */, 0 /*tDim*/ ); vecImg->SetImportChannel(imgMem->GetData(), 0, mitk::Image::CopyMemory ); vecImg->SetImportChannel(imgMem->GetData(), 1, mitk::Image::CopyMemory ); std::cout<<"[PASSED]"<IsValidSlice(0,0,1) , ""); MITK_TEST_OUTPUT(<< " Testing whether CopyMemory worked"); MITK_TEST_CONDITION_REQUIRED(imgMem->GetData() != vecImg->GetData(), ""); MITK_TEST_OUTPUT(<< " Testing destruction after SetImportChannel"); vecImg = NULL; std::cout<<"[PASSED]"<Initialize(); vtkimage->SetDimensions( 2, 3, 4); double vtkorigin[] = {-350,-358.203, -1363.5}; vtkimage->SetOrigin(vtkorigin); mitk::Point3D vtkoriginAsMitkPoint; mitk::vtk2itk(vtkorigin, vtkoriginAsMitkPoint); double vtkspacing[] = {1.367, 1.367, 2}; vtkimage->SetSpacing(vtkspacing); vtkimage->SetScalarType( VTK_SHORT ); vtkimage->AllocateScalars(); std::cout<<"[PASSED]"<Initialize(vtkimage); MITK_TEST_CONDITION_REQUIRED(mitkByVtkImage->IsInitialized(), ""); MITK_TEST_OUTPUT(<< " vtkimage->Delete"); vtkimage->Delete(); std::cout<<"[PASSED]"<GetGeometry()->GetSpacing(); mitk::Vector3D vtkspacingAsMitkVector; mitk::vtk2itk(vtkspacing, vtkspacingAsMitkVector); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(spacing2,vtkspacingAsMitkVector), ""); MITK_TEST_OUTPUT(<< " Testing whether GetSlicedGeometry(0)->GetOrigin() has been correctly initialized from vtkImageData"); mitk::Point3D origin2 = mitkByVtkImage->GetSlicedGeometry(0)->GetOrigin(); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(origin2,vtkoriginAsMitkPoint), ""); MITK_TEST_OUTPUT(<< " Testing whether GetGeometry()->GetOrigin() has been correctly initialized from vtkImageData"); origin2 = mitkByVtkImage->GetGeometry()->GetOrigin(); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(origin2,vtkoriginAsMitkPoint), ""); MITK_TEST_OUTPUT(<< " Testing whether GetTimeSlicedGeometry()->GetOrigin() has been correctly initialized from vtkImageData"); origin2 = mitkByVtkImage->GetTimeSlicedGeometry()->GetOrigin(); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(origin2,vtkoriginAsMitkPoint), ""); // TODO test the following initializers on channel-incorporation // void mitk::Image::Initialize(const mitk::PixelType& type, unsigned int dimension, unsigned int *dimensions, unsigned int channels) // void mitk::Image::Initialize(const mitk::PixelType& type, int sDim, const mitk::Geometry2D& geometry2d, bool flipped, unsigned int channels, int tDim ) // void mitk::Image::Initialize(const mitk::Image* image) // void mitk::Image::Initialize(const mitkIpPicDescriptor* pic, int channels, int tDim, int sDim) //mitk::Image::Pointer vecImg = mitk::Image::New(); //vecImg->Initialize(PixelType(typeid(float), 6, itk::ImageIOBase::SYMMETRICSECONDRANKTENSOR), *imgMem->GetGeometry(), 2 /* #channels */, 0 /*tDim*/, false /*shiftBoundingBoxMinimumToZero*/ ); //vecImg->Initialize(PixelType(typeid(itk::Vector)), *imgMem->GetGeometry(), 2 /* #channels */, 0 /*tDim*/, false /*shiftBoundingBoxMinimumToZero*/ ); // testing access by index coordinates and by world coordinates mitk::DataNode::Pointer node; mitk::DataNodeFactory::Pointer nodeReader = mitk::DataNodeFactory::New(); MITK_TEST_CONDITION_REQUIRED(argc == 2, "Check if test image is accessible!"); + const std::string filename = std::string(argv[1]); try { - const std::string filename = std::string(argv[1]); nodeReader->SetFileName(filename); nodeReader->Update(); node = nodeReader->GetOutput(); } catch(...) { - MITK_TEST_FAILED_MSG(<< "Could not read file for testing: " << "brain.mhd"); + MITK_TEST_FAILED_MSG(<< "Could not read file for testing: " << filename); return NULL; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); // test by index coordinates mitk::Index3D index; mitk::FillVector3D(index, 55, 39, 50); MITK_TEST_OUTPUT(<< "Testing mitk::Image::GetPixelValueByIndex"); double val = image->GetPixelValueByIndex(index); MITK_TEST_CONDITION_REQUIRED( mitk::Equal(val,112.22475433349609), ""); //test by world coordinates MITK_TEST_OUTPUT(<< "Testing mitk::Image::GetPixelValueByWorldCoordinate"); mitk::Point3D point; mitk::FillVector3D(point, -5.93752, 18.7199, 6.74218); val = image->GetPixelValueByWorldCoordinate(point); MITK_TEST_CONDITION_REQUIRED( mitk::Equal(val,94.456184387207031), ""); MITK_TEST_OUTPUT(<< "Convert to index and access value by mitk::Image::GetPixelValueByIndex again"); mitk::Index3D index2; image->GetGeometry()->WorldToIndex(point, index2); float val2 = image->GetPixelValueByIndex(index2); MITK_TEST_CONDITION_REQUIRED( mitk::Equal(val2,94.456184387207031), ""); //access via itk MITK_TEST_OUTPUT(<< "Test conversion to itk::Image"); typedef itk::Image ItkFloatImage3D; ItkFloatImage3D::Pointer itkimage; mitk::CastToItkImage(image, itkimage); std::cout<<"[PASSED]"<itk-physical->world consistency"); mitk::Point3D itkPhysicalPoint; image->GetGeometry()->WorldToItkPhysicalPoint(point, itkPhysicalPoint); mitk::Point3D backTransformedPoint; image->GetGeometry()->ItkPhysicalPointToWorld(itkPhysicalPoint, backTransformedPoint); MITK_TEST_CONDITION_REQUIRED( mitk::Equal(point,backTransformedPoint), ""); MITK_TEST_OUTPUT(<< "Compare value of pixel returned by mitk in comparison to itk"); itk::Index<3> idx; itkimage->TransformPhysicalPointToIndex(itkPhysicalPoint, idx); float valByItk = itkimage->GetPixel(idx); MITK_TEST_CONDITION_REQUIRED( mitk::Equal(valByItk,94.456184387207031), ""); + mitk::Image::Pointer cloneImage = image->Clone(); + MITK_TEST_CONDITION_REQUIRED(cloneImage->GetDimension() == image->GetDimension(), "Clone (testing dimension)"); + MITK_TEST_CONDITION_REQUIRED(cloneImage->GetPixelType() == image->GetPixelType(), "Clone (testing pixel type)"); + + for (unsigned int i = 0u; i < cloneImage->GetDimension(); ++i) + { + MITK_TEST_CONDITION_REQUIRED(cloneImage->GetDimension(i) == image->GetDimension(i), "Clone (testing dimension " << i << ")"); + } + + MITK_TEST_END(); return EXIT_SUCCESS; } diff --git a/Core/Code/Testing/mitkPointSetTest.cpp b/Core/Code/Testing/mitkPointSetTest.cpp index a14bc28d02..d812b356d5 100644 --- a/Core/Code/Testing/mitkPointSetTest.cpp +++ b/Core/Code/Testing/mitkPointSetTest.cpp @@ -1,604 +1,610 @@ /*========================================================================= 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 "mitkTestingMacros.h" #include #include #include #include #include class mitkPointSetTestClass { public: static void TestGetITKPointSet(mitk::PointSet *pointSet) { //try to get the itkPointSet mitk::PointSet::DataType::Pointer itkdata = NULL; itkdata = pointSet->GetPointSet(); MITK_TEST_CONDITION( itkdata.IsNotNull(), "try to get the itkPointSet from a newly created PointSet" ) } static void TestGetSizeIsZero(mitk::PointSet *pointSet) { //fresh PointSet has to be empty! MITK_TEST_CONDITION( pointSet->GetSize() == 0, "check if the PointSet size is 0 " ) } static void TestIsEmpty(mitk::PointSet *pointSet) { MITK_TEST_CONDITION(pointSet->IsEmptyTimeStep(0), "check if the PointSet is empty" ) } static void TestCreateOperationAndAddPoint(mitk::PointSet *pointSet) { int id = 0; mitk::Point3D point; point.Fill(1); mitk::PointOperation* doOp = new mitk::PointOperation(mitk::OpINSERT, point, id); pointSet->ExecuteOperation(doOp); MITK_TEST_CONDITION( pointSet->GetSize()==1 && pointSet->IndexExists(id), "check if added points exists" ) delete doOp; mitk::Point3D tempPoint; tempPoint.Fill(0); tempPoint = pointSet->GetPoint(id); MITK_TEST_CONDITION( point == tempPoint, "check if added point contains real value" ) } static void TestAddSecondPoint(mitk::PointSet *pointSet) { //add a point directly int id=0; mitk::Point3D point; mitk::FillVector3D(point, 1.0, 2.0, 3.0); ++id; pointSet->GetPointSet()->GetPoints()->InsertElement(id, point); MITK_TEST_CONDITION( pointSet->GetSize()==2 ||pointSet->IndexExists(id), "check if added points exists" ) mitk::Point3D tempPoint; tempPoint.Fill(0); tempPoint = pointSet->GetPoint(id); MITK_TEST_CONDITION( point == tempPoint, "check if added point contains real value" ) } static void TestIsNotEmpty(mitk::PointSet *pointSet) { //PointSet can not be empty! MITK_TEST_CONDITION( !pointSet->IsEmptyTimeStep(0), "check if the PointSet is not empty " ) /* std::cout << "check if the PointSet is not empty "; if (pointSet->IsEmpty(0)) { std::cout<<"[FAILED]"<GetPoint(1); pointSet->SwapPointPosition(1, true); tempPoint = pointSet->GetPoint(0); MITK_TEST_CONDITION( point == tempPoint, "check SwapPointPosition upwards" ) /* if(point != tempPoint) { std::cout<<"[FAILED]"<SwapPointPosition(0, true)==false, "check SwapPointPosition upwards not possible" ) /* if(pointSet->SwapPointPosition(0, true)) { std::cout<<"[FAILED]"<GetPoint(0); pointSet->SwapPointPosition(0, false); tempPoint = pointSet->GetPoint(1); MITK_TEST_CONDITION( point == tempPoint, "check SwapPointPosition down" ) /* if(point != tempPoint) { std::cout<<"[FAILED]"<SetPoint(id, point); //Check SwapPointPosition downwards not possible MITK_TEST_CONDITION(!pointSet2->SwapPointPosition(id, false), "check SwapPointPosition downwards not possible" ) /* if(pointSet->SwapPointPosition(1, false)) { std::cout<<"[FAILED]"<ExecuteOperation(doOp); tempPoint = pointSet->GetPoint(id); MITK_TEST_CONDITION(tempPoint == point1 , "check PointOperation OpMove " ) delete doOp; /* if (tempPoint != point1) { std::cout<<"[FAILED]"<GetPoint(id); mitk::PointOperation* doOp = new mitk::PointOperation(mitk::OpREMOVE, point, id); pointSet->ExecuteOperation(doOp); tempPoint = pointSet->GetPoint(id); MITK_TEST_CONDITION(!pointSet->IndexExists(id) , "check PointOperation OpREMOVE " ) delete doOp; /* if(pointSet->IndexExists(id)) { std::cout<<"[FAILED]"<ExecuteOperation(doOp); MITK_TEST_CONDITION(pointSet->GetSelectInfo(4) , "check PointOperation OpSELECTPOINT " ) delete doOp; /* if (!pointSet->GetSelectInfo(4)) { std::cout<<"[FAILED]"<GetNumberOfSelected() == 1 , "check GetNumeberOfSelected " ) /* if(pointSet->GetNumberOfSelected() != 1) { std::cout<<"[FAILED]"<SearchSelectedPoint() == 4 , "check SearchSelectedPoint " ) /* if( pointSet->SearchSelectedPoint() != 4) { std::cout<<"[FAILED]"<ExecuteOperation(doOp); MITK_TEST_CONDITION(!pointSet->GetSelectInfo(4) , "check PointOperation OpDESELECTPOINT " ) MITK_TEST_CONDITION(pointSet->GetNumberOfSelected() == 0 , "check GetNumeberOfSelected " ) delete doOp; /* if (pointSet->GetSelectInfo(4)) { std::cout<<"[FAILED]"<GetNumberOfSelected() != 0) { std::cout<<"[FAILED]"<GetPoint(id); mitk::PointOperation* doOp = new mitk::PointOperation(mitk::OpMOVEPOINTUP, point4, id); pointSet->ExecuteOperation(doOp); tempPoint = pointSet->GetPoint(id-1); MITK_TEST_CONDITION(tempPoint == point , "check PointOperation OpMOVEPOINTUP " ) delete doOp; /* if (tempPoint != point) { std::cout<<"[FAILED]"<GetPoint(id); mitk::PointOperation* doOp = new mitk::PointOperation(mitk::OpMOVEPOINTDOWN, point2, id); pointSet->ExecuteOperation(doOp); tempPoint = pointSet->GetPoint(id+1); MITK_TEST_CONDITION(tempPoint == point , "check PointOperation OpMOVEPOINTDOWN " ) delete doOp; /* if (tempPoint != point) { std::cout<<"[FAILED]"<SetSelectInfo(2, true); MITK_TEST_CONDITION(pointSet->GetSelectInfo(2) , "check SetSelectInfo" ) /* if (!pointSet->GetSelectInfo(2)) { std::cout<<"[FAILED]"<SetPoint(5, point5, mitk::PTEDGE ); tempPoint = pointSet->GetPoint(5); MITK_TEST_CONDITION(tempPoint == point5, "check InsertPoint with PointSpecification" ) /* if (tempPoint != point5) { std::cout<<"[FAILED]"<GetPointIfExists(5, &tmpPoint); MITK_TEST_CONDITION(tmpPoint == point5, "check GetPointIfExists: " ) /* if (tmpPoint != point5) { std::cout<<"[FAILED]"<InsertPoint(10, p10); pointSet->InsertPoint(11, p11); pointSet->InsertPoint(12, p12); MITK_TEST_CONDITION((pointSet->IndexExists(10) == true) || (pointSet->IndexExists(11) == true) || (pointSet->IndexExists(12) == true), "add points with id 10, 11, 12: " ) //check OpREMOVE ExecuteOperation int id = 11; mitk::PointOperation* doOp = new mitk::PointOperation(mitk::OpREMOVE, point, id); pointSet->ExecuteOperation(doOp); MITK_TEST_CONDITION(!pointSet->IndexExists(id), "remove point id 11: ") /* if(pointSet->IndexExists(id)) { std::cout<<"[FAILED]"<ExecuteOperation(doOp); delete doOp; //check OpMOVEPOINTUP ExecuteOperation doOp = new mitk::PointOperation(mitk::OpMOVEPOINTUP, p12, 12); pointSet->ExecuteOperation(doOp); delete doOp; mitk::PointSet::PointType newP10 = pointSet->GetPoint(10); mitk::PointSet::PointType newP12 = pointSet->GetPoint(12); MITK_TEST_CONDITION(((newP10 == p12) && (newP12 == p10)) == true, "check PointOperation OpMOVEPOINTUP for point id 12:" ) //check OpMOVEPOINTDOWN ExecuteOperation doOp = new mitk::PointOperation(mitk::OpMOVEPOINTDOWN, p10, 10); pointSet->ExecuteOperation(doOp); delete doOp; newP10 = pointSet->GetPoint(10); newP12 = pointSet->GetPoint(12); MITK_TEST_CONDITION(((newP10 == p10) && (newP12 == p12)) == true, "check PointOperation OpMOVEPOINTDOWN for point id 10: ") } static void TestOpMovePointUpOnFirstPoint(mitk::PointSet *pointSet) { //check OpMOVEPOINTUP on first point ExecuteOperation mitk::PointSet::PointType p1 = pointSet->GetPoint(1); mitk::PointSet::PointType p2 = pointSet->GetPoint(2); mitk::PointOperation* doOp = new mitk::PointOperation(mitk::OpMOVEPOINTUP, p1, 1); pointSet->ExecuteOperation(doOp); delete doOp; mitk::PointSet::PointType newP1 = pointSet->GetPoint(1); mitk::PointSet::PointType newP2 = pointSet->GetPoint(2); MITK_TEST_CONDITION(((newP1 == p1) && (newP2 == p2)) == true, "check PointOperation OpMOVEPOINTUP for point id 1: ") /* if (((newP1 == p1) && (newP2 == p2)) == false) { std::cout<<"[FAILED]"<GetPointSet()->GetPoints(); mitk::PointSet::PointDataContainer* pd = ps->GetPointSet()->GetPointData(); MITK_TEST_CONDITION_REQUIRED(pc->Size() == pd->Size(), "PointContainer and PointDataContainer have same size"); mitk::PointSet::PointsContainer::ConstIterator pIt = pc->Begin(); mitk::PointSet::PointDataContainer::ConstIterator dIt = pd->Begin(); bool failed = false; for (; pIt != pc->End(); ++pIt, ++dIt) if (pIt->Index() != dIt->Index()) { failed = true; break; } MITK_TEST_CONDITION(failed == false, "Indices in PointContainer and PointDataContainer are equal"); } }; int mitkPointSetTest(int /*argc*/, char* /*argv*/[]) { MITK_TEST_BEGIN("PointSet") //Create PointSet mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); MITK_TEST_CONDITION_REQUIRED(pointSet.IsNotNull(),"Testing instantiation") mitkPointSetTestClass::TestGetITKPointSet(pointSet); mitkPointSetTestClass::TestGetSizeIsZero(pointSet); mitkPointSetTestClass::TestIsEmpty(pointSet); mitkPointSetTestClass::TestCreateOperationAndAddPoint(pointSet); mitk::Point3D point2, point3, point4; point2.Fill(3); point3.Fill(4); point4.Fill(5); pointSet->InsertPoint(2,point2); pointSet->InsertPoint(3,point3); pointSet->InsertPoint(4,point4); mitkPointSetTestClass::TestAddSecondPoint(pointSet); mitkPointSetTestClass::TestIsNotEmpty(pointSet); mitkPointSetTestClass::TestSwapPointPositionUpwards(pointSet); mitkPointSetTestClass::TestSwapPointPositionUpwardsNotPossible(pointSet); mitkPointSetTestClass::TestSwapPointPositionDownwards(pointSet); mitkPointSetTestClass::TestSwapPointPositionDownwardsNotPossible(pointSet); mitkPointSetTestClass::TestPointOperationOpMove(pointSet); mitkPointSetTestClass::TestPointOperationOpRemove(pointSet); mitkPointSetTestClass::TestPointOperationOpSelectPoint(pointSet); mitkPointSetTestClass::TestGetNumberOfSelected(pointSet); mitkPointSetTestClass::TestSearchSelectedPoint(pointSet); mitkPointSetTestClass::TestOpDeselectPoint(pointSet); mitkPointSetTestClass::TestOpMovePointUp(pointSet); mitkPointSetTestClass::TestOpMovePointDown(pointSet); mitkPointSetTestClass::TestSetSelectInfo(pointSet); mitkPointSetTestClass::TestInsertPointWithPointSpecification(pointSet); mitkPointSetTestClass::TestGetPointIfExists(pointSet); mitkPointSetTestClass::TestCreateHoleInThePointIDs(pointSet); mitkPointSetTestClass::TestOpMovePointUpOnFirstPoint(pointSet); MITK_TEST_OUTPUT(<< "Test InsertPoint(), SetPoint() and SwapPointPosition()"); mitk::PointSet::PointType point; mitk::FillVector3D(point, 2.2, 3.3, -4.4); /* call everything that might modify PointContainer and PointDataContainer */ pointSet->InsertPoint(17, point); pointSet->SetPoint(4, point); pointSet->SetPoint(7, point); pointSet->SetPoint(2, point); pointSet->SwapPointPosition(7, true); pointSet->SwapPointPosition(3, true); pointSet->SwapPointPosition(2, false); mitkPointSetTestClass::TestPointContainerPointDataContainer(pointSet); MITK_TEST_OUTPUT(<< "Test OpREMOVE"); mitk::PointOperation op1(mitk::OpREMOVE, mitk::Point3D(), 2); // existing index pointSet->ExecuteOperation(&op1); mitk::PointOperation op1b(mitk::OpREMOVE, mitk::Point3D(), 112); // non existing index pointSet->ExecuteOperation(&op1b); mitkPointSetTestClass::TestPointContainerPointDataContainer(pointSet); MITK_TEST_OUTPUT(<< "Test OpMove"); mitk::PointOperation op2(mitk::OpMOVE, mitk::Point3D(), 4); // existing index pointSet->ExecuteOperation(&op2); mitk::PointOperation op3(mitk::OpMOVE, mitk::Point3D(), 34); // non existing index pointSet->ExecuteOperation(&op3); mitkPointSetTestClass::TestPointContainerPointDataContainer(pointSet); MITK_TEST_OUTPUT(<< "Test OpINSERT"); mitk::PointOperation op4(mitk::OpINSERT, mitk::Point3D(), 38); // non existing index pointSet->ExecuteOperation(&op4); mitk::PointOperation op5(mitk::OpINSERT, mitk::Point3D(), 17); // existing index pointSet->ExecuteOperation(&op5); mitkPointSetTestClass::TestPointContainerPointDataContainer(pointSet); + mitk::PointSet::Pointer clonePS = pointSet->Clone(); + mitkPointSetTestClass::TestIsNotEmpty(clonePS); + MITK_TEST_CONDITION_REQUIRED(clonePS->GetPointSetSeriesSize() == pointSet->GetPointSetSeriesSize(), "Testing cloned point set's size!"); + MITK_TEST_CONDITION_REQUIRED(clonePS.GetPointer() != pointSet.GetPointer(), "Testing that the clone is not the source PS!"); + MITK_TEST_CONDITION_REQUIRED(clonePS->GetGeometry()->GetCenter() == pointSet->GetGeometry()->GetCenter() , "Testing if the geometry is cloned correctly!"); + MITK_TEST_CONDITION_REQUIRED(clonePS->GetPropertyList()->GetMap()->size() == pointSet->GetPropertyList()->GetMap()->size() , "Testing if the property list is cloned correctly!"); MITK_TEST_END(); } diff --git a/Core/Code/Testing/mitkSurfaceTest.cpp b/Core/Code/Testing/mitkSurfaceTest.cpp index ae00eee7eb..cc45b9364d 100644 --- a/Core/Code/Testing/mitkSurfaceTest.cpp +++ b/Core/Code/Testing/mitkSurfaceTest.cpp @@ -1,233 +1,147 @@ /*========================================================================= 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 "mitkSurface.h" #include "mitkCommon.h" #include "mitkVector.h" +#include "mitkTestingMacros.h" #include "mitkTimeSlicedGeometry.h" #include "vtkPolyData.h" #include "vtkSphereSource.h" #include int mitkSurfaceTest(int /*argc*/, char* /*argv*/[]) { - mitk::Surface::Pointer surface; - std::cout << "Testing mitk::Surface::New(): "; - surface = mitk::Surface::New(); - if (surface.IsNull()) { - std::cout<<"[FAILED]"<PrintSelf(std::cout, 0); - std::cout<<"[PASSED]"<Clone(); + MITK_TEST_CONDITION_REQUIRED( cloneSurface.GetPointer(), "Testing clone surface initialization!" ); vtkSphereSource* sphereSource = vtkSphereSource::New(); sphereSource->SetCenter(0,0,0); sphereSource->SetRadius(5.0); sphereSource->SetThetaResolution(10); sphereSource->SetPhiResolution(10); sphereSource->Update(); vtkPolyData* polys = sphereSource->GetOutput(); + MITK_TEST_CONDITION_REQUIRED(surface->GetVtkPolyData() == NULL, "Testing initial state of vtkPolyData"); surface->SetVtkPolyData( polys ); sphereSource->Delete(); - std::cout << "Testing mitk::Surface::SetVtkPolyData(): "; - if (surface->GetVtkPolyData() == NULL ) { - std::cout<<"[FAILED]"<GetVtkPolyData()!= NULL, "Testing set vtkPolyData"); - { + cloneSurface = surface->Clone(); + MITK_TEST_CONDITION_REQUIRED(cloneSurface->GetVtkPolyData()!= NULL, "Testing set vtkPolyData of cloned surface!"); + vtkFloatingPointType bounds[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; - polys->ComputeBounds(); polys->GetBounds( bounds ); - std::cout << "Testing GetBoundingBox() "; surface->UpdateOutputInformation(); surface->SetRequestedRegionToLargestPossibleRegion(); - // mitk::BoundingBox bb = const_cast( mitk::BoundingBox* bb = const_cast(surface->GetGeometry()->GetBoundingBox()); mitk::BoundingBox::BoundsArrayType surfBounds = bb->GetBounds(); - if ( bounds[0] != surfBounds[0] - || bounds[1] != surfBounds[1] - || bounds[2] != surfBounds[2] - || bounds[3] != surfBounds[3] - || bounds[4] != surfBounds[4] - || bounds[5] != surfBounds[5] - ) { - std::cout<<"[FAILED]"<Expand(5); surface->Update(); surface->SetRequestedRegionToLargestPossibleRegion(); mitk::Surface::RegionType requestedRegion = surface->GetRequestedRegion(); + MITK_TEST_CONDITION_REQUIRED(requestedRegion.GetSize(3) == 5, "Testing mitk::Surface::Expand( timesteps ): "); - if ( requestedRegion.GetSize(3) != 5 ) { - std::cout<<"[FAILED]"<GetTimeSlicedGeometry()->GetGeometry3D(0); - //geometry->GetVtkTransform()->Identity(); - //geometry->GetVtkTransform()->Translate(10,10,10); - //geometry->TransferVtkToItkTransform(); - //mitk::TimeSlicedGeometry* timeSlicedGeometry = surface->GetTimeSlicedGeometry(); - //timeSlicedGeometry->InitializeEvenlyTimed(geometry, 5); - - vtkFloatingPointType bounds[5][6]; + vtkFloatingPointType boundsMat[5][6]; for (int i=0;i<5;i++) { vtkSphereSource* sphereSource = vtkSphereSource::New(); sphereSource->SetCenter(0,0,0); sphereSource->SetRadius(1.0 * (i+1.0)); sphereSource->SetThetaResolution(10); sphereSource->SetPhiResolution(10); sphereSource->Update(); sphereSource->GetOutput()->ComputeBounds(); - sphereSource->GetOutput()->GetBounds( bounds[i] ); + sphereSource->GetOutput()->GetBounds( boundsMat[i] ); surface->SetVtkPolyData( sphereSource->GetOutput(),i ); sphereSource->Delete(); } surface->UpdateOutputInformation(); surface->SetRequestedRegionToLargestPossibleRegion(); - bool passed = true; + passed = true; for (int i=0;i<5;i++) { mitk::BoundingBox::BoundsArrayType surfBounds = (const_cast(surface->GetTimeSlicedGeometry()->GetGeometry3D(i)->GetBoundingBox()))->GetBounds(); - if ( bounds[i][0] != surfBounds[0] - || bounds[i][1] != surfBounds[1] - || bounds[i][2] != surfBounds[2] - || bounds[i][3] != surfBounds[3] - || bounds[i][4] != surfBounds[4] - || bounds[i][5] != surfBounds[5] ) + if ( boundsMat[i][0] != surfBounds[0] + || boundsMat[i][1] != surfBounds[1] + || boundsMat[i][2] != surfBounds[2] + || boundsMat[i][3] != surfBounds[3] + || boundsMat[i][4] != surfBounds[4] + || boundsMat[i][5] != surfBounds[5] ) { passed = false; break; } } + MITK_TEST_CONDITION_REQUIRED(passed, "Testing mitk::Surface::Testing 4D surface data creation!" ); - if (!passed) - { - std::cout<<"[FAILED]"<GetUpdatedTimeSlicedGeometry(): \n"; const mitk::TimeSlicedGeometry* inputTimeGeometry = surface->GetUpdatedTimeSlicedGeometry(); int time = 3; int timestep=0; timestep = inputTimeGeometry->MSToTimeStep( time ); + MITK_TEST_CONDITION_REQUIRED(time == timestep, "Testing correctness of geometry for surface->GetUpdatedTimeSlicedGeometry()!"); - std::cout << "time: "<< time << std::endl; - std::cout << "timestep: "<SetCenter(0,0,0); sphereSource->SetRadius( 100.0 ); sphereSource->SetThetaResolution(10); sphereSource->SetPhiResolution(10); sphereSource->Update(); surface->SetVtkPolyData( sphereSource->GetOutput(), 3 ); sphereSource->Delete(); inputTimeGeometry = surface->GetUpdatedTimeSlicedGeometry(); time = 3; timestep=0; - timestep = inputTimeGeometry->MSToTimeStep( time ); - - std::cout << "time: "<< time << std::endl; - std::cout << "timestep: "<MSToTimeStep( time ); + MITK_TEST_CONDITION_REQUIRED(time == timestep, "Explicitly changing the data of timestep 3 and checking for timebounds correctness of surface's geometry again!"); unsigned int numberoftimesteps = surface->GetTimeSteps(); mitk::Surface::Pointer dummy = mitk::Surface::New(); dummy->Graft(surface); - std::cout << "polyData != NULL ??" << std::endl; - if (dummy->GetVtkPolyData() == NULL) - { - std::cout<<"[FAILED]"<GetTimeSteps() << std::endl; - if (dummy->GetTimeSteps() != numberoftimesteps) - { - std::cout<<"[FAILED]"<GetVtkPolyData() != NULL, "Testing copying a Surface with Graft()!"); + MITK_TEST_CONDITION_REQUIRED( dummy->GetTimeSteps() == numberoftimesteps, "orig-numberofTimeSteps:" << numberoftimesteps << " copy-numberofTimeSteps:" << dummy->GetTimeSteps()); + + MITK_TEST_END(); } diff --git a/Modules/MitkExt/DataManagement/mitkContour.cpp b/Modules/MitkExt/DataManagement/mitkContour.cpp index 13f9362b53..2cbbf686d8 100644 --- a/Modules/MitkExt/DataManagement/mitkContour.cpp +++ b/Modules/MitkExt/DataManagement/mitkContour.cpp @@ -1,152 +1,163 @@ /*========================================================================= 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 "mitkContour.h" mitk::Contour::Contour() : - m_ContourPath (PathType::New()), - m_CurrentWindow ( NULL ), - m_BoundingBox (BoundingBoxType::New()), - m_Vertices ( BoundingBoxType::PointsContainer::New() ), - m_Closed ( true ), - m_Selected ( false ), - m_Width (3.0) +m_ContourPath (PathType::New()), +m_CurrentWindow ( NULL ), +m_BoundingBox (BoundingBoxType::New()), +m_Vertices ( BoundingBoxType::PointsContainer::New() ), +m_Closed ( true ), +m_Selected ( false ), +m_Width (3.0) { Superclass::InitializeTimeSlicedGeometry(); } +mitk::Contour::Contour( const Contour & other ): BaseData(other), +m_ContourPath(other.m_ContourPath), +m_CurrentWindow(other.m_CurrentWindow), +m_BoundingBox(other.m_BoundingBox), +m_Vertices(other.m_Vertices), +m_Closed(other.m_Closed), +m_Selected(other.m_Selected), +m_Width(other.m_Width) +{ +} + mitk::Contour::~Contour() { } void mitk::Contour::AddVertex(mitk::Point3D newPoint) { BoundingBoxType::PointType p; p.CastFrom(newPoint); m_Vertices->InsertElement(m_Vertices->Size(), p); ContinuousIndexType idx; idx.CastFrom(newPoint); m_ContourPath->AddVertex(idx); m_BoundingBox->SetPoints(m_Vertices); Modified(); } void mitk::Contour::UpdateOutputInformation() { // \todo probably we should do this additionally for each time-step float mitkBounds[6]; if (m_Vertices->Size() == 0) { mitkBounds[0] = 0.0; mitkBounds[1] = 0.0; mitkBounds[2] = 0.0; mitkBounds[3] = 0.0; mitkBounds[4] = 0.0; mitkBounds[5] = 0.0; } else { m_BoundingBox->ComputeBoundingBox(); BoundingBoxType::BoundsArrayType tmp = m_BoundingBox->GetBounds(); mitkBounds[0] = tmp[0]; mitkBounds[1] = tmp[1]; mitkBounds[2] = tmp[2]; mitkBounds[3] = tmp[3]; mitkBounds[4] = tmp[4]; mitkBounds[5] = tmp[5]; } Geometry3D* geometry3d = GetGeometry(0); geometry3d->SetBounds(mitkBounds); GetTimeSlicedGeometry()->UpdateInformation(); } void mitk::Contour::SetRequestedRegionToLargestPossibleRegion() { } bool mitk::Contour::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } bool mitk::Contour::VerifyRequestedRegion() { return true; } void mitk::Contour::SetRequestedRegion(itk::DataObject*) { } mitk::Contour::PathType::Pointer mitk::Contour::GetContourPath() const { return m_ContourPath; } void mitk::Contour::SetCurrentWindow(vtkRenderWindow* rw) { m_CurrentWindow = rw; } vtkRenderWindow* mitk::Contour::GetCurrentWindow() const { return m_CurrentWindow; } void mitk::Contour::Initialize() { m_ContourPath = PathType::New(); m_ContourPath->Initialize(); m_BoundingBox = BoundingBoxType::New(); m_Vertices = BoundingBoxType::PointsContainer::New(); GetTimeSlicedGeometry()->InitializeEvenlyTimed(1); } unsigned int mitk::Contour::GetNumberOfPoints() const { return m_Vertices->Size(); } mitk::Contour::PointsContainerPointer mitk::Contour::GetPoints() const { return m_Vertices; } void mitk::Contour::SetPoints(mitk::Contour::PointsContainerPointer points) { m_Vertices = points; Modified(); } void mitk::Contour::PrintSelf( std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf( os, indent ); os << indent << "Number of verticies: " << GetNumberOfPoints() << std::endl; mitk::Contour::PointsContainerIterator pointsIt = m_Vertices->Begin(), end = m_Vertices->End(); os << indent << "Verticies: " << std::endl; int i = 0; while ( pointsIt != end ) { os << indent << indent << i << ": " << pointsIt.Value() << std::endl; ++pointsIt; ++i; } } diff --git a/Modules/MitkExt/DataManagement/mitkContour.h b/Modules/MitkExt/DataManagement/mitkContour.h index 0d0d8cbafe..529536bfc1 100644 --- a/Modules/MitkExt/DataManagement/mitkContour.h +++ b/Modules/MitkExt/DataManagement/mitkContour.h @@ -1,180 +1,183 @@ /*========================================================================= 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 _MITK_CONTOUR_H_ #define _MITK_CONTOUR_H_ #include "mitkCommon.h" #include "MitkExtExports.h" #include "mitkBaseData.h" #include #include namespace mitk { /** * This class holds stores vertices for drawing a contour * */ class MitkExt_EXPORT Contour : public BaseData { public: mitkClassMacro(Contour, BaseData); itkNewMacro(Self); + mitkCloneMacro(Contour); + typedef itk::PolyLineParametricPath<3> PathType; typedef PathType::Pointer PathPointer; typedef PathType::ContinuousIndexType ContinuousIndexType; typedef PathType::InputType InputType; typedef PathType::OutputType OutputType; typedef PathType::OffsetType OffsetType; typedef itk::BoundingBox BoundingBoxType; typedef BoundingBoxType::PointsContainer PointsContainer; typedef BoundingBoxType::PointsContainer::Pointer PointsContainerPointer; typedef BoundingBoxType::PointsContainerIterator PointsContainerIterator; /** * sets whether the contour should be closed or open. * by default the contour is closed */ itkSetMacro(Closed, bool); /** * returns if the contour is closed or opened */ itkGetMacro(Closed, bool); itkSetMacro(Selected, bool); itkGetMacro(Selected, bool); itkSetMacro(Width, float); itkGetMacro(Width, float); /** * clean up the contour data */ void Initialize(); /** * add a new vertex to the contour */ void AddVertex(mitk::Point3D newPoint); /** * return an itk parametric path of the contour */ PathPointer GetContourPath() const; /** * set the current render window. This is helpful if one * wants to draw the contour in one special window only. */ void SetCurrentWindow(vtkRenderWindow* rw); /** * returns the points to the current render window */ vtkRenderWindow* GetCurrentWindow() const; /** * returns the number of points stored in the contour */ unsigned int GetNumberOfPoints() const; /** * returns the container of the contour points */ PointsContainerPointer GetPoints() const; /** * set the contour points container. */ void SetPoints(PointsContainerPointer points); /** * intherited from parent */ virtual void UpdateOutputInformation(); /** * intherited from parent */ virtual void SetRequestedRegionToLargestPossibleRegion(); /** * intherited from parent */ virtual bool RequestedRegionIsOutsideOfTheBufferedRegion(); /** * intherited from parent */ virtual bool VerifyRequestedRegion(); /** * intherited from parent */ virtual void SetRequestedRegion(itk::DataObject *data); protected: Contour(); + Contour(const Contour & other); virtual ~Contour(); virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; private: /** * parametric path of a contour; */ PathType::Pointer m_ContourPath; /** * the current render window */ vtkRenderWindow* m_CurrentWindow; /** * the bounding box of the contour */ BoundingBoxType::Pointer m_BoundingBox; /** * container for all contour points */ BoundingBoxType::PointsContainer::Pointer m_Vertices; /** * decide whether th contour is open or closed */ bool m_Closed; bool m_Selected; float m_Width; }; } // namespace mitk #endif //_MITK_CONTOUR_H_ diff --git a/Modules/MitkExt/DataManagement/mitkUnstructuredGrid.cpp b/Modules/MitkExt/DataManagement/mitkUnstructuredGrid.cpp index c601642583..2d4ce2f3e6 100644 --- a/Modules/MitkExt/DataManagement/mitkUnstructuredGrid.cpp +++ b/Modules/MitkExt/DataManagement/mitkUnstructuredGrid.cpp @@ -1,234 +1,251 @@ /*========================================================================= 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 "mitkUnstructuredGrid.h" #include #include void mitk::UnstructuredGrid::SetVtkUnstructuredGrid( vtkUnstructuredGrid* grid, unsigned int t ) { this->Expand(t); if(m_GridSeries[ t ] != NULL) { m_GridSeries[ t ]->Delete(); } m_GridSeries[ t ] = grid; // call m_VtkPolyData->Register(NULL) to tell the reference counting that we // want to keep a reference on the object if (m_GridSeries[t] != 0) m_GridSeries[t]->Register(grid); this->Modified(); m_CalculateBoundingBox = true; } void mitk::UnstructuredGrid::Expand(unsigned int timeSteps) { // check if the vector is long enough to contain the new element // at the given position. If not, expand it with sufficient zero-filled elements. if(timeSteps > m_GridSeries.size()) { Superclass::Expand(timeSteps); vtkUnstructuredGrid* pdnull = 0; m_GridSeries.resize( timeSteps, pdnull ); m_CalculateBoundingBox = true; } } void mitk::UnstructuredGrid::ClearData() { for ( VTKUnstructuredGridSeries::iterator it = m_GridSeries.begin(); it != m_GridSeries.end(); ++it ) { if ( ( *it ) != 0 ) ( *it )->Delete(); } m_GridSeries.clear(); Superclass::ClearData(); } void mitk::UnstructuredGrid::InitializeEmpty() { vtkUnstructuredGrid* pdnull = 0; m_GridSeries.resize( 1, pdnull ); Superclass::InitializeTimeSlicedGeometry(1); m_Initialized = true; } vtkUnstructuredGrid* mitk::UnstructuredGrid::GetVtkUnstructuredGrid(unsigned int t) { if ( t < m_GridSeries.size() ) { vtkUnstructuredGrid* grid = m_GridSeries[ t ]; if((grid == 0) && (GetSource().GetPointer() != 0)) { RegionType requestedregion; requestedregion.SetIndex(3, t); requestedregion.SetSize(3, 1); SetRequestedRegion(&requestedregion); GetSource()->Update(); } grid = m_GridSeries[ t ]; return grid; } else return 0; } mitk::UnstructuredGrid::UnstructuredGrid() : m_CalculateBoundingBox( false ) { this->InitializeEmpty(); } +mitk::UnstructuredGrid::UnstructuredGrid(const mitk::UnstructuredGrid &other) : +BaseData(other), +m_CalculateBoundingBox( other.m_CalculateBoundingBox ), +m_LargestPossibleRegion(other.m_LargestPossibleRegion) +{ + if(!other.m_Initialized) + { + this->InitializeEmpty(); + } + else + { + m_GridSeries = other.m_GridSeries; + m_Initialized = other.m_Initialized; + } + this->SetRequestedRegion( const_cast(&other) ); +} + mitk::UnstructuredGrid::~UnstructuredGrid() { this->ClearData(); } void mitk::UnstructuredGrid::UpdateOutputInformation() { if ( this->GetSource() ) { this->GetSource()->UpdateOutputInformation(); } if ( ( m_CalculateBoundingBox ) && ( m_GridSeries.size() > 0 ) ) CalculateBoundingBox(); else GetTimeSlicedGeometry()->UpdateInformation(); } void mitk::UnstructuredGrid::CalculateBoundingBox() { // // first make sure, that the associated time sliced geometry has // the same number of geometry 3d's as vtkUnstructuredGrids are present // mitk::TimeSlicedGeometry* timeGeometry = GetTimeSlicedGeometry(); if ( timeGeometry->GetTimeSteps() != m_GridSeries.size() ) { itkExceptionMacro(<<"timeGeometry->GetTimeSteps() != m_GridSeries.size() -- use Initialize(timeSteps) with correct number of timeSteps!"); } // // Iterate over the vtkUnstructuredGrids and update the Geometry // information of each of the items. // for ( unsigned int i = 0 ; i < m_GridSeries.size() ; ++i ) { vtkUnstructuredGrid* grid = m_GridSeries[ i ]; vtkFloatingPointType bounds[ ] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; if ( ( grid != 0 ) && ( grid->GetNumberOfCells() > 0 ) ) { grid->Update(); grid->ComputeBounds(); grid->GetBounds( bounds ); } mitk::Geometry3D::Pointer g3d = timeGeometry->GetGeometry3D( i ); assert( g3d.IsNotNull() ); g3d->SetFloatBounds( bounds ); } timeGeometry->UpdateInformation(); mitk::BoundingBox::Pointer bb = const_cast( timeGeometry->GetBoundingBox() ); itkDebugMacro( << "boundingbox min: "<< bb->GetMinimum()); itkDebugMacro( << "boundingbox max: "<< bb->GetMaximum()); m_CalculateBoundingBox = false; } void mitk::UnstructuredGrid::SetRequestedRegionToLargestPossibleRegion() { m_RequestedRegion = GetLargestPossibleRegion(); } bool mitk::UnstructuredGrid::RequestedRegionIsOutsideOfTheBufferedRegion() { RegionType::IndexValueType end = m_RequestedRegion.GetIndex(3)+m_RequestedRegion.GetSize(3); if(((RegionType::IndexValueType)m_GridSeries.size()) < end) return true; for( RegionType::IndexValueType t=m_RequestedRegion.GetIndex(3); t < end; ++t ) if(m_GridSeries[t] == 0) return true; return false; } bool mitk::UnstructuredGrid::VerifyRequestedRegion() { if( (m_RequestedRegion.GetIndex(3)>=0) && (m_RequestedRegion.GetIndex(3)+m_RequestedRegion.GetSize(3)<=m_GridSeries.size()) ) return true; return false; } void mitk::UnstructuredGrid::SetRequestedRegion( itk::DataObject *data ) { mitk::UnstructuredGrid *gridData; gridData = dynamic_cast(data); if (gridData) { m_RequestedRegion = gridData->GetRequestedRegion(); } else { // pointer could not be cast back down itkExceptionMacro( << "mitk::UnstructuredGrid::SetRequestedRegion(DataObject*) cannot cast " << typeid(data).name() << " to " << typeid(UnstructuredGrid*).name() ); } } void mitk::UnstructuredGrid::SetRequestedRegion(UnstructuredGrid::RegionType *region) //by arin { if(region != 0) { m_RequestedRegion = *region; } else { // pointer could not be cast back down itkExceptionMacro( << "mitk::UnstructuredGrid::SetRequestedRegion(UnstructuredGrid::RegionType*) cannot cast " << typeid(region).name() << " to " << typeid(UnstructuredGrid*).name() ); } } void mitk::UnstructuredGrid::CopyInformation( const itk::DataObject * data ) { Superclass::CopyInformation(data); } void mitk::UnstructuredGrid::Update() { if ( GetSource() == 0 ) { for ( VTKUnstructuredGridSeries::iterator it = m_GridSeries.begin() ; it != m_GridSeries.end() ; ++it ) { if ( ( *it ) != 0 ) ( *it )->Update(); } } Superclass::Update(); } diff --git a/Modules/MitkExt/DataManagement/mitkUnstructuredGrid.h b/Modules/MitkExt/DataManagement/mitkUnstructuredGrid.h index 2d4eefa989..347cc86e17 100644 --- a/Modules/MitkExt/DataManagement/mitkUnstructuredGrid.h +++ b/Modules/MitkExt/DataManagement/mitkUnstructuredGrid.h @@ -1,109 +1,113 @@ /*========================================================================= 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 _MITK_UNSTRUCTURED_GRID_H_ #define _MITK_UNSTRUCTURED_GRID_H_ #include "mitkBaseData.h" #include "MitkExtExports.h" #include "itkImageRegion.h" class vtkUnstructuredGrid; namespace mitk { //##Documentation //## @brief Class for storing unstructured grids (vtkUnstructuredGrid) //## @ingroup Data class MitkExt_EXPORT UnstructuredGrid : public BaseData { public: // not yet the best choice of a region-type for surfaces, but it works for the time being typedef itk::ImageRegion< 5 > RegionType; mitkClassMacro(UnstructuredGrid, BaseData); itkNewMacro(Self); + + mitkCloneMacro(UnstructuredGrid); virtual void SetVtkUnstructuredGrid(vtkUnstructuredGrid* grid, unsigned int t = 0); virtual vtkUnstructuredGrid* GetVtkUnstructuredGrid(unsigned int t = 0); virtual void UpdateOutputInformation(); virtual void SetRequestedRegionToLargestPossibleRegion(); virtual bool RequestedRegionIsOutsideOfTheBufferedRegion(); virtual bool VerifyRequestedRegion(); virtual void SetRequestedRegion(itk::DataObject *data); virtual void SetRequestedRegion(UnstructuredGrid::RegionType *region); virtual void CopyInformation(const itk::DataObject *data); virtual void Update(); const RegionType& GetLargestPossibleRegion() const { m_LargestPossibleRegion.SetIndex(3, 0); m_LargestPossibleRegion.SetSize(3, GetTimeSlicedGeometry()->GetTimeSteps()); return m_LargestPossibleRegion; } //##Documentation //## Get the region object that defines the size and starting index //## for the region of the image requested (i.e., the region of the //## image to be operated on by a filter). virtual const RegionType& GetRequestedRegion() const { return m_RequestedRegion; } void CalculateBoundingBox(); protected: typedef std::vector< vtkUnstructuredGrid* > VTKUnstructuredGridSeries; // Initialize should not be called manually; // The polydata vector is initialized automatically when enlarged; virtual void Expand( unsigned int timeSteps = 1 ); UnstructuredGrid(); + + UnstructuredGrid(const mitk::UnstructuredGrid & other); virtual ~UnstructuredGrid(); virtual void ClearData(); virtual void InitializeEmpty(); VTKUnstructuredGridSeries m_GridSeries; mutable RegionType m_LargestPossibleRegion; RegionType m_RequestedRegion; bool m_CalculateBoundingBox; }; } // namespace mitk #endif /* _MITK_UNSTRUCTURED_GRID_H_ */ diff --git a/Modules/MitkExt/Testing/files.cmake b/Modules/MitkExt/Testing/files.cmake index 0d77aae0d5..9ce27db6b0 100644 --- a/Modules/MitkExt/Testing/files.cmake +++ b/Modules/MitkExt/Testing/files.cmake @@ -1,40 +1,41 @@ SET(MODULE_TESTS mitkAutoCropImageFilterTest.cpp mitkBoundingObjectCutterTest.cpp mitkContourMapper2DTest.cpp mitkContourTest.cpp mitkCoreExtObjectFactoryTest mitkDataNodeExtTest.cpp mitkExternalToolsTest.cpp mitkMeshTest.cpp mitkMultiStepperTest.cpp mitkOrganTypePropertyTest.cpp mitkPipelineSmartPointerCorrectnessTest.cpp mitkPlaneFitTest.cpp mitkPointLocatorTest.cpp # mitkSegmentationInterpolationTest.cpp # mitkTestTemplate.cpp mitkToolManagerTest.cpp + mitkUnstructuredGridTest.cpp mitkSimpleHistogramTest.cpp ) SET(MODULE_IMAGE_TESTS mitkUnstructuredGridVtkWriterTest.cpp mitkCompressedImageContainerTest.cpp mitkCylindricToCartesianFilterTest.cpp #mitkExtractImageFilterTest.cpp mitkManualSegmentationToSurfaceFilterTest.cpp mitkOverwriteSliceImageFilterTest.cpp mitkSurfaceToImageFilterTest.cpp ) SET(MODULE_CUSTOM_TESTS mitkLabeledImageToSurfaceFilterTest.cpp ) SET(MODULE_TESTIMAGES US4DCyl.pic.gz Pic3D.pic.gz Pic2DplusT.pic.gz BallBinary30x30x30.pic.gz Png2D-bw.png binary.stl ball.stl ) \ No newline at end of file diff --git a/Modules/MitkExt/Testing/mitkContourTest.cpp b/Modules/MitkExt/Testing/mitkContourTest.cpp index 644d4b7e8f..768726ae74 100644 --- a/Modules/MitkExt/Testing/mitkContourTest.cpp +++ b/Modules/MitkExt/Testing/mitkContourTest.cpp @@ -1,104 +1,62 @@ /*========================================================================= 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 "mitkContour.h" #include "mitkCommon.h" +#include "mitkTestingMacros.h" #include + int mitkContourTest(int /*argc*/, char* /*argv*/[]) { - mitk::Contour::Pointer contour; - std::cout << "Testing mitk::Contour::New(): "; - contour = mitk::Contour::New(); - if (contour.IsNull()) { - std::cout<<"[FAILED]"<AddVertex(p); p.Fill(1); contour->AddVertex(p); p.Fill(2); contour->AddVertex(p); - - if (contour->GetNumberOfPoints() != 3) - { - std::cout<<"[FAILED]"<GetNumberOfPoints() == 3, "Testing AddVertex()"); - std::cout << "Testing mitk::Contour::GetPoints()"; mitk::Contour::PointsContainerPointer points = contour->GetPoints(); - if ( points.IsNull() ) - { - std::cout<<"[FAILED]"<Initialize(); - if (contour->GetNumberOfPoints() != 0) - { - std::cout<<"[FAILED]"<GetNumberOfPoints() == 0, "Testing Initialize()!"); contour->SetPoints(points); - if ( contour->GetNumberOfPoints() != 3) - { - std::cout<<"[FAILED]"<GetNumberOfPoints() == 3, "Testimg SetPoints()!"); mitk::Contour::PathPointer path = contour->GetContourPath(); - if ( path.IsNull() ) - { - return EXIT_FAILURE; - } + MITK_TEST_CONDITION_REQUIRED(path.IsNotNull(), "Testing GetContourPath()!"); contour->UpdateOutputInformation(); contour->SetClosed(false); + MITK_TEST_CONDITION_REQUIRED(!contour->GetClosed(), "Testing GetClosed()!"); - if (contour->GetClosed()) - { - std::cout<<"[FAILED] "<Clone(); + MITK_TEST_CONDITION_REQUIRED(cloneContour.IsNotNull(), "Testing clone instantiation!"); + MITK_TEST_CONDITION_REQUIRED(cloneContour.GetPointer() != contour.GetPointer(), "Testing cloned object is not original object!"); + MITK_TEST_CONDITION_REQUIRED(cloneContour->GetGeometry()->GetCenter() == contour->GetGeometry()->GetCenter(), "Testing if Geometry is cloned!"); + MITK_TEST_CONDITION_REQUIRED(cloneContour->GetPoints() == points, "Testing cloning of point data!"); - std::cout<<"[TEST DONE]"<VerifyRequestedRegion(), "Requested region verification after initialization!"); + + //create a clone object + mitk::UnstructuredGrid::Pointer cloneObject = testObject->Clone(); + MITK_TEST_CONDITION_REQUIRED(cloneObject.IsNotNull(),"Testing instantiation of clone") + MITK_TEST_CONDITION_REQUIRED( cloneObject->VerifyRequestedRegion(), "Requested region verification after initialization of clone!"); + + // set some grid data to the class + vtkUnstructuredGrid* grid = vtkUnstructuredGrid::New(); + testObject->SetVtkUnstructuredGrid(grid); + MITK_TEST_CONDITION_REQUIRED(testObject->GetVtkUnstructuredGrid()== grid, "Testing Set/Get vtkUnstructuredGrid"); + + // specify a region and set it to the test object + mitk::UnstructuredGrid::RegionType* ugRegion = new mitk::UnstructuredGrid::RegionType; + mitk::UnstructuredGrid::RegionType::SizeType size; + size[0] = 100; + size[1] = 100; + size[2] = 100; + + mitk::UnstructuredGrid::RegionType::IndexType index; + index[0] = 0; + index[1] = 0; + index[2] = 0; + + ugRegion->SetSize(size); + ugRegion->SetIndex(index); + testObject->SetRequestedRegion(ugRegion); + testObject->UpdateOutputInformation(); + MITK_TEST_CONDITION_REQUIRED(testObject->GetRequestedRegion().GetSize() == ugRegion->GetSize(), "Testing Set/Get of Requested Region by RegionType1!"); + MITK_TEST_CONDITION_REQUIRED(testObject->GetRequestedRegion().GetIndex() == ugRegion->GetIndex(), "Testing Set/Get of Requested Region by RegionType2!"); + // VerifyRequested Region should be false due to the chosen size parameter! + MITK_TEST_CONDITION_REQUIRED(!testObject->VerifyRequestedRegion(), "Requested Region verification!"); + + mitk::UnstructuredGrid::Pointer copyObject = mitk::UnstructuredGrid::New(); + copyObject->CopyInformation(testObject); + copyObject->SetRequestedRegion(testObject); + MITK_TEST_CONDITION_REQUIRED(copyObject->GetLargestPossibleRegion() == testObject->GetLargestPossibleRegion(), "Testing generation of copy object"); + MITK_TEST_CONDITION_REQUIRED(copyObject->GetRequestedRegion().GetSize() == ugRegion->GetSize(), "Testing SetRequestedRegion by DataObject1"); + MITK_TEST_CONDITION_REQUIRED(copyObject->GetRequestedRegion().GetIndex() == ugRegion->GetIndex(), "Testing SetRequestedRegion by DataObject2"); + + + cloneObject = testObject->Clone(); + MITK_TEST_CONDITION_REQUIRED(cloneObject->GetRequestedRegion() == testObject->GetRequestedRegion(), "Testing region cloning!"); + MITK_TEST_CONDITION_REQUIRED(cloneObject->GetVtkUnstructuredGrid()== grid, "Testing Get/Set-VtkUnstructuredGrid cloning"); + MITK_TEST_CONDITION_REQUIRED(cloneObject->GetRequestedRegion().GetSize() == ugRegion->GetSize(), "Testing Set/Get of Requested Region by RegionType1 in clone!"); + MITK_TEST_CONDITION_REQUIRED(cloneObject->GetRequestedRegion().GetIndex() == ugRegion->GetIndex(), "Testing Set/Get of Requested Region by RegionType2 in clone!"); + // VerifyRequested Region should be false due to the chosen size parameter! + MITK_TEST_CONDITION_REQUIRED(!cloneObject->VerifyRequestedRegion(), "Requested Region verification!"); + + // test this at the very end otherwise several other test cases need to be adapted!! + testObject->SetRequestedRegionToLargestPossibleRegion(); + MITK_TEST_CONDITION_REQUIRED(testObject->GetRequestedRegion().GetSize() == testObject->GetLargestPossibleRegion().GetSize(), "Testing Set/Get LargestPossibleRegion!"); + + // always end with this! + MITK_TEST_END() +} +