diff --git a/Core/Code/Controllers/mitkVtkInteractorCameraController.cpp b/Core/Code/Controllers/mitkVtkInteractorCameraController.cpp index c8235cfb5e..1940097eba 100644 --- a/Core/Code/Controllers/mitkVtkInteractorCameraController.cpp +++ b/Core/Code/Controllers/mitkVtkInteractorCameraController.cpp @@ -1,195 +1,195 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkVtkInteractorCameraController.h" #include "mitkInteractionConst.h" #include #include #include #include "mitkAction.h" #include "mitkVtkPropRenderer.h" mitk::VtkInteractorCameraController::VtkInteractorCameraController(const char* type) : CameraController(type), m_VtkInteractor(NULL) { //m_VtkInteractor = vtkRenderWindowInteractor::New(); } mitk::VtkInteractorCameraController::~VtkInteractorCameraController() { if(m_VtkInteractor!=NULL) { m_VtkInteractor->SetRenderWindow(NULL); m_VtkInteractor->Delete(); m_VtkInteractor = NULL; } } void mitk::VtkInteractorCameraController::Resize(int w, int h) { if(m_VtkInteractor) m_VtkInteractor->SetSize(w, h); } void mitk::VtkInteractorCameraController::MousePressEvent(mitk::MouseEvent *me) { MITK_INFO<<"Called MousePressEvent() in VtkInteractorCameraController. Seems to be obsolete after QVTK restructuring (bug #1503, bug #954)"<GetEnabled()) { return; } int ctrl = me->GetButtonState() & BS_ControlButton; int shift = me->GetButtonState() & BS_ShiftButton; int xp = (int)me->GetDisplayPosition()[0]; int yp = (int)me->GetDisplayPosition()[1]; m_VtkInteractor->SetEventInformationFlipY(xp, yp, ctrl, shift); switch (me->GetButton()) { case BS_LeftButton: m_VtkInteractor->InvokeEvent(vtkCommand::LeftButtonPressEvent,NULL); break; case BS_MidButton: m_VtkInteractor->InvokeEvent(vtkCommand::MiddleButtonPressEvent,NULL); break; case BS_RightButton: m_VtkInteractor->InvokeEvent(vtkCommand::RightButtonPressEvent,NULL); break; default: return; } } } void mitk::VtkInteractorCameraController::MouseReleaseEvent(mitk::MouseEvent *me) { MITK_INFO<<"Called MouseReleaseEvent() in VtkInteractorCameraController. Seems to be obsolete after QVTK restructuring (bug #1503, bug #954)"<GetEnabled()) { return; } int ctrl = me->GetButtonState() & BS_ControlButton; int shift = me->GetButtonState() & BS_ShiftButton; int xp = (int)me->GetDisplayPosition()[0]; int yp = (int)me->GetDisplayPosition()[1]; m_VtkInteractor->SetEventInformationFlipY(xp, yp, ctrl, shift); switch (me->GetButton()) { case BS_LeftButton: m_VtkInteractor->InvokeEvent(vtkCommand::LeftButtonReleaseEvent,NULL); break; case BS_MidButton: m_VtkInteractor->InvokeEvent(vtkCommand::MiddleButtonReleaseEvent,NULL); break; case BS_RightButton: m_VtkInteractor->InvokeEvent(vtkCommand::RightButtonReleaseEvent,NULL); break; default: return; } } } void mitk::VtkInteractorCameraController::MouseMoveEvent(mitk::MouseEvent *me) { MITK_INFO<<"Called MouseMoveEvent() in VtkInteractorCameraController. Seems to be obsolete after QVTK restructuring (bug #1503, bug #954)"<GetEnabled()) { return; } int ctrl = me->GetButtonState() & BS_ControlButton; int shift = me->GetButtonState() & BS_ShiftButton; int xp = (int)me->GetDisplayPosition()[0]; int yp = (int)me->GetDisplayPosition()[1]; m_VtkInteractor->SetEventInformationFlipY(xp, yp, ctrl, shift); m_VtkInteractor->InvokeEvent(vtkCommand::MouseMoveEvent, NULL); } } void mitk::VtkInteractorCameraController::KeyPressEvent(mitk::KeyEvent *ke) { MITK_INFO<<"Called KeyPressEvent() in VtkInteractorCameraController. Seems to be obsolete after QVTK restructuring (bug #1503, bug #954)"<GetEnabled()) { return; } int ctrl = ke->GetButtonState() & BS_ControlButton; int shift = ke->GetButtonState() & BS_ShiftButton; Point2D p(ke->GetDisplayPosition()); - m_VtkInteractor->SetEventInformationFlipY(p[0], p[1], ctrl, shift, tolower(ke->GetText()[0]), 1, ke->GetText()); + m_VtkInteractor->SetEventInformationFlipY(static_cast(p[0]), static_cast(p[1]), ctrl, shift, tolower(ke->GetText()[0]), 1, ke->GetText()); m_VtkInteractor->InvokeEvent(vtkCommand::KeyPressEvent, NULL); m_VtkInteractor->InvokeEvent(vtkCommand::CharEvent, NULL); } } void mitk::VtkInteractorCameraController::SetRenderer(const mitk::BaseRenderer* renderer) { Superclass::SetRenderer(renderer); if (renderer) { // CHG 11-07: QVTK-Widget comes along with vtkRenderWindow and vtkRenWinInteractor, therefore do not // generate a new one any more m_VtkInteractor = renderer->GetVtkRenderer()->GetRenderWindow()->GetInteractor(); m_VtkInteractor->SetRenderWindow(renderer->GetVtkRenderer()->GetRenderWindow()); // Enable possibility to (mouse-)interact with the renderer m_VtkInteractor->Enable(); m_VtkInteractor->Register(NULL); } /* VtkRenderWindowInteractor* windowInteractor = dynamic_cast(m_VtkInteractor); if (windowInteractor == NULL) { itkWarningMacro(<< "renderwindow is not an mitk::VtkRenderWindow"); } else { windowInteractor->SetMitkRenderer(const_cast(this->GetRenderer())); } m_VtkInteractor->Initialize(); m_VtkInteractor->SetRenderWindow(renderer->GetVtkRenderWindow()); } else { m_VtkInteractor->SetRenderWindow(NULL); m_VtkInteractor->Delete(); m_VtkInteractor = NULL; }*/ } vtkRenderWindowInteractor* mitk::VtkInteractorCameraController::GetVtkInteractor() { return m_VtkInteractor; } ///* //bool mitk::VtkInteractorCameraController::ExecuteAction(Action*, mitk::StateEvent const * /*stateEvent*/ //{ // return false; //} //*/ diff --git a/Core/Code/DataManagement/mitkDataStorage.cpp b/Core/Code/DataManagement/mitkDataStorage.cpp index 396e6bddea..6e22ebfffc 100644 --- a/Core/Code/DataManagement/mitkDataStorage.cpp +++ b/Core/Code/DataManagement/mitkDataStorage.cpp @@ -1,512 +1,512 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkDataStorage.h" #include "mitkDataNode.h" #include "mitkProperties.h" #include "mitkNodePredicateBase.h" #include "mitkNodePredicateProperty.h" #include "mitkGroupTagProperty.h" #include "itkMutexLockHolder.h" #include "itkCommand.h" mitk::DataStorage::DataStorage() : itk::Object() , m_BlockNodeModifiedEvents(false) { } mitk::DataStorage::~DataStorage() { ///// we can not call GetAll() in destructor, because it is implemented in a subclass //SetOfObjects::ConstPointer all = this->GetAll(); //for (SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) // this->RemoveListeners(it->Value()); //m_NodeModifiedObserverTags.clear(); //m_NodeDeleteObserverTags.clear(); } void mitk::DataStorage::Add(mitk::DataNode* node, mitk::DataNode* parent) { mitk::DataStorage::SetOfObjects::Pointer parents = mitk::DataStorage::SetOfObjects::New(); parents->InsertElement(0, parent); this->Add(node, parents); } void mitk::DataStorage::Remove(const mitk::DataStorage::SetOfObjects* nodes) { if (nodes == NULL) return; for (mitk::DataStorage::SetOfObjects::ConstIterator it = nodes->Begin(); it != nodes->End(); it++) this->Remove(it.Value()); } mitk::DataStorage::SetOfObjects::ConstPointer mitk::DataStorage::GetSubset(const NodePredicateBase* condition) const { mitk::DataStorage::SetOfObjects::ConstPointer result = this->FilterSetOfObjects(this->GetAll(), condition); return result; } mitk::DataNode* mitk::DataStorage::GetNamedNode(const char* name) const { if (name == NULL) return NULL; mitk::StringProperty::Pointer s(mitk::StringProperty::New(name)); mitk::NodePredicateProperty::Pointer p = mitk::NodePredicateProperty::New("name", s); mitk::DataStorage::SetOfObjects::ConstPointer rs = this->GetSubset(p); if (rs->Size() >= 1) return rs->GetElement(0); else return NULL; } mitk::DataNode* mitk::DataStorage::GetNode(const NodePredicateBase* condition) const { if (condition == NULL) return NULL; mitk::DataStorage::SetOfObjects::ConstPointer rs = this->GetSubset(condition); if (rs->Size() >= 1) return rs->GetElement(0); else return NULL; } mitk::DataNode* mitk::DataStorage::GetNamedDerivedNode(const char* name, const mitk::DataNode* sourceNode, bool onlyDirectDerivations) const { if (name == NULL) return NULL; mitk::StringProperty::Pointer s(mitk::StringProperty::New(name)); mitk::NodePredicateProperty::Pointer p = mitk::NodePredicateProperty::New("name", s); mitk::DataStorage::SetOfObjects::ConstPointer rs = this->GetDerivations(sourceNode, p, onlyDirectDerivations); if (rs->Size() >= 1) return rs->GetElement(0); else return NULL; } void mitk::DataStorage::PrintSelf(std::ostream& os, itk::Indent indent) const { //Superclass::PrintSelf(os, indent); mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetAll(); os << indent << "DataStorage " << this << " is managing " << all->Size() << " objects. List of objects:" << std::endl; for (mitk::DataStorage::SetOfObjects::ConstIterator allIt = all->Begin(); allIt != all->End(); allIt++) { std::string name; allIt.Value()->GetName(name); std::string datatype; if (allIt.Value()->GetData() != NULL) datatype = allIt.Value()->GetData()->GetNameOfClass(); os << indent << " " << allIt.Value().GetPointer() << "<" << datatype << ">: " << name << std::endl; mitk::DataStorage::SetOfObjects::ConstPointer parents = this->GetSources(allIt.Value()); if (parents->Size() > 0) { os << indent << " Direct sources: "; for (mitk::DataStorage::SetOfObjects::ConstIterator parentIt = parents->Begin(); parentIt != parents->End(); parentIt++) os << parentIt.Value().GetPointer() << ", "; os << std::endl; } mitk::DataStorage::SetOfObjects::ConstPointer derivations = this->GetDerivations(allIt.Value()); if (derivations->Size() > 0) { os << indent << " Direct derivations: "; for (mitk::DataStorage::SetOfObjects::ConstIterator derivationIt = derivations->Begin(); derivationIt != derivations->End(); derivationIt++) os << derivationIt.Value().GetPointer() << ", "; os << std::endl; } } os << std::endl; } mitk::DataStorage::SetOfObjects::ConstPointer mitk::DataStorage::FilterSetOfObjects(const SetOfObjects* set, const NodePredicateBase* condition) const { if (set == NULL) return NULL; mitk::DataStorage::SetOfObjects::Pointer result = mitk::DataStorage::SetOfObjects::New(); for (mitk::DataStorage::SetOfObjects::ConstIterator it = set->Begin(); it != set->End(); it++) if (condition == NULL || condition->CheckNode(it.Value()) == true) //alway copy the set, otherwise the iterator in mitk::DataStorage::Remove() will crash result->InsertElement(result->Size(), it.Value()); return mitk::DataStorage::SetOfObjects::ConstPointer(result); } const mitk::DataNode::GroupTagList mitk::DataStorage::GetGroupTags() const { DataNode::GroupTagList result; SetOfObjects::ConstPointer all = this->GetAll(); if (all.IsNull()) return result; for (mitk::DataStorage::SetOfObjects::ConstIterator nodeIt = all->Begin(); nodeIt != all->End(); nodeIt++) // for each node { mitk::PropertyList* pl = nodeIt.Value()->GetPropertyList(); for (mitk::PropertyList::PropertyMap::const_iterator propIt = pl->GetMap()->begin(); propIt != pl->GetMap()->end(); propIt++) if (dynamic_cast(propIt->second.GetPointer()) != NULL) result.insert(propIt->first); } return result; } void mitk::DataStorage::EmitAddNodeEvent(const mitk::DataNode* node) { AddNodeEvent.Send(node); } void mitk::DataStorage::EmitRemoveNodeEvent(const mitk::DataNode* node) { RemoveNodeEvent.Send(node); } void mitk::DataStorage::OnNodeModifiedOrDeleted( const itk::Object *caller, const itk::EventObject &event ) { if(m_BlockNodeModifiedEvents) return; const mitk::DataNode* _Node = dynamic_cast(caller); if(_Node) { const itk::ModifiedEvent* modEvent = dynamic_cast(&event); if(modEvent) ChangedNodeEvent.Send(_Node); else DeleteNodeEvent.Send(_Node); } } void mitk::DataStorage::AddListeners( const mitk::DataNode* _Node ) { itk::MutexLockHolder locked(m_MutexOne); // node must not be 0 and must not be yet registered mitk::DataNode* NonConstNode = const_cast(_Node); if(_Node && m_NodeModifiedObserverTags .find(NonConstNode) == m_NodeModifiedObserverTags.end()) { itk::MemberCommand::Pointer nodeModifiedCommand = itk::MemberCommand::New(); nodeModifiedCommand->SetCallbackFunction(this , &mitk::DataStorage::OnNodeModifiedOrDeleted); m_NodeModifiedObserverTags[NonConstNode] = NonConstNode->AddObserver(itk::ModifiedEvent(), nodeModifiedCommand); // add itk delete listener on datastorage itk::MemberCommand::Pointer deleteCommand = itk::MemberCommand::New(); deleteCommand->SetCallbackFunction(this, &mitk::DataStorage::OnNodeModifiedOrDeleted); // add observer m_NodeDeleteObserverTags[NonConstNode] = NonConstNode->AddObserver(itk::DeleteEvent(), deleteCommand); } } void mitk::DataStorage::RemoveListeners( const mitk::DataNode* _Node ) { itk::MutexLockHolder locked(m_MutexOne) ; // node must not be 0 and must be registered mitk::DataNode* NonConstNode = const_cast(_Node); if(_Node && m_NodeModifiedObserverTags .find(NonConstNode) != m_NodeModifiedObserverTags.end()) { // const cast is bad! but sometimes it is necessary. removing an observer does not really // touch the internal state NonConstNode->RemoveObserver(m_NodeModifiedObserverTags .find(NonConstNode)->second); NonConstNode->RemoveObserver(m_NodeDeleteObserverTags .find(NonConstNode)->second); m_NodeModifiedObserverTags.erase(NonConstNode); m_NodeDeleteObserverTags.erase(NonConstNode); } } mitk::TimeSlicedGeometry::Pointer mitk::DataStorage::ComputeBoundingGeometry3D( const SetOfObjects* input, const char* boolPropertyKey, mitk::BaseRenderer* renderer, const char* boolPropertyKey2) { if (input == NULL) throw std::invalid_argument("DataStorage: input is invalid"); BoundingBox::PointsContainer::Pointer pointscontainer=BoundingBox::PointsContainer::New(); BoundingBox::PointIdentifier pointid=0; Point3D point; Vector3D minSpacing; minSpacing.Fill(ScalarTypeNumericTraits::max()); ScalarType stmin, stmax; stmin= ScalarTypeNumericTraits::NonpositiveMin(); stmax= ScalarTypeNumericTraits::max(); ScalarType minimalIntervallSize = stmax; ScalarType minimalTime = stmax; ScalarType maximalTime = 0; // Needed for check of zero bounding boxes mitk::ScalarType nullpoint[]={0,0,0,0,0,0}; BoundingBox::BoundsArrayType itkBoundsZero(nullpoint); for (SetOfObjects::ConstIterator it = input->Begin(); it != input->End(); ++it) { DataNode::Pointer node = it->Value(); if((node.IsNotNull()) && (node->GetData() != NULL) && (node->GetData()->IsEmpty()==false) && node->IsOn(boolPropertyKey, renderer) && node->IsOn(boolPropertyKey2, renderer) ) { const TimeSlicedGeometry* geometry = node->GetData()->GetUpdatedTimeSlicedGeometry(); if (geometry != NULL ) { // bounding box (only if non-zero) BoundingBox::BoundsArrayType itkBounds = geometry->GetBoundingBox()->GetBounds(); if (itkBounds == itkBoundsZero) { continue; } unsigned char i; for(i=0; i<8; ++i) { point = geometry->GetCornerPoint(i); if(point[0]*point[0]+point[1]*point[1]+point[2]*point[2] < large) pointscontainer->InsertElement( pointid++, point); else { itkGenericOutputMacro( << "Unrealistically distant corner point encountered. Ignored. Node: " << node ); } } // spacing try { AffineTransform3D::Pointer inverseTransform = AffineTransform3D::New(); geometry->GetIndexToWorldTransform()->GetInverse(inverseTransform); vnl_vector< AffineTransform3D::MatrixType::ValueType > unitVector(3); int axis; for(axis = 0; axis < 3; ++axis) { unitVector.fill(0); unitVector[axis] = 1.0; ScalarType mmPerPixel = 1.0/(inverseTransform->GetMatrix()*unitVector).magnitude(); if(minSpacing[axis] > mmPerPixel) { minSpacing[axis] = mmPerPixel; } } // time bounds // iterate over all time steps // Attention: Objects with zero bounding box are not respected in time bound calculation TimeBounds minTB = geometry->GetTimeBounds(); for (unsigned int i=0; iGetTimeSteps(); i++) { const TimeBounds & curTimeBounds = node->GetData()->GetGeometry(i)->GetTimeBounds(); // get the minimal time of all objects in the DataStorage if ((curTimeBounds[0]stmin)) { minimalTime=curTimeBounds[0]; } // get the maximal time of all objects in the DataStorage if ((curTimeBounds[1]>maximalTime)&&(curTimeBounds[1]SetPoints(pointscontainer); result->ComputeBoundingBox(); // minimal time bounds of a single time step for all geometries TimeBounds minTimeBounds; minTimeBounds[0] = 0; minTimeBounds[1] = 1; // compute the number of time steps unsigned int numberOfTimeSteps = 1; if (maximalTime!=0) // make sure that there is at least one time sliced geometry in the data storage { minTimeBounds[0] = minimalTime; minTimeBounds[1] = minimalTime + minimalIntervallSize; - numberOfTimeSteps = (maximalTime-minimalTime)/minimalIntervallSize; + numberOfTimeSteps = static_cast((maximalTime-minimalTime)/minimalIntervallSize); } TimeSlicedGeometry::Pointer timeSlicedGeometry = NULL; if ( result->GetPoints()->Size()>0 ) { // Initialize a geometry of a single time step Geometry3D::Pointer geometry = Geometry3D::New(); geometry->Initialize(); // correct bounding-box (is now in mm, should be in index-coordinates) // according to spacing BoundingBox::BoundsArrayType bounds = result->GetBounds(); int i; for(i = 0; i < 6; ++i) { bounds[i] /= minSpacing[i/2]; } geometry->SetBounds(bounds); geometry->SetSpacing(minSpacing); geometry->SetTimeBounds(minTimeBounds); // Initialize the time sliced geometry timeSlicedGeometry = TimeSlicedGeometry::New(); timeSlicedGeometry->InitializeEvenlyTimed(geometry,numberOfTimeSteps); } return timeSlicedGeometry; } mitk::TimeSlicedGeometry::Pointer mitk::DataStorage::ComputeBoundingGeometry3D( const char* boolPropertyKey, mitk::BaseRenderer* renderer, const char* boolPropertyKey2) { return this->ComputeBoundingGeometry3D(this->GetAll(), boolPropertyKey, renderer, boolPropertyKey2); } mitk::TimeSlicedGeometry::Pointer mitk::DataStorage::ComputeVisibleBoundingGeometry3D( mitk::BaseRenderer* renderer, const char* boolPropertyKey ) { return ComputeBoundingGeometry3D( "visible", renderer, boolPropertyKey ); } mitk::BoundingBox::Pointer mitk::DataStorage::ComputeBoundingBox( const char* boolPropertyKey, mitk::BaseRenderer* renderer, const char* boolPropertyKey2) { BoundingBox::PointsContainer::Pointer pointscontainer=BoundingBox::PointsContainer::New(); BoundingBox::PointIdentifier pointid=0; Point3D point; // Needed for check of zero bounding boxes mitk::ScalarType nullpoint[]={0,0,0,0,0,0}; BoundingBox::BoundsArrayType itkBoundsZero(nullpoint); SetOfObjects::ConstPointer all = this->GetAll(); for (SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) { DataNode::Pointer node = it->Value(); if((node.IsNotNull()) && (node->GetData() != NULL) && (node->GetData()->IsEmpty()==false) && node->IsOn(boolPropertyKey, renderer) && node->IsOn(boolPropertyKey2, renderer) ) { const Geometry3D* geometry = node->GetData()->GetUpdatedTimeSlicedGeometry(); if (geometry != NULL ) { // bounding box (only if non-zero) BoundingBox::BoundsArrayType itkBounds = geometry->GetBoundingBox()->GetBounds(); if (itkBounds == itkBoundsZero) { continue; } unsigned char i; for(i=0; i<8; ++i) { point = geometry->GetCornerPoint(i); if(point[0]*point[0]+point[1]*point[1]+point[2]*point[2] < large) pointscontainer->InsertElement( pointid++, point); else { itkGenericOutputMacro( << "Unrealistically distant corner point encountered. Ignored. Node: " << node ); } } } } } BoundingBox::Pointer result = BoundingBox::New(); result->SetPoints(pointscontainer); result->ComputeBoundingBox(); return result; } mitk::TimeBounds mitk::DataStorage::ComputeTimeBounds( const char* boolPropertyKey, mitk::BaseRenderer* renderer, const char* boolPropertyKey2) { TimeBounds timeBounds; ScalarType stmin, stmax, cur; stmin= ScalarTypeNumericTraits::NonpositiveMin(); stmax= ScalarTypeNumericTraits::max(); timeBounds[0]=stmax; timeBounds[1]=stmin; SetOfObjects::ConstPointer all = this->GetAll(); for (SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) { DataNode::Pointer node = it->Value(); if((node.IsNotNull()) && (node->GetData() != NULL) && (node->GetData()->IsEmpty()==false) && node->IsOn(boolPropertyKey, renderer) && node->IsOn(boolPropertyKey2, renderer) ) { const Geometry3D* geometry = node->GetData()->GetUpdatedTimeSlicedGeometry(); if (geometry != NULL ) { const TimeBounds & curTimeBounds = geometry->GetTimeBounds(); cur=curTimeBounds[0]; //is it after -infinity, but before everything else that we found until now? if((cur > stmin) && (cur < timeBounds[0])) timeBounds[0] = cur; cur=curTimeBounds[1]; //is it before infinity, but after everything else that we found until now? if((cur < stmax) && (cur > timeBounds[1])) timeBounds[1] = cur; } } } if(!(timeBounds[0] < stmax)) { timeBounds[0] = stmin; timeBounds[1] = stmax; } return timeBounds; } diff --git a/Core/Code/DataManagement/mitkImage.cpp b/Core/Code/DataManagement/mitkImage.cpp index a9f31623dd..397e027b78 100644 --- a/Core/Code/DataManagement/mitkImage.cpp +++ b/Core/Code/DataManagement/mitkImage.cpp @@ -1,1278 +1,1280 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkImage.h" #include "mitkImageStatisticsHolder.h" #include "mitkPixelTypeMultiplex.h" #include +#include + #define FILL_C_ARRAY( _arr, _size, _value) for(unsigned int i=0u; i<_size; i++) \ { _arr[i] = _value; } mitk::Image::Image() : m_Dimension(0), m_Dimensions(NULL), m_ImageDescriptor(NULL), m_OffsetTable(NULL), m_CompleteData(NULL), m_ImageStatistics(NULL) { m_Dimensions = new unsigned int[MAX_IMAGE_DIMENSIONS]; FILL_C_ARRAY( m_Dimensions, MAX_IMAGE_DIMENSIONS, 0u); m_Initialized = false; } mitk::Image::Image(const Image &other) : SlicedData(other), m_Dimension(0), m_Dimensions(NULL), m_ImageDescriptor(NULL), m_OffsetTable(NULL), m_CompleteData(NULL), m_ImageStatistics(NULL) { m_Dimensions = new unsigned int[MAX_IMAGE_DIMENSIONS]; FILL_C_ARRAY( m_Dimensions, MAX_IMAGE_DIMENSIONS, 0u); this->Initialize( other.GetPixelType(), other.GetDimension(), other.GetDimensions()); //Since the above called "Initialize" method doesn't take the geometry into account we need to set it //here manually this->SetGeometry(dynamic_cast(other.GetGeometry()->Clone().GetPointer())); 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_ReferenceCountLock.Lock(); m_ReferenceCount = 0; m_ReferenceCountLock.Unlock(); if(m_OffsetTable != NULL) delete [] m_OffsetTable; if(m_ImageStatistics != NULL) delete m_ImageStatistics; } const mitk::PixelType mitk::Image::GetPixelType(int n) const { return this->m_ImageDescriptor->GetChannelTypeById(n); } 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().IsNull()) return NULL; if(GetSource()->Updating()==false) GetSource()->UpdateOutputInformation(); } m_CompleteData=GetChannelData(); // update channel's data // if data was not available at creation point, the m_Data of channel descriptor is NULL // if data present, it won't be overwritten m_ImageDescriptor->GetChannelDescriptor(0).SetData(m_CompleteData->GetData()); return m_CompleteData->GetData(); } template void AccessPixel( const mitk::PixelType ptype, void* data, const unsigned int offset, double& value ) { value = 0.0; if( data == NULL ) return; if(ptype.GetBpe() != 24) { value = (double) (((T*) data)[ offset ]); } else { const unsigned int rgboffset = 3 * offset; double returnvalue = (((T*) data)[rgboffset ]); returnvalue += (((T*) data)[rgboffset + 1]); returnvalue += (((T*) data)[rgboffset + 2]); value = returnvalue; } } double mitk::Image::GetPixelValueByIndex(const mitk::Index3D &position, unsigned int timestep) { double value = 0; if (this->GetTimeSteps() < timestep) { timestep = this->GetTimeSteps(); } value = 0.0; const unsigned int* imageDims = this->m_ImageDescriptor->GetDimensions(); const mitk::PixelType ptype = this->m_ImageDescriptor->GetChannelTypeById(0); // Comparison ?>=0 not needed since all position[i] and timestep are unsigned int // (position[0]>=0 && position[1] >=0 && position[2]>=0 && timestep>=0) // && if ( (unsigned int)position[0] < imageDims[0] && (unsigned int)position[1] < imageDims[1] && ( (imageDims[2] == 0) || (unsigned int)position[2] < imageDims[2]) // in case a 2D Image passed in, the third dimension could be set to 0 causing the if() to fail /*&& (unsigned int)timestep < imageDims[3]*/ ) { const unsigned int offset = position[0] + position[1]*imageDims[0] + position[2]*imageDims[0]*imageDims[1] + timestep*imageDims[0]*imageDims[1]*imageDims[2]; mitkPixelTypeMultiplex3( AccessPixel, ptype, this->GetData(), offset, value ); } return value; } double mitk::Image::GetPixelValueByWorldCoordinate(const mitk::Point3D& position, unsigned int timestep) { double value = 0.0; if (this->GetTimeSteps() < timestep) { timestep = this->GetTimeSteps(); } Index3D itkIndex; this->GetGeometry()->WorldToIndex(position, itkIndex); const unsigned int* imageDims = this->m_ImageDescriptor->GetDimensions(); const mitk::PixelType ptype = this->m_ImageDescriptor->GetChannelTypeById(0); //if ( (itkIndex[0]>=0 && itkIndex[1] >=0 && itkIndex[2]>=0 && timestep>=0) // && // lines above taken from comparison since always true due to unsigned type if (((unsigned int)itkIndex[0] < imageDims[0] && (unsigned int)itkIndex[1] < imageDims[1] && (imageDims[2] == 0) ) || ((unsigned int)itkIndex[2] < imageDims[2])) // in case a 2D Image passed in, the third dimension could be set to 0 causing the if() to fail { const unsigned int offset = itkIndex[0] + itkIndex[1]*imageDims[0] + itkIndex[2]*imageDims[0]*imageDims[1] + timestep*imageDims[0]*imageDims[1]*imageDims[2]; mitkPixelTypeMultiplex3( AccessPixel, ptype, this->GetData(), offset, value ); } return value; } vtkImageData* mitk::Image::GetVtkImageData(int t, int n) { if(m_Initialized==false) { if(GetSource().IsNull()) 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(); } mitk::Image::ImageDataItemPointer mitk::Image::GetSliceData(int s, int t, int n, void *data, ImportMemoryManagementType importMemoryManagement) { if(IsValidSlice(s,t,n)==false) return NULL; const size_t ptypeSize = this->m_ImageDescriptor->GetChannelTypeById(n).GetSize(); // 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, m_ImageDescriptor, 2, data, importMemoryManagement == ManageMemory, ((size_t) s)*m_OffsetTable[2]*(ptypeSize)); 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, m_ImageDescriptor, 2, data, importMemoryManagement == ManageMemory, (((size_t) s)*m_OffsetTable[2]+((size_t) t)*m_OffsetTable[3])*(ptypeSize)); sl->SetComplete(true); return m_Slices[pos]=sl; } // slice is unavailable. Can we calculate it? if((GetSource().IsNotNull()) && (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; const size_t ptypeSize = this->m_ImageDescriptor->GetChannelTypeById(n).GetSize(); // 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, m_ImageDescriptor, 3, data, importMemoryManagement == ManageMemory, (((size_t) t)*m_OffsetTable[3])*(ptypeSize)); 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 { mitk::PixelType chPixelType = this->m_ImageDescriptor->GetChannelTypeById(n); vol=m_Volumes[pos]; // ok, let's combine the slices! if(vol.GetPointer()==NULL) vol=new ImageDataItem( chPixelType, 3, m_Dimensions, NULL, true); vol->SetComplete(true); size_t size=m_OffsetTable[2]*(ptypeSize); 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); // FIXME mitkIpPicDescriptor * pic = sl->GetPicDescriptor(); // replace old slice with reference to volume sl=new ImageDataItem(*vol, m_ImageDescriptor, 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().IsNotNull()) && (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, m_ImageDescriptor, m_ImageDescriptor->GetNumberOfDimensions(), data, importMemoryManagement == ManageMemory); ch->SetComplete(true); } else { const size_t ptypeSize = this->m_ImageDescriptor->GetChannelTypeById(n).GetSize(); ch=m_Channels[n]; // ok, let's combine the volumes! if(ch.GetPointer()==NULL) ch=new ImageDataItem(this->m_ImageDescriptor, NULL, true); ch->SetComplete(true); size_t size=m_OffsetTable[m_Dimension-1]*(ptypeSize); 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]*(ptypeSize); std::memcpy(static_cast(ch->GetData())+offset, vol->GetData(), size); // REVEIW FIX mitkIpPicDescriptor * pic = vol->GetPicDescriptor(); // replace old volume with reference to channel vol=new ImageDataItem(*ch, m_ImageDescriptor, 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; } } } // REVIEW FIX // 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().IsNotNull()) && (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; const size_t ptypeSize = this->m_ImageDescriptor->GetChannelTypeById(n).GetSize(); 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]*(ptypeSize)); 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]*(ptypeSize)); //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; const size_t ptypeSize = this->m_ImageDescriptor->GetChannelTypeById(n).GetSize(); 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]*(ptypeSize)); 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]*(ptypeSize)); } vol->SetComplete(true); this->m_ImageDescriptor->GetChannelDescriptor(n).SetData( vol->GetData() ); //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; // channel descriptor const size_t ptypeSize = this->m_ImageDescriptor->GetChannelTypeById(n).GetSize(); 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]*(ptypeSize)); 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]*(ptypeSize)); ch->SetComplete(true); this->m_ImageDescriptor->GetChannelDescriptor(n).SetData( ch->GetData() ); //we just added a missing Channel, which is not regarded as modification. //Therefore, we do not call Modified()! } return true; } 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; if( m_ImageStatistics == NULL) { m_ImageStatistics = new mitk::ImageStatisticsHolder( this ); } SetRequestedRegionToLargestPossibleRegion(); } void mitk::Image::Initialize(const mitk::ImageDescriptor::Pointer inDesc) { // store the descriptor this->m_ImageDescriptor = inDesc; // initialize image this->Initialize( inDesc->GetChannelDescriptor(0).GetPixelType(), inDesc->GetNumberOfDimensions(), inDesc->GetDimensions(), 1 ); } void mitk::Image::Initialize(const mitk::PixelType& type, unsigned int dimension, const unsigned int *dimensions, unsigned int channels) { Clear(); m_Dimension=dimension; if(!dimensions) itkExceptionMacro(<< "invalid zero dimension image"); unsigned int i; for(i=0;im_ImageDescriptor = mitk::ImageDescriptor::New(); this->m_ImageDescriptor->Initialize( this->m_Dimensions, this->m_Dimension ); 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; } for( unsigned int i=0u; im_ImageDescriptor->AddNewChannel( 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; this->m_ImageDescriptor->Initialize( this->m_Dimensions, this->m_Dimension ); 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(), *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; } switch ( vtkimagedata->GetScalarType() ) { case VTK_BIT: case VTK_CHAR: //pixelType.Initialize(typeid(char), vtkimagedata->GetNumberOfScalarComponents()); Initialize(mitk::MakeScalarPixelType(), m_Dimension, tmpDimensions, channels); break; case VTK_UNSIGNED_CHAR: //pixelType.Initialize(typeid(unsigned char), vtkimagedata->GetNumberOfScalarComponents()); Initialize(mitk::MakeScalarPixelType(), m_Dimension, tmpDimensions, channels); break; case VTK_SHORT: //pixelType.Initialize(typeid(short), vtkimagedata->GetNumberOfScalarComponents()); Initialize(mitk::MakeScalarPixelType(), m_Dimension, tmpDimensions, channels); break; case VTK_UNSIGNED_SHORT: //pixelType.Initialize(typeid(unsigned short), vtkimagedata->GetNumberOfScalarComponents()); Initialize(mitk::MakeScalarPixelType(), m_Dimension, tmpDimensions, channels); break; case VTK_INT: //pixelType.Initialize(typeid(int), vtkimagedata->GetNumberOfScalarComponents()); Initialize(mitk::MakeScalarPixelType(), m_Dimension, tmpDimensions, channels); break; case VTK_UNSIGNED_INT: //pixelType.Initialize(typeid(unsigned int), vtkimagedata->GetNumberOfScalarComponents()); Initialize(mitk::MakeScalarPixelType(), m_Dimension, tmpDimensions, channels); break; case VTK_LONG: //pixelType.Initialize(typeid(long), vtkimagedata->GetNumberOfScalarComponents()); Initialize(mitk::MakeScalarPixelType(), m_Dimension, tmpDimensions, channels); break; case VTK_UNSIGNED_LONG: //pixelType.Initialize(typeid(unsigned long), vtkimagedata->GetNumberOfScalarComponents()); Initialize(mitk::MakeScalarPixelType(), m_Dimension, tmpDimensions, channels); break; case VTK_FLOAT: //pixelType.Initialize(typeid(float), vtkimagedata->GetNumberOfScalarComponents()); Initialize(mitk::MakeScalarPixelType(), m_Dimension, tmpDimensions, channels); break; case VTK_DOUBLE: //pixelType.Initialize(typeid(double), vtkimagedata->GetNumberOfScalarComponents()); Initialize(mitk::MakeScalarPixelType(), m_Dimension, tmpDimensions, channels); 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; } 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; } 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!"); Superclass::Expand(timeSteps); } 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); const size_t ptypeSize = this->m_ImageDescriptor->GetChannelTypeById(n).GetSize(); // 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, m_ImageDescriptor, 2, data, importMemoryManagement == ManageMemory, ((size_t) s)*m_OffsetTable[2]*(ptypeSize)); 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, m_ImageDescriptor, 2, data, importMemoryManagement == ManageMemory, (((size_t) s)*m_OffsetTable[2]+((size_t) t)*m_OffsetTable[3])*(ptypeSize)); 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, m_ImageDescriptor, 2, data, importMemoryManagement == ManageMemory, ((size_t) s)*m_OffsetTable[2]*(ptypeSize)); 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); const size_t ptypeSize = this->m_ImageDescriptor->GetChannelTypeById(n).GetSize(); // 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, m_ImageDescriptor, 3, data,importMemoryManagement == ManageMemory, (((size_t) t)*m_OffsetTable[3])*(ptypeSize)); return m_Volumes[pos]=vol; } mitk::PixelType chPixelType = this->m_ImageDescriptor->GetChannelTypeById(n); // allocate new volume if(importMemoryManagement == CopyMemory) { vol=new ImageDataItem( chPixelType, 3, m_Dimensions, NULL, true); if(data != NULL) std::memcpy(vol->GetData(), data, m_OffsetTable[3]*(ptypeSize)); } else { vol=new ImageDataItem( chPixelType, 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) { const size_t ptypeSize = this->m_ImageDescriptor->GetChannelTypeById(n).GetSize(); ch=new ImageDataItem(this->m_ImageDescriptor, NULL, true); if(data != NULL) std::memcpy(ch->GetData(), data, m_OffsetTable[4]*(ptypeSize)); } else { ch=new ImageDataItem(this->m_ImageDescriptor, 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(); } void mitk::Image::PrintSelf(std::ostream& os, itk::Indent indent) const { unsigned char i; if(m_Initialized) { os << indent << " Dimension: " << m_Dimension << std::endl; os << indent << " Dimensions: "; for(i=0; i < m_Dimension; ++i) os << GetDimension(i) << " "; os << std::endl; for(unsigned int ch=0; ch < this->m_ImageDescriptor->GetNumberOfChannels(); ch++) { mitk::PixelType chPixelType = this->m_ImageDescriptor->GetChannelTypeById(ch); os << indent << " Channel: " << this->m_ImageDescriptor->GetChannelName(ch) << std::endl; os << indent << " PixelType: " << chPixelType.GetTypeId().name() << std::endl; os << indent << " BitsPerElement: " << chPixelType.GetSize() << std::endl; os << indent << " NumberOfComponents: " << chPixelType.GetNumberOfComponents() << std::endl; os << indent << " BitsPerComponent: " << chPixelType.GetBitsPerComponent() << 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 + if(std::abs(mx[i][j]) > ref) // matrix is nd ret = true; } } } } return ret; } #include "mitkImageStatisticsHolder.h" //##Documentation mitk::ScalarType mitk::Image::GetScalarValueMin(int t) const { return m_ImageStatistics->GetScalarValueMin(t); } //##Documentation //## \brief Get the maximum for scalar images mitk::ScalarType mitk::Image::GetScalarValueMax(int t) const { return m_ImageStatistics->GetScalarValueMax(t); } //##Documentation //## \brief Get the second smallest value for scalar images mitk::ScalarType mitk::Image::GetScalarValue2ndMin(int t) const { return m_ImageStatistics->GetScalarValue2ndMin(t); } mitk::ScalarType mitk::Image::GetScalarValueMinNoRecompute( unsigned int t ) const { return m_ImageStatistics->GetScalarValueMinNoRecompute(t); } mitk::ScalarType mitk::Image::GetScalarValue2ndMinNoRecompute( unsigned int t ) const { return m_ImageStatistics->GetScalarValue2ndMinNoRecompute(t); } mitk::ScalarType mitk::Image::GetScalarValue2ndMax(int t) const { return m_ImageStatistics->GetScalarValue2ndMax(t); } mitk::ScalarType mitk::Image::GetScalarValueMaxNoRecompute( unsigned int t) const { return m_ImageStatistics->GetScalarValueMaxNoRecompute(t); } mitk::ScalarType mitk::Image::GetScalarValue2ndMaxNoRecompute( unsigned int t ) const { return m_ImageStatistics->GetScalarValue2ndMaxNoRecompute(t); } mitk::ScalarType mitk::Image::GetCountOfMinValuedVoxels(int t ) const { return m_ImageStatistics->GetCountOfMinValuedVoxels(t); } mitk::ScalarType mitk::Image::GetCountOfMaxValuedVoxels(int t) const { return m_ImageStatistics->GetCountOfMaxValuedVoxels(t); } unsigned int mitk::Image::GetCountOfMaxValuedVoxelsNoRecompute( unsigned int t ) const { return m_ImageStatistics->GetCountOfMaxValuedVoxelsNoRecompute(t); } unsigned int mitk::Image::GetCountOfMinValuedVoxelsNoRecompute( unsigned int t ) const { return m_ImageStatistics->GetCountOfMinValuedVoxelsNoRecompute(t); } diff --git a/Core/Code/IO/mitkPixelType.h b/Core/Code/IO/mitkPixelType.h index 14dffbd58d..8d4c2aae3c 100644 --- a/Core/Code/IO/mitkPixelType.h +++ b/Core/Code/IO/mitkPixelType.h @@ -1,259 +1,258 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef PIXELTYPE_H_HEADER_INCLUDED_C1EBF565 #define PIXELTYPE_H_HEADER_INCLUDED_C1EBF565 #include #include "mitkCommon.h" #include "mitkPixelTypeTraits.h" #include #include #include #include namespace mitk { template< typename ComponentT> const char* ComponentTypeToString() { return typeid(ComponentT).name(); } template const char* PixelTypeToString() { return typeid(PixelT).name(); } //##Documentation //## @brief Class for defining the data type of pixels //## //## To obtain additional type information not provided by this class //## itk::ImageIOBase can be used by passing the return value of //## PixelType::GetItkTypeId() to itk::ImageIOBase::SetPixelTypeInfo //## and using the itk::ImageIOBase methods GetComponentType, //## GetComponentTypeAsString, GetPixelType, GetPixelTypeAsString. //## @ingroup Data class MITK_CORE_EXPORT PixelType { public: - itkTypeMacro(PixelType, None); typedef itk::ImageIOBase::IOPixelType ItkIOPixelType; PixelType(const mitk::PixelType & aPixelType); /** \brief Get the \a type_info of the scalar (!) type. Each element * may contain m_NumberOfComponents (more than one) of these scalars. * */ inline const std::type_info& GetTypeId() const { return m_ComponentType; } /** \brief Get the \a type_info of the whole pixel type. * * If you want the type information for the component of a compound type use the * GetTypeId() method */ inline const std::type_info& GetPixelTypeId() const { return m_PixelType; } /** \brief Returns a string containing the ItkTypeName, * * The string provides the same information as GetPixelTypeId.name() */ std::string GetItkTypeAsString() const { return m_PixelTypeName; } /** \brief Returns a string containing the type name of the component, * * The string provides the same information as GetTypeId.name() */ std::string GetComponentTypeAsString() const { return m_ComponentTypeName; } /** \brief Get size of the PixelType in bytes * * A RGBA PixelType of floats will return 4 * sizeof(float) */ size_t GetSize() const { return (m_NumberOfComponents * m_BytesPerComponent); } /** \brief Get the number of bits per element (of an * element) * * A vector of double with three components will return * 8*sizeof(double)*3. * \sa GetBitsPerComponent * \sa GetItkTypeId * \sa GetTypeId */ size_t GetBpe() const { return this->GetSize() * 8; } /** \brief Get the number of components of which each element consists * * Each pixel can consist of multiple components, e.g. RGB. */ inline size_t GetNumberOfComponents() const { return m_NumberOfComponents; } /** \brief Get the number of bits per components * \sa GetBitsPerComponent */ inline size_t GetBitsPerComponent() const { return m_BytesPerComponent * 8; } bool operator==(const PixelType& rhs) const; bool operator!=(const PixelType& rhs) const; bool operator==(const std::type_info& typeId) const; bool operator!=(const std::type_info& typeId) const; ~PixelType() {} private: friend class ItkImageFileReader; friend class NrrdTbssImageReader; friend class NrrdTbssRoiImageReader; template< typename ComponentT, typename PixelT, std::size_t numberOfComponents > friend PixelType MakePixelType(); template< typename ItkImageType > friend PixelType MakePixelType(); PixelType( const std::type_info& componentType, const std::type_info& pixelType, std::size_t bytesPerComponent, std::size_t numberOfComponents, const char* componentTypeName = 0, const char* pixelTypeName = 0 ) : m_ComponentType( componentType ), m_PixelType( pixelType ), m_NumberOfComponents( numberOfComponents ), m_BytesPerComponent( bytesPerComponent ) { if(componentTypeName) m_ComponentTypeName = componentTypeName; else m_ComponentTypeName = componentType.name(); if(pixelTypeName) m_PixelTypeName = pixelTypeName; else m_PixelTypeName = pixelType.name(); } // default constructor is disabled on purpose PixelType(void); // assignment operator declared private on purpose PixelType& operator=(const PixelType& other); /** \brief the \a type_info of the scalar (!) component type. Each element may contain m_NumberOfComponents (more than one) of these scalars. */ const std::type_info& m_ComponentType; const std::type_info& m_PixelType; std::string m_ComponentTypeName; std::string m_PixelTypeName; std::size_t m_NumberOfComponents; std::size_t m_BytesPerComponent; }; /** \brief A template method for creating a pixel type. */ template< typename ComponentT, typename PixelT, std::size_t numOfComponents > PixelType MakePixelType() { typedef itk::Image< PixelT, numOfComponents> ItkImageType; return PixelType( typeid(ComponentT), typeid(ItkImageType), sizeof(ComponentT), numOfComponents, ComponentTypeToString(), PixelTypeToString() ); } /** \brief A template method for creating a pixel type from an ItkImageType * * For fixed size vector images ( i.e. images of type itk::FixedArray<3,float> ) also the number of components * is propagated to the constructor */ template< typename ItkImageType > PixelType MakePixelType() { // define new type, since the ::PixelType is used to distinguish between simple and compound types typedef typename ItkImageType::PixelType ImportPixelType; // get the component type ( is either directly ImportPixelType or ImportPixelType::ValueType for compound types ) typedef typename GetComponentType::ComponentType ComponentT; // The PixelType is the same as the ComponentT for simple types typedef typename ItkImageType::PixelType PixelT; // Get the length of compound type ( initialized to 1 for simple types and variable-length vector images) size_t numComp = ComponentsTrait< (isPrimitiveType::value || isVectorImage::value), ItkImageType >::Size; // call the constructor return PixelType( typeid(ComponentT), typeid(PixelT), sizeof(ComponentT), numComp, ComponentTypeToString(), PixelTypeToString() ); } /** \brief An interface to the MakePixelType method for creating scalar pixel types. * * Usage: for example MakeScalarPixelType() for a scalar short image */ template< typename T> PixelType MakeScalarPixelType() { return MakePixelType(); } } // namespace mitk #endif /* PIXELTYPE_H_HEADER_INCLUDED_C1EBF565 */ diff --git a/Core/Code/Interactions/mitkDisplayVectorInteractorLevelWindow.cpp b/Core/Code/Interactions/mitkDisplayVectorInteractorLevelWindow.cpp index 1eaaa6ce09..d8b9523905 100644 --- a/Core/Code/Interactions/mitkDisplayVectorInteractorLevelWindow.cpp +++ b/Core/Code/Interactions/mitkDisplayVectorInteractorLevelWindow.cpp @@ -1,131 +1,131 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkDisplayVectorInteractorLevelWindow.h" #include "mitkOperation.h" #include "mitkDisplayCoordinateOperation.h" #include "mitkStateEvent.h" #include "mitkInteractionConst.h" #include "mitkAction.h" #include "mitkStandaloneDataStorage.h" #include "mitkNodePredicateDataType.h" #include "mitkLevelWindowProperty.h" #include "mitkLevelWindow.h" void mitk::DisplayVectorInteractorLevelWindow::ExecuteOperation(Operation* itkNotUsed( operation ) ) { } bool mitk::DisplayVectorInteractorLevelWindow::ExecuteAction(Action* action, mitk::StateEvent const* stateEvent) { bool ok=false; const DisplayPositionEvent* posEvent=dynamic_cast(stateEvent->GetEvent()); if(posEvent==NULL) return false; int actionId = action->GetActionId(); switch(actionId) { case AcINITMOVE: // MITK_INFO << "AcINITMOVE"; { m_Sender=posEvent->GetSender(); m_StartDisplayCoordinate=posEvent->GetDisplayPosition(); m_LastDisplayCoordinate=posEvent->GetDisplayPosition(); m_CurrentDisplayCoordinate=posEvent->GetDisplayPosition(); ok = true; break; } case AcLEVELWINDOW: { m_LastDisplayCoordinate=m_CurrentDisplayCoordinate; m_CurrentDisplayCoordinate=posEvent->GetDisplayPosition(); mitk::DataStorage::Pointer storage = m_Sender->GetDataStorage(); mitk::DataNode::Pointer node = NULL; mitk::DataStorage::SetOfObjects::ConstPointer allImageNodes = storage->GetSubset(mitk::NodePredicateDataType::New( "Image") ); for ( unsigned int i = 0; i < allImageNodes->size() ; i++ ) { bool isActiveImage = false; bool propFound = allImageNodes->at( i )->GetBoolProperty( "imageForLevelWindow", isActiveImage ); if ( propFound && isActiveImage ) { node = allImageNodes->at( i ); continue; } } if ( node.IsNull() ) { node = storage->GetNode( mitk::NodePredicateDataType::New( "Image" ) ); } if ( node.IsNull() ) { return false; } mitk::LevelWindow lv = mitk::LevelWindow(); node->GetLevelWindow(lv); - int level = lv.GetLevel(); - int window = lv.GetWindow(); + ScalarType level = lv.GetLevel(); + ScalarType window = lv.GetWindow(); - level += ( m_CurrentDisplayCoordinate[0] - m_LastDisplayCoordinate[0] )*2; - window += ( m_CurrentDisplayCoordinate[1] - m_LastDisplayCoordinate[1] )*2; + level += ( m_CurrentDisplayCoordinate[0] - m_LastDisplayCoordinate[0] )*static_cast(2); + window += ( m_CurrentDisplayCoordinate[1] - m_LastDisplayCoordinate[1] )*static_cast(2); lv.SetLevelWindow( level, window ); dynamic_cast(node->GetProperty("levelwindow"))->SetLevelWindow( lv ); m_Sender->GetRenderingManager()->RequestUpdateAll(); ok = true; break; } case AcFINISHMOVE: // MITK_INFO << "AcFINISHMOVE"; { ok = true; break; } default: ok = false; break; } return ok; } mitk::DisplayVectorInteractorLevelWindow::DisplayVectorInteractorLevelWindow(const char * type) : mitk::StateMachine(type), m_Sender(NULL) { m_StartDisplayCoordinate.Fill(0); m_LastDisplayCoordinate.Fill(0); m_CurrentDisplayCoordinate.Fill(0); m_UndoEnabled = false; } mitk::DisplayVectorInteractorLevelWindow::~DisplayVectorInteractorLevelWindow() { } diff --git a/Core/Code/Interactions/mitkDisplayVectorInteractorScroll.cpp b/Core/Code/Interactions/mitkDisplayVectorInteractorScroll.cpp index f876493942..0aee1898d8 100644 --- a/Core/Code/Interactions/mitkDisplayVectorInteractorScroll.cpp +++ b/Core/Code/Interactions/mitkDisplayVectorInteractorScroll.cpp @@ -1,224 +1,224 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkDisplayVectorInteractorScroll.h" #include "mitkOperation.h" #include "mitkDisplayCoordinateOperation.h" //#include "mitkDisplayPositionEvent.h" #include "mitkUndoController.h" #include "mitkStateEvent.h" #include "mitkInteractionConst.h" #include "mitkAction.h" void mitk::DisplayVectorInteractorScroll::ExecuteOperation(Operation* itkNotUsed( operation ) ) { } bool mitk::DisplayVectorInteractorScroll::ExecuteAction(Action* action, mitk::StateEvent const* stateEvent) { bool ok=false; const DisplayPositionEvent* posEvent=dynamic_cast(stateEvent->GetEvent()); m_IsAltModifierActive = false; int actionId = action->GetActionId(); switch(actionId) { case AcINITMOVE: { if(posEvent==NULL) return false; m_Sender=posEvent->GetSender(); m_StartDisplayCoordinate=posEvent->GetDisplayPosition(); m_LastDisplayCoordinate=posEvent->GetDisplayPosition(); m_CurrentDisplayCoordinate=posEvent->GetDisplayPosition(); ok = true; break; } case AcSCROLLMOUSEWHEEL: { const WheelEvent* wheelEvent=dynamic_cast(stateEvent->GetEvent()); if(wheelEvent != NULL) { int buttonState = stateEvent->GetEvent()->GetButtonState(); if(buttonState == 1024) { m_IsAltModifierActive = true; } mitk::SliceNavigationController::Pointer sliceNaviController = wheelEvent->GetSender()->GetSliceNavigationController(); if ( !sliceNaviController->GetSliceLocked() ) { this->InvokeEvent( StartScrollInteractionEvent() ); mitk::Stepper* stepper = sliceNaviController->GetSlice(); if (stepper->GetSteps() <= 1) { stepper = sliceNaviController->GetTime(); } // get the desired delta int delta = wheelEvent->GetDelta(); if ( m_InvertScrollingDirection ) delta *= -1; // If we want to invert the scrolling direction -> delta * -1 if ( delta < 0 ) { stepper->Next(); } else { stepper->Previous(); } } this->InvokeEvent( EndScrollInteractionEvent() ); } ok = true; break; } case AcSCROLL: { if(posEvent==NULL) return false; int buttonState = stateEvent->GetEvent()->GetButtonState(); //1025 = Alt+LeftMouseButton+Move //1028 = Alt+MiddleMouseButton+Move if(buttonState == 1025 || buttonState == 1028 ) { m_IsAltModifierActive = true; } mitk::SliceNavigationController::Pointer sliceNaviController = m_Sender->GetSliceNavigationController(); if(sliceNaviController) { this->InvokeEvent( StartScrollInteractionEvent() ); int delta = 0; - delta = m_LastDisplayCoordinate[1]-posEvent->GetDisplayPosition()[1]; + delta = static_cast(m_LastDisplayCoordinate[1]-posEvent->GetDisplayPosition()[1]); // if we moved less than 'm_IndexToSliceModifier' pixels slice ONE slice only if ( delta>0 && delta-m_IndexToSliceModifier) { delta=-m_IndexToSliceModifier; } delta /= m_IndexToSliceModifier; if ( m_InvertScrollingDirection ) delta *= -1; int newPos = sliceNaviController->GetSlice()->GetPos() + delta; // if auto repeat is on, start at first slice if you reach the last slice and vice versa int maxSlices = sliceNaviController->GetSlice()->GetSteps(); if ( m_AutoRepeat ) { while(newPos<0) { newPos += maxSlices; } while(newPos>=maxSlices) { newPos -= maxSlices; } } else { // if the new slice is below 0 we still show slice 0 // due to the stepper using unsigned int we have to do this ourselves if ( newPos < 1 ) newPos = 0; } // set the new position sliceNaviController->GetSlice()->SetPos( newPos ); this->InvokeEvent( EndScrollInteractionEvent() ); } m_LastDisplayCoordinate=m_CurrentDisplayCoordinate; m_CurrentDisplayCoordinate=posEvent->GetDisplayPosition(); } case AcFINISHMOVE: { ok = true; break; } default: ok = false; break; } return ok; } void mitk::DisplayVectorInteractorScroll::SetIndexToSliceModifier( int modifier ) { m_IndexToSliceModifier = modifier; } void mitk::DisplayVectorInteractorScroll::SetAutoRepeat( bool autoRepeat ) { m_AutoRepeat = autoRepeat; } mitk::DisplayVectorInteractorScroll::DisplayVectorInteractorScroll(const char * type, mitk::OperationActor* destination) : mitk::StateMachine(type) , m_Sender(NULL) , m_Destination(destination) , m_IndexToSliceModifier(4) , m_AutoRepeat( false ) , m_InvertScrollingDirection( false ) , m_IsAltModifierActive( false ) { m_StartDisplayCoordinate.Fill(0); m_LastDisplayCoordinate.Fill(0); m_CurrentDisplayCoordinate.Fill(0); m_UndoEnabled = false; //if(m_Destination==NULL) // m_Destination=this; } mitk::DisplayVectorInteractorScroll::~DisplayVectorInteractorScroll() { if ( m_Destination != this ) delete m_Destination; } void mitk::DisplayVectorInteractorScroll::SetInvertScrollingDirection( bool invert ) { m_InvertScrollingDirection = invert; } bool mitk::DisplayVectorInteractorScroll::IsAltModifierActive() const { return m_IsAltModifierActive; } diff --git a/Core/Code/Rendering/vtkMitkThickSlicesFilter.cpp b/Core/Code/Rendering/vtkMitkThickSlicesFilter.cpp index ef8f746ead..1d12aa7a8f 100644 --- a/Core/Code/Rendering/vtkMitkThickSlicesFilter.cpp +++ b/Core/Code/Rendering/vtkMitkThickSlicesFilter.cpp @@ -1,373 +1,373 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "vtkMitkThickSlicesFilter.h" #include "vtkDataArray.h" #include "vtkImageData.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkStreamingDemandDrivenPipeline.h" #include #include vtkCxxRevisionMacro(vtkMitkThickSlicesFilter, "$Revision: 1.00 $"); vtkStandardNewMacro(vtkMitkThickSlicesFilter); //---------------------------------------------------------------------------- // Construct an instance of vtkMitkThickSlicesFilter fitler. vtkMitkThickSlicesFilter::vtkMitkThickSlicesFilter() { this->HandleBoundaries = 1; this->Dimensionality = 2; this->m_CurrentMode = MIP; // by default process active point scalars this->SetInputArrayToProcess(0,0,0,vtkDataObject::FIELD_ASSOCIATION_POINTS, vtkDataSetAttributes::SCALARS); } //---------------------------------------------------------------------------- void vtkMitkThickSlicesFilter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "HandleBoundaries: " << this->HandleBoundaries << "\n"; os << indent << "Dimensionality: " << this->Dimensionality << "\n"; } //---------------------------------------------------------------------------- int vtkMitkThickSlicesFilter::RequestInformation(vtkInformation*, vtkInformationVector** inputVector, vtkInformationVector* outputVector) { // Get input and output pipeline information. vtkInformation* outInfo = outputVector->GetInformationObject(0); vtkInformation* inInfo = inputVector[0]->GetInformationObject(0); // Get the input whole extent. int extent[6]; inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), extent); // Reduce 3D to 2D output extent[4] = extent[5] = 0; // Store the new whole extent for the output. outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), extent, 6); /* // Set the number of point data componets to the number of // components in the gradient vector. vtkDataObject::SetPointDataActiveScalarInfo(outInfo, VTK_DOUBLE, this->Dimensionality); */ return 1; } //---------------------------------------------------------------------------- // This method computes the input extent necessary to generate the output. int vtkMitkThickSlicesFilter::RequestUpdateExtent(vtkInformation*, vtkInformationVector** inputVector, vtkInformationVector* outputVector) { // Get input and output pipeline information. vtkInformation* outInfo = outputVector->GetInformationObject(0); vtkInformation* inInfo = inputVector[0]->GetInformationObject(0); // Get the input whole extent. int wholeExtent[6]; inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), wholeExtent); // Get the requested update extent from the output. int inUExt[6]; outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), inUExt); /*inUExt[4] -= 5; inUExt[5] += 5; if (inUExt[4] < wholeExtent[4]) */inUExt[4] = wholeExtent[4]; /*if (inUExt[5] > wholeExtent[5]) */inUExt[5] = wholeExtent[5]; // Store the update extent needed from the intput. inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), inUExt, 6); return 1; } //---------------------------------------------------------------------------- // This execute method handles boundaries. // it handles boundaries. Pixels are just replicated to get values // out of extent. template void vtkMitkThickSlicesFilterExecute(vtkMitkThickSlicesFilter *self, vtkImageData *inData, T *inPtr, vtkImageData *outData, T *outPtr, int outExt[6], int /*id*/) { int idxX, idxY; int maxX, maxY; vtkIdType inIncX, inIncY, inIncZ; vtkIdType outIncX, outIncY, outIncZ; //int axesNum; int *inExt = inData->GetExtent(); int *wholeExtent; vtkIdType *inIncs; //int useYMin, useYMax, useXMin, useXMax; // find the region to loop over maxX = outExt[1] - outExt[0]; maxY = outExt[3] - outExt[2]; // maxZ = outExt[5] - outExt[4]; // Get the dimensionality of the gradient. //axesNum = self->GetDimensionality(); // Get increments to march through data inData->GetContinuousIncrements(outExt, inIncX, inIncY, inIncZ); outData->GetContinuousIncrements(outExt, outIncX, outIncY, outIncZ); /* // The data spacing is important for computing the gradient. // central differences (2 * ratio). // Negative because below we have (min - max) for dx ... inData->GetSpacing(r); r[0] = -0.5 / r[0]; r[1] = -0.5 / r[1]; r[2] = -0.5 / r[2]; */ // get some other info we need inIncs = inData->GetIncrements(); wholeExtent = inData->GetExtent(); // Move the pointer to the correct starting position. inPtr += (outExt[0]-inExt[0])*inIncs[0] + (outExt[2]-inExt[2])*inIncs[1] + (outExt[4]-inExt[4])*inIncs[2]; // Loop through ouput pixels int _minZ = /*-5 + outExt[4]; if( _minZ < wholeExtent[4]) _minZ=*/wholeExtent[4]; int _maxZ = /* 5 + outExt[4]; if( _maxZ > wholeExtent[5]) _maxZ=*/wholeExtent[5]; if(_maxZ<_minZ) return; double invNum = 1.0 / (_maxZ-_minZ+1) ; switch(self->GetThickSliceMode()) { default: case vtkMitkThickSlicesFilter::MIP: { //MIP for (idxY = 0; idxY <= maxY; idxY++) { //useYMin = ((idxY + outExt[2]) <= wholeExtent[2]) ? 0 : -inIncs[1]; //useYMax = ((idxY + outExt[2]) >= wholeExtent[3]) ? 0 : inIncs[1]; for (idxX = 0; idxX <= maxX; idxX++) { //useXMin = ((idxX + outExt[0]) <= wholeExtent[0]) ? 0 : -inIncs[0]; //useXMax = ((idxX + outExt[0]) >= wholeExtent[1]) ? 0 : inIncs[0]; T mip = inPtr[_minZ*inIncs[2]]; for(int z = _minZ+1; z<= _maxZ;z++) { T value = inPtr[z*inIncs[2]]; if(value > mip) mip=value; } // do X axis *outPtr = mip; outPtr++; inPtr++; } outPtr += outIncY; inPtr += inIncY; } } break; case vtkMitkThickSlicesFilter::SUM: { //MIP for (idxY = 0; idxY <= maxY; idxY++) { //useYMin = ((idxY + outExt[2]) <= wholeExtent[2]) ? 0 : -inIncs[1]; //useYMax = ((idxY + outExt[2]) >= wholeExtent[3]) ? 0 : inIncs[1]; for (idxX = 0; idxX <= maxX; idxX++) { //useXMin = ((idxX + outExt[0]) <= wholeExtent[0]) ? 0 : -inIncs[0]; //useXMax = ((idxX + outExt[0]) >= wholeExtent[1]) ? 0 : inIncs[0]; double sum = 0; for(int z = _minZ; z<= _maxZ;z++) { T value = inPtr[z*inIncs[2]]; sum += value; } // do X axis - *outPtr = invNum*sum; + *outPtr = static_cast(invNum*sum); outPtr++; inPtr++; } outPtr += outIncY; inPtr += inIncY; } } break; case vtkMitkThickSlicesFilter::WEIGHTED: { const int size = _maxZ-_minZ; std::vector weights(size); double mean = 0.5 * double(_minZ + _maxZ); double sigma_sq = double(size) / 6.0; sigma_sq *= sigma_sq; double sum = 0; int i=0; for(int z = _minZ+1; z<= _maxZ;z++) { double val = exp(-(((double)z-mean)/sigma_sq)); weights[i++] = val; sum += val; } for(i=0; i= wholeExtent[3]) ? 0 : inIncs[1]; for (idxX = 0; idxX <= maxX; idxX++) { //useXMin = ((idxX + outExt[0]) <= wholeExtent[0]) ? 0 : -inIncs[0]; //useXMax = ((idxX + outExt[0]) >= wholeExtent[1]) ? 0 : inIncs[0]; T mip = inPtr[_minZ*inIncs[2]]; i=0; double mymip = 0; for(int z = _minZ+1; z<= _maxZ;z++) { double value = inPtr[z*inIncs[2]]; mymip+=value*weights[i++]; } - mip = mymip; + mip = static_cast(mymip); // do X axis *outPtr = mip; outPtr++; inPtr++; } outPtr += outIncY; inPtr += inIncY; } } break; } } int vtkMitkThickSlicesFilter::RequestData( vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector) { if (!this->Superclass::RequestData(request, inputVector, outputVector)) { return 0; } vtkImageData* output = vtkImageData::GetData(outputVector); vtkDataArray* outArray = output->GetPointData()->GetScalars(); vtksys_ios::ostringstream newname; newname << (outArray->GetName()?outArray->GetName():"") << "Gradient"; outArray->SetName(newname.str().c_str()); // Why not pass the original array? if (this->GetInputArrayToProcess(0, inputVector)) { output->GetPointData()->AddArray( this->GetInputArrayToProcess(0, inputVector)); } return 1; } //---------------------------------------------------------------------------- // This method contains a switch statement that calls the correct // templated function for the input data type. This method does handle // boundary conditions. void vtkMitkThickSlicesFilter::ThreadedRequestData(vtkInformation*, vtkInformationVector** inputVector, vtkInformationVector*, vtkImageData*** inData, vtkImageData** outData, int outExt[6], int threadId) { // Get the input and output data objects. vtkImageData* input = inData[0][0]; vtkImageData* output = outData[0]; // The ouptut scalar type must be double to store proper gradients. /* if(output->GetScalarType() != VTK_DOUBLE) { vtkErrorMacro("Execute: output ScalarType is " << output->GetScalarType() << "but must be double."); return; } */ vtkDataArray* inputArray = this->GetInputArrayToProcess(0, inputVector); if (!inputArray) { vtkErrorMacro("No input array was found. Cannot execute"); return; } // Gradient makes sense only with one input component. This is not // a Jacobian filter. if(inputArray->GetNumberOfComponents() != 1) { vtkErrorMacro( "Execute: input has more than one component. " "The input to gradient should be a single component image. " "Think about it. If you insist on using a color image then " "run it though RGBToHSV then ExtractComponents to get the V " "components. That's probably what you want anyhow."); return; } void* inPtr = inputArray->GetVoidPointer(0); void* outPtr = output->GetScalarPointerForExtent(outExt); switch(inputArray->GetDataType()) { vtkTemplateMacro( vtkMitkThickSlicesFilterExecute(this, input, static_cast(inPtr), output, static_cast(outPtr), outExt, threadId) ); default: vtkErrorMacro("Execute: Unknown ScalarType " << input->GetScalarType()); return; } }