diff --git a/Modules/Segmentation/Controllers/mitkToolManager.cpp b/Modules/Segmentation/Controllers/mitkToolManager.cpp index b583d6fb60..e192402e33 100644 --- a/Modules/Segmentation/Controllers/mitkToolManager.cpp +++ b/Modules/Segmentation/Controllers/mitkToolManager.cpp @@ -1,564 +1,566 @@ /*=================================================================== 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 "mitkToolManager.h" #include "mitkGlobalInteraction.h" #include "mitkCoreObjectFactory.h" #include #include #include #include "mitkInteractionEventObserver.h" #include "mitkDisplayInteractor.h" #include "mitkSegTool2D.h" #include "usGetModuleContext.h" #include "usModuleContext.h" mitk::ToolManager::ToolManager(DataStorage* storage) :m_ActiveTool(NULL), m_ActiveToolID(-1), m_RegisteredClients(0), m_DataStorage(storage), m_ExclusiveStateEventPolicy(true) { CoreObjectFactory::GetInstance(); // to make sure a CoreObjectFactory was instantiated (and in turn, possible tools are registered) - bug 1029 this->InitializeTools(); //ActivateTool(0); // first one is default } mitk::ToolManager::~ToolManager() { for (DataVectorType::iterator dataIter = m_WorkingData.begin(); dataIter != m_WorkingData.end(); ++dataIter) (*dataIter)->RemoveObserver(m_WorkingDataObserverTags[(*dataIter)]); if(this->GetDataStorage() != NULL) this->GetDataStorage()->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1 ( this, &ToolManager::OnNodeRemoved )); if (m_ActiveTool) { m_ActiveTool->Deactivated(); m_ActiveToolRegistration.Unregister(); //GlobalInteraction::GetInstance()->RemoveListener( m_ActiveTool ); m_ActiveTool = NULL; m_ActiveToolID = -1; // no tool active ActiveToolChanged.Send(); } for ( NodeTagMapType::iterator observerTagMapIter = m_ReferenceDataObserverTags.begin(); observerTagMapIter != m_ReferenceDataObserverTags.end(); ++observerTagMapIter ) { observerTagMapIter->first->RemoveObserver( observerTagMapIter->second ); } } void mitk::ToolManager::InitializeTools() { if(mitk::GlobalInteraction::GetInstance()->IsInitialized()) { m_Tools.resize(0); // get a list of all known mitk::Tools std::list thingsThatClaimToBeATool = itk::ObjectFactoryBase::CreateAllInstance("mitkTool"); // remember these tools for ( std::list::iterator iter = thingsThatClaimToBeATool.begin(); iter != thingsThatClaimToBeATool.end(); ++iter ) { if ( Tool* tool = dynamic_cast( iter->GetPointer() ) ) { tool->InitializeStateMachine(); tool->SetToolManager(this); // important to call right after instantiation tool->ErrorMessage += MessageDelegate1( this, &ToolManager::OnToolErrorMessage ); tool->GeneralMessage += MessageDelegate1( this, &ToolManager::OnGeneralToolMessage ); m_Tools.push_back( tool ); } } } } void mitk::ToolManager::OnToolErrorMessage(std::string s) { this->ToolErrorMessage(s); } void mitk::ToolManager::OnGeneralToolMessage(std::string s) { this->GeneralToolMessage(s); } const mitk::ToolManager::ToolVectorTypeConst mitk::ToolManager::GetTools() { ToolVectorTypeConst resultList; for ( ToolVectorType::iterator iter = m_Tools.begin(); iter != m_Tools.end(); ++iter ) { resultList.push_back( iter->GetPointer() ); } return resultList; } mitk::Tool* mitk::ToolManager::GetToolById(int id) { try { return m_Tools.at(id); } catch(std::exception&) { return NULL; } } bool mitk::ToolManager::ActivateTool(int id) { + if (id != -1 && !this->GetToolById(id)->CanHandle(this->GetReferenceData(0)->GetData())) + return false; if(this->GetDataStorage()) { this->GetDataStorage()->RemoveNodeEvent.AddListener( mitk::MessageDelegate1 ( this, &ToolManager::OnNodeRemoved ) ); } //MITK_INFO << "ToolManager::ActivateTool("<SetEventNotificationPolicy(GlobalInteraction::INFORM_MULTIPLE); } if ( GetToolById( id ) == m_ActiveTool ) return true; // no change needed static int nextTool = -1; nextTool = id; //MITK_INFO << "ToolManager::ActivateTool("<Deactivated(); //GlobalInteraction::GetInstance()->RemoveListener( m_ActiveTool ); m_ActiveToolRegistration.Unregister(); } m_ActiveTool = GetToolById( nextTool ); m_ActiveToolID = m_ActiveTool ? nextTool : -1; // current ID if tool is valid, otherwise -1 ActiveToolChanged.Send(); if (m_ActiveTool) { if (m_RegisteredClients > 0) { m_ActiveTool->Activated(); //GlobalInteraction::GetInstance()->AddListener( m_ActiveTool ); m_ActiveToolRegistration = us::GetModuleContext()->RegisterService( m_ActiveTool, us::ServiceProperties() ); //If a tool is activated set event notification policy to one if (m_ExclusiveStateEventPolicy && dynamic_cast(m_ActiveTool)) GlobalInteraction::GetInstance()->SetEventNotificationPolicy(GlobalInteraction::INFORM_ONE); } } } inActivateTool = false; return (m_ActiveTool != NULL); } void mitk::ToolManager::SetReferenceData(DataVectorType data) { if (data != m_ReferenceData) { // remove observers from old nodes for ( DataVectorType::iterator dataIter = m_ReferenceData.begin(); dataIter != m_ReferenceData.end(); ++dataIter ) { NodeTagMapType::iterator searchIter = m_ReferenceDataObserverTags.find( *dataIter ); if ( searchIter != m_ReferenceDataObserverTags.end() ) { //MITK_INFO << "Stopping observation of " << (void*)(*dataIter) << std::endl; (*dataIter)->RemoveObserver( searchIter->second ); } } m_ReferenceData = data; // TODO tell active tool? // attach new observers m_ReferenceDataObserverTags.clear(); for ( DataVectorType::iterator dataIter = m_ReferenceData.begin(); dataIter != m_ReferenceData.end(); ++dataIter ) { //MITK_INFO << "Observing " << (void*)(*dataIter) << std::endl; itk::MemberCommand::Pointer command = itk::MemberCommand::New(); command->SetCallbackFunction( this, &ToolManager::OnOneOfTheReferenceDataDeleted ); command->SetCallbackFunction( this, &ToolManager::OnOneOfTheReferenceDataDeletedConst ); m_ReferenceDataObserverTags.insert( std::pair( (*dataIter), (*dataIter)->AddObserver( itk::DeleteEvent(), command ) ) ); } ReferenceDataChanged.Send(); } } void mitk::ToolManager::OnOneOfTheReferenceDataDeletedConst(const itk::Object* caller, const itk::EventObject& e) { OnOneOfTheReferenceDataDeleted( const_cast(caller), e ); } void mitk::ToolManager::OnOneOfTheReferenceDataDeleted(itk::Object* caller, const itk::EventObject& itkNotUsed(e)) { //MITK_INFO << "Deleted: " << (void*)caller << " Removing from reference data list." << std::endl; DataVectorType v; for (DataVectorType::iterator dataIter = m_ReferenceData.begin(); dataIter != m_ReferenceData.end(); ++dataIter ) { //MITK_INFO << " In list: " << (void*)(*dataIter); if ( (void*)(*dataIter) != (void*)caller ) { v.push_back( *dataIter ); //MITK_INFO << " kept" << std::endl; } else { //MITK_INFO << " removed" << std::endl; m_ReferenceDataObserverTags.erase( *dataIter ); // no tag to remove anymore } } this->SetReferenceData( v ); } void mitk::ToolManager::SetReferenceData(DataNode* data) { //MITK_INFO << "ToolManager::SetReferenceData(" << (void*)data << ")" << std::endl; DataVectorType v; if (data) { v.push_back(data); } SetReferenceData(v); } void mitk::ToolManager::SetWorkingData(DataVectorType data) { if ( data != m_WorkingData ) { // remove observers from old nodes for ( DataVectorType::iterator dataIter = m_WorkingData.begin(); dataIter != m_WorkingData.end(); ++dataIter ) { NodeTagMapType::iterator searchIter = m_WorkingDataObserverTags.find( *dataIter ); if ( searchIter != m_WorkingDataObserverTags.end() ) { //MITK_INFO << "Stopping observation of " << (void*)(*dataIter) << std::endl; (*dataIter)->RemoveObserver( searchIter->second ); } } m_WorkingData = data; // TODO tell active tool? // Quick workaround for bug #16598 if (m_WorkingData.empty()) this->ActivateTool(-1); // workaround end // attach new observers m_WorkingDataObserverTags.clear(); for ( DataVectorType::iterator dataIter = m_WorkingData.begin(); dataIter != m_WorkingData.end(); ++dataIter ) { //MITK_INFO << "Observing " << (void*)(*dataIter) << std::endl; itk::MemberCommand::Pointer command = itk::MemberCommand::New(); command->SetCallbackFunction( this, &ToolManager::OnOneOfTheWorkingDataDeleted ); command->SetCallbackFunction( this, &ToolManager::OnOneOfTheWorkingDataDeletedConst ); m_WorkingDataObserverTags.insert( std::pair( (*dataIter), (*dataIter)->AddObserver( itk::DeleteEvent(), command ) ) ); } WorkingDataChanged.Send(); } } void mitk::ToolManager::OnOneOfTheWorkingDataDeletedConst(const itk::Object* caller, const itk::EventObject& e) { OnOneOfTheWorkingDataDeleted( const_cast(caller), e ); } void mitk::ToolManager::OnOneOfTheWorkingDataDeleted(itk::Object* caller, const itk::EventObject& itkNotUsed(e)) { //MITK_INFO << "Deleted: " << (void*)caller << " Removing from reference data list." << std::endl; DataVectorType v; for (DataVectorType::iterator dataIter = m_WorkingData.begin(); dataIter != m_WorkingData.end(); ++dataIter ) { //MITK_INFO << " In list: " << (void*)(*dataIter); if ( (void*)(*dataIter) != (void*)caller ) { v.push_back( *dataIter ); //MITK_INFO << " kept" << std::endl; } else { //MITK_INFO << " removed" << std::endl; m_WorkingDataObserverTags.erase( *dataIter ); // no tag to remove anymore } } this->SetWorkingData( v ); } void mitk::ToolManager::SetWorkingData(DataNode* data) { DataVectorType v; if (data) // don't allow for NULL nodes { v.push_back(data); } SetWorkingData(v); } void mitk::ToolManager::SetRoiData(DataVectorType data) { if (data != m_RoiData) { // remove observers from old nodes for ( DataVectorType::iterator dataIter = m_RoiData.begin(); dataIter != m_RoiData.end(); ++dataIter ) { NodeTagMapType::iterator searchIter = m_RoiDataObserverTags.find( *dataIter ); if ( searchIter != m_RoiDataObserverTags.end() ) { //MITK_INFO << "Stopping observation of " << (void*)(*dataIter) << std::endl; (*dataIter)->RemoveObserver( searchIter->second ); } } m_RoiData = data; // TODO tell active tool? // attach new observers m_RoiDataObserverTags.clear(); for ( DataVectorType::iterator dataIter = m_RoiData.begin(); dataIter != m_RoiData.end(); ++dataIter ) { //MITK_INFO << "Observing " << (void*)(*dataIter) << std::endl; itk::MemberCommand::Pointer command = itk::MemberCommand::New(); command->SetCallbackFunction( this, &ToolManager::OnOneOfTheRoiDataDeleted ); command->SetCallbackFunction( this, &ToolManager::OnOneOfTheRoiDataDeletedConst ); m_RoiDataObserverTags.insert( std::pair( (*dataIter), (*dataIter)->AddObserver( itk::DeleteEvent(), command ) ) ); } RoiDataChanged.Send(); } } void mitk::ToolManager::SetRoiData(DataNode* data) { DataVectorType v; if(data) { v.push_back(data); } this->SetRoiData(v); } void mitk::ToolManager::OnOneOfTheRoiDataDeletedConst(const itk::Object* caller, const itk::EventObject& e) { OnOneOfTheRoiDataDeleted( const_cast(caller), e ); } void mitk::ToolManager::OnOneOfTheRoiDataDeleted(itk::Object* caller, const itk::EventObject& itkNotUsed(e)) { //MITK_INFO << "Deleted: " << (void*)caller << " Removing from roi data list." << std::endl; DataVectorType v; for (DataVectorType::iterator dataIter = m_RoiData.begin(); dataIter != m_RoiData.end(); ++dataIter ) { //MITK_INFO << " In list: " << (void*)(*dataIter); if ( (void*)(*dataIter) != (void*)caller ) { v.push_back( *dataIter ); //MITK_INFO << " kept" << std::endl; } else { //MITK_INFO << " removed" << std::endl; m_RoiDataObserverTags.erase( *dataIter ); // no tag to remove anymore } } this->SetRoiData( v ); } mitk::ToolManager::DataVectorType mitk::ToolManager::GetReferenceData() { return m_ReferenceData; } mitk::DataNode* mitk::ToolManager::GetReferenceData(int idx) { try { return m_ReferenceData.at(idx); } catch(std::exception&) { return NULL; } } mitk::ToolManager::DataVectorType mitk::ToolManager::GetWorkingData() { return m_WorkingData; } mitk::ToolManager::DataVectorType mitk::ToolManager::GetRoiData() { return m_RoiData; } mitk::DataNode* mitk::ToolManager::GetRoiData(int idx) { try { return m_RoiData.at(idx); } catch(std::exception&) { return NULL; } } mitk::DataStorage* mitk::ToolManager::GetDataStorage() { if ( m_DataStorage.IsNotNull() ) { return m_DataStorage; } else { return NULL; } } void mitk::ToolManager::SetDataStorage(DataStorage& storage) { m_DataStorage = &storage; } mitk::DataNode* mitk::ToolManager::GetWorkingData(int idx) { try { return m_WorkingData.at(idx); } catch(std::exception&) { return NULL; } } int mitk::ToolManager::GetActiveToolID() { return m_ActiveToolID; } mitk::Tool* mitk::ToolManager::GetActiveTool() { return m_ActiveTool; } void mitk::ToolManager::RegisterClient() { if ( m_RegisteredClients < 1 ) { if ( m_ActiveTool ) { m_ActiveTool->Activated(); //GlobalInteraction::GetInstance()->AddListener( m_ActiveTool ); m_ActiveToolRegistration = us::GetModuleContext()->RegisterService( m_ActiveTool, us::ServiceProperties() ); } } ++m_RegisteredClients; } void mitk::ToolManager::UnregisterClient() { if ( m_RegisteredClients < 1) return; --m_RegisteredClients; if ( m_RegisteredClients < 1 ) { if ( m_ActiveTool ) { m_ActiveTool->Deactivated(); //GlobalInteraction::GetInstance()->RemoveListener( m_ActiveTool ); m_ActiveToolRegistration.Unregister(); } } } int mitk::ToolManager::GetToolID( const Tool* tool ) { int id(0); for ( ToolVectorType::iterator iter = m_Tools.begin(); iter != m_Tools.end(); ++iter, ++id ) { if ( tool == iter->GetPointer() ) { return id; } } return -1; } void mitk::ToolManager::OnNodeRemoved(const mitk::DataNode* node) { //check if the data of the node is typeof Image /*if(dynamic_cast(node->GetData())) {*/ //check all storage vectors OnOneOfTheReferenceDataDeleted(const_cast(node), itk::DeleteEvent()); OnOneOfTheRoiDataDeleted(const_cast(node),itk::DeleteEvent()); OnOneOfTheWorkingDataDeleted(const_cast(node),itk::DeleteEvent()); //} } void mitk::ToolManager::ActivateExclusiveStateEventPolicy(bool state) { m_ExclusiveStateEventPolicy = state; } diff --git a/Modules/Segmentation/Interactions/mitkAdaptiveRegionGrowingTool.cpp b/Modules/Segmentation/Interactions/mitkAdaptiveRegionGrowingTool.cpp index 6ee0dc4633..bf24f4f8f0 100644 --- a/Modules/Segmentation/Interactions/mitkAdaptiveRegionGrowingTool.cpp +++ b/Modules/Segmentation/Interactions/mitkAdaptiveRegionGrowingTool.cpp @@ -1,93 +1,109 @@ /*=================================================================== 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 "mitkAdaptiveRegionGrowingTool.h" - +#include "mitkImage.h" #include "mitkToolManager.h" #include "mitkProperties.h" // us #include #include #include #include namespace mitk { MITK_TOOL_MACRO(MitkSegmentation_EXPORT, AdaptiveRegionGrowingTool, "AdaptiveRegionGrowingTool"); } mitk::AdaptiveRegionGrowingTool::AdaptiveRegionGrowingTool() { m_PointSetNode = mitk::DataNode::New(); m_PointSetNode->GetPropertyList()->SetProperty("name", mitk::StringProperty::New("3D_Regiongrowing_Seedpoint")); m_PointSetNode->GetPropertyList()->SetProperty("helper object", mitk::BoolProperty::New(true)); m_PointSet = mitk::PointSet::New(); m_PointSetNode->SetData(m_PointSet); m_SeedPointInteractor = mitk::SinglePointDataInteractor::New(); m_SeedPointInteractor->LoadStateMachine("PointSet.xml"); m_SeedPointInteractor->SetEventConfig("PointSetConfig.xml"); m_SeedPointInteractor->SetDataNode(m_PointSetNode); } mitk::AdaptiveRegionGrowingTool::~AdaptiveRegionGrowingTool() { } +bool mitk::AdaptiveRegionGrowingTool::CanHandle(BaseData* referenceData) const +{ + if (referenceData == NULL) + return false; + + Image* image = dynamic_cast(referenceData); + + if (image == NULL) + return false; + + if (image->GetDimension() < 3) + return false; + + return true; +} + const char** mitk::AdaptiveRegionGrowingTool::GetXPM() const { return NULL; } const char* mitk::AdaptiveRegionGrowingTool::GetName() const { return "Region Growing 3D"; } us::ModuleResource mitk::AdaptiveRegionGrowingTool::GetIconResource() const { us::Module* module = us::GetModuleContext()->GetModule(); us::ModuleResource resource = module->GetResource("RegionGrowing_48x48.png"); return resource; } void mitk::AdaptiveRegionGrowingTool::Activated() { if (!GetDataStorage()->Exists(m_PointSetNode)) GetDataStorage()->Add(m_PointSetNode, GetWorkingData()); } void mitk::AdaptiveRegionGrowingTool::Deactivated() { m_PointSet->Clear(); GetDataStorage()->Remove(m_PointSetNode); } mitk::DataNode* mitk::AdaptiveRegionGrowingTool::GetReferenceData(){ return this->m_ToolManager->GetReferenceData(0); } mitk::DataStorage* mitk::AdaptiveRegionGrowingTool::GetDataStorage(){ return this->m_ToolManager->GetDataStorage(); } mitk::DataNode* mitk::AdaptiveRegionGrowingTool::GetWorkingData(){ return this->m_ToolManager->GetWorkingData(0); } mitk::DataNode::Pointer mitk::AdaptiveRegionGrowingTool::GetPointSetNode() { return m_PointSetNode; } diff --git a/Modules/Segmentation/Interactions/mitkAdaptiveRegionGrowingTool.h b/Modules/Segmentation/Interactions/mitkAdaptiveRegionGrowingTool.h index 666bc0ffa0..a91057e956 100644 --- a/Modules/Segmentation/Interactions/mitkAdaptiveRegionGrowingTool.h +++ b/Modules/Segmentation/Interactions/mitkAdaptiveRegionGrowingTool.h @@ -1,133 +1,135 @@ /*=================================================================== 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 mitkAdaptiveRegionGrowingTool_h_Included #define mitkAdaptiveRegionGrowingTool_h_Included #include "mitkCommon.h" #include #include "mitkAutoSegmentationTool.h" #include "mitkDataStorage.h" #include "mitkSinglePointDataInteractor.h" #include "mitkPointSet.h" namespace us { class ModuleResource; } namespace mitk { /** \brief Dummy Tool for AdaptiveRegionGrowingToolGUI to get Tool functionality for AdaptiveRegionGrowing. The actual logic is implemented in QmitkAdaptiveRegionGrowingToolGUI. \ingroup ToolManagerEtAl \sa mitk::Tool \sa QmitkInteractiveSegmentation */ class MitkSegmentation_EXPORT AdaptiveRegionGrowingTool : public AutoSegmentationTool { public: /** * @brief mitkClassMacro */ mitkClassMacro(AdaptiveRegionGrowingTool, AutoSegmentationTool); itkFactorylessNewMacro(Self) itkCloneMacro(Self) + bool CanHandle(BaseData* referenceData) const; + /** * @brief Get XPM * @return NULL */ virtual const char** GetXPM() const; /** * @brief Get name * @return name of the Tool */ virtual const char* GetName() const; /** * @brief Get icon resource * @return the resource Object of the Icon */ us::ModuleResource GetIconResource() const; /** * @brief Adds interactor for the seedpoint and creates a seedpoint if neccessary. * * */ virtual void Activated(); /** * @brief Removes all set points and interactors. * * */ virtual void Deactivated(); /** * @brief get pointset node * @return the point set node */ virtual DataNode::Pointer GetPointSetNode(); /** * @brief get reference data * @return the current reference data. */ mitk::DataNode* GetReferenceData(); /** * @brief Get working data * @return a list of all working data. */ mitk::DataNode* GetWorkingData(); /** * @brief Get datastorage * @return the current data storage. */ mitk::DataStorage* GetDataStorage(); protected: /** * @brief constructor */ AdaptiveRegionGrowingTool(); // purposely hidden /** * @brief destructor */ virtual ~AdaptiveRegionGrowingTool(); private: PointSet::Pointer m_PointSet; SinglePointDataInteractor::Pointer m_SeedPointInteractor; DataNode::Pointer m_PointSetNode; }; } // namespace #endif diff --git a/Modules/Segmentation/Interactions/mitkFastMarchingTool3D.cpp b/Modules/Segmentation/Interactions/mitkFastMarchingTool3D.cpp index 51b97a65ff..03fd5c2940 100644 --- a/Modules/Segmentation/Interactions/mitkFastMarchingTool3D.cpp +++ b/Modules/Segmentation/Interactions/mitkFastMarchingTool3D.cpp @@ -1,440 +1,456 @@ /*=================================================================== 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 "mitkFastMarchingTool3D.h" #include "mitkToolManager.h" #include "mitkBaseRenderer.h" #include "mitkRenderingManager.h" #include "mitkInteractionConst.h" #include "mitkGlobalInteraction.h" #include "itkOrImageFilter.h" #include "mitkImageTimeSelector.h" #include "mitkImageCast.h" // us #include #include #include #include namespace mitk { MITK_TOOL_MACRO(MitkSegmentation_EXPORT, FastMarchingTool3D, "FastMarching3D tool"); } mitk::FastMarchingTool3D::FastMarchingTool3D() :/*FeedbackContourTool*/AutoSegmentationTool(), m_NeedUpdate(true), m_CurrentTimeStep(0), m_LowerThreshold(0), m_UpperThreshold(200), m_StoppingValue(100), m_Sigma(1.0), m_Alpha(-0.5), m_Beta(3.0) { } mitk::FastMarchingTool3D::~FastMarchingTool3D() { } +bool mitk::FastMarchingTool3D::CanHandle(BaseData* referenceData) const +{ + if (referenceData == NULL) + return false; + + Image* image = dynamic_cast(referenceData); + + if (image == NULL) + return false; + + if (image->GetDimension() < 3) + return false; + + return true; +} + const char** mitk::FastMarchingTool3D::GetXPM() const { return NULL;//mitkFastMarchingTool3D_xpm; } us::ModuleResource mitk::FastMarchingTool3D::GetIconResource() const { us::Module* module = us::GetModuleContext()->GetModule(); us::ModuleResource resource = module->GetResource("FastMarching_48x48.png"); return resource; } const char* mitk::FastMarchingTool3D::GetName() const { return "Fast Marching 3D"; } void mitk::FastMarchingTool3D::SetUpperThreshold(double value) { m_UpperThreshold = value / 10.0; m_ThresholdFilter->SetUpperThreshold( m_UpperThreshold ); m_NeedUpdate = true; } void mitk::FastMarchingTool3D::SetLowerThreshold(double value) { m_LowerThreshold = value / 10.0; m_ThresholdFilter->SetLowerThreshold( m_LowerThreshold ); m_NeedUpdate = true; } void mitk::FastMarchingTool3D::SetBeta(double value) { if (m_Beta != value) { m_Beta = value; m_SigmoidFilter->SetBeta( m_Beta ); m_NeedUpdate = true; } } void mitk::FastMarchingTool3D::SetSigma(double value) { if (m_Sigma != value) { if(value > 0.0) { m_Sigma = value; m_GradientMagnitudeFilter->SetSigma( m_Sigma ); m_NeedUpdate = true; } } } void mitk::FastMarchingTool3D::SetAlpha(double value) { if (m_Alpha != value) { m_Alpha = value; m_SigmoidFilter->SetAlpha( m_Alpha ); m_NeedUpdate = true; } } void mitk::FastMarchingTool3D::SetStoppingValue(double value) { if (m_StoppingValue != value) { m_StoppingValue = value; m_FastMarchingFilter->SetStoppingValue( m_StoppingValue ); m_NeedUpdate = true; } } void mitk::FastMarchingTool3D::Activated() { Superclass::Activated(); m_ResultImageNode = mitk::DataNode::New(); m_ResultImageNode->SetName("FastMarching_Preview"); m_ResultImageNode->SetBoolProperty("helper object", true); m_ResultImageNode->SetColor(0.0, 1.0, 0.0); m_ResultImageNode->SetVisibility(true); m_ToolManager->GetDataStorage()->Add( this->m_ResultImageNode, m_ToolManager->GetReferenceData(0)); m_SeedsAsPointSet = mitk::PointSet::New(); m_SeedsAsPointSetNode = mitk::DataNode::New(); m_SeedsAsPointSetNode->SetData(m_SeedsAsPointSet); m_SeedsAsPointSetNode->SetName("3D_FastMarching_PointSet"); m_SeedsAsPointSetNode->SetBoolProperty("helper object", true); m_SeedsAsPointSetNode->SetColor(0.0, 1.0, 0.0); m_SeedsAsPointSetNode->SetVisibility(true); m_SeedPointInteractor = mitk::PointSetInteractor::New("PressMoveReleaseAndPointSetting", m_SeedsAsPointSetNode); m_ReferenceImageAsITK = InternalImageType::New(); m_ProgressCommand = mitk::ToolCommand::New(); m_ThresholdFilter = ThresholdingFilterType::New(); m_ThresholdFilter->SetLowerThreshold( m_LowerThreshold ); m_ThresholdFilter->SetUpperThreshold( m_UpperThreshold ); m_ThresholdFilter->SetOutsideValue( 0 ); m_ThresholdFilter->SetInsideValue( 1.0 ); m_SmoothFilter = SmoothingFilterType::New(); m_SmoothFilter->AddObserver( itk::ProgressEvent(), m_ProgressCommand); m_SmoothFilter->SetTimeStep( 0.05 ); m_SmoothFilter->SetNumberOfIterations( 2 ); m_SmoothFilter->SetConductanceParameter( 9.0 ); m_GradientMagnitudeFilter = GradientFilterType::New(); m_GradientMagnitudeFilter->AddObserver( itk::ProgressEvent(), m_ProgressCommand); m_GradientMagnitudeFilter->SetSigma( m_Sigma ); m_SigmoidFilter = SigmoidFilterType::New(); m_SigmoidFilter->AddObserver( itk::ProgressEvent(), m_ProgressCommand); m_SigmoidFilter->SetAlpha( m_Alpha ); m_SigmoidFilter->SetBeta( m_Beta ); m_SigmoidFilter->SetOutputMinimum( 0.0 ); m_SigmoidFilter->SetOutputMaximum( 1.0 ); m_FastMarchingFilter = FastMarchingFilterType::New(); m_FastMarchingFilter->AddObserver( itk::ProgressEvent(), m_ProgressCommand); m_FastMarchingFilter->SetStoppingValue( m_StoppingValue ); m_SeedContainer = NodeContainer::New(); m_SeedContainer->Initialize(); m_FastMarchingFilter->SetTrialPoints( m_SeedContainer ); //set up pipeline m_SmoothFilter->SetInput( m_ReferenceImageAsITK ); m_GradientMagnitudeFilter->SetInput( m_SmoothFilter->GetOutput() ); m_SigmoidFilter->SetInput( m_GradientMagnitudeFilter->GetOutput() ); m_FastMarchingFilter->SetInput( m_SigmoidFilter->GetOutput() ); m_ThresholdFilter->SetInput( m_FastMarchingFilter->GetOutput() ); m_ToolManager->GetDataStorage()->Add(m_SeedsAsPointSetNode, m_ToolManager->GetWorkingData(0)); mitk::GlobalInteraction::GetInstance()->AddInteractor(m_SeedPointInteractor); itk::SimpleMemberCommand::Pointer pointAddedCommand = itk::SimpleMemberCommand::New(); pointAddedCommand->SetCallbackFunction(this, &mitk::FastMarchingTool3D::OnAddPoint); m_PointSetAddObserverTag = m_SeedsAsPointSet->AddObserver( mitk::PointSetAddEvent(), pointAddedCommand); itk::SimpleMemberCommand::Pointer pointRemovedCommand = itk::SimpleMemberCommand::New(); pointRemovedCommand->SetCallbackFunction(this, &mitk::FastMarchingTool3D::OnDelete); m_PointSetRemoveObserverTag = m_SeedsAsPointSet->AddObserver( mitk::PointSetRemoveEvent(), pointRemovedCommand); this->Initialize(); } void mitk::FastMarchingTool3D::Deactivated() { Superclass::Deactivated(); m_ToolManager->GetDataStorage()->Remove( this->m_ResultImageNode ); m_ToolManager->GetDataStorage()->Remove( this->m_SeedsAsPointSetNode ); this->ClearSeeds(); this->m_SmoothFilter->RemoveAllObservers(); this->m_SigmoidFilter->RemoveAllObservers(); this->m_GradientMagnitudeFilter->RemoveAllObservers(); this->m_FastMarchingFilter->RemoveAllObservers(); m_ResultImageNode = NULL; mitk::RenderingManager::GetInstance()->RequestUpdateAll(); unsigned int numberOfPoints = m_SeedsAsPointSet->GetSize(); for (unsigned int i = 0; i < numberOfPoints; ++i) { mitk::Point3D point = m_SeedsAsPointSet->GetPoint(i); mitk::PointOperation* doOp = new mitk::PointOperation(mitk::OpREMOVE, point, 0); m_SeedsAsPointSet->ExecuteOperation(doOp); } mitk::GlobalInteraction::GetInstance()->RemoveInteractor(m_SeedPointInteractor); m_ToolManager->GetDataStorage()->Remove(m_SeedsAsPointSetNode); m_SeedsAsPointSetNode = NULL; m_SeedsAsPointSet->RemoveObserver(m_PointSetAddObserverTag); m_SeedsAsPointSet->RemoveObserver(m_PointSetRemoveObserverTag); } void mitk::FastMarchingTool3D::Initialize() { m_ReferenceImage = dynamic_cast(m_ToolManager->GetReferenceData(0)->GetData()); if(m_ReferenceImage->GetTimeGeometry()->CountTimeSteps() > 1) { mitk::ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New(); timeSelector->SetInput( m_ReferenceImage ); timeSelector->SetTimeNr( m_CurrentTimeStep ); timeSelector->UpdateLargestPossibleRegion(); m_ReferenceImage = timeSelector->GetOutput(); } CastToItkImage(m_ReferenceImage, m_ReferenceImageAsITK); m_SmoothFilter->SetInput( m_ReferenceImageAsITK ); m_NeedUpdate = true; } void mitk::FastMarchingTool3D::ConfirmSegmentation() { // combine preview image with current working segmentation if (dynamic_cast(m_ResultImageNode->GetData())) { //logical or combination of preview and segmentation slice OutputImageType::Pointer segmentationImageInITK = OutputImageType::New(); mitk::Image::Pointer workingImage = dynamic_cast(GetTargetSegmentationNode()->GetData()); if(workingImage->GetTimeGeometry()->CountTimeSteps() > 1) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput( workingImage ); timeSelector->SetTimeNr( m_CurrentTimeStep ); timeSelector->UpdateLargestPossibleRegion(); CastToItkImage( timeSelector->GetOutput(), segmentationImageInITK ); } else { CastToItkImage( workingImage, segmentationImageInITK ); } typedef itk::OrImageFilter OrImageFilterType; OrImageFilterType::Pointer orFilter = OrImageFilterType::New(); orFilter->SetInput(0, m_ThresholdFilter->GetOutput()); orFilter->SetInput(1, segmentationImageInITK); orFilter->Update(); //set image volume in current time step from itk image workingImage->SetVolume( (void*)(m_ThresholdFilter->GetOutput()->GetPixelContainer()->GetBufferPointer()), m_CurrentTimeStep); this->m_ResultImageNode->SetVisibility(false); this->ClearSeeds(); workingImage->Modified(); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); m_ToolManager->ActivateTool(-1); } void mitk::FastMarchingTool3D::OnAddPoint() { // Add a new seed point for FastMarching algorithm mitk::Point3D clickInIndex; m_ReferenceImage->GetGeometry()->WorldToIndex(m_SeedsAsPointSet->GetPoint(m_SeedsAsPointSet->GetSize()-1), clickInIndex); itk::Index<3> seedPosition; seedPosition[0] = clickInIndex[0]; seedPosition[1] = clickInIndex[1]; seedPosition[2] = clickInIndex[2]; NodeType node; const double seedValue = 0.0; node.SetValue( seedValue ); node.SetIndex( seedPosition ); this->m_SeedContainer->InsertElement(this->m_SeedContainer->Size(), node); m_FastMarchingFilter->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); m_NeedUpdate = true; this->Update(); m_ReadyMessage.Send(); } void mitk::FastMarchingTool3D::OnDelete() { // delete last seed point if(!(this->m_SeedContainer->empty())) { //delete last element of seeds container this->m_SeedContainer->pop_back(); m_FastMarchingFilter->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); m_NeedUpdate = true; this->Update(); } } void mitk::FastMarchingTool3D::Update() { const unsigned int progress_steps = 200; if (m_NeedUpdate) { m_ProgressCommand->AddStepsToDo(progress_steps); //remove interaction with poinset while updating mitk::GlobalInteraction::GetInstance()->RemoveInteractor(m_SeedPointInteractor); CurrentlyBusy.Send(true); try { m_ThresholdFilter->Update(); } catch( itk::ExceptionObject & excep ) { MITK_ERROR << "Exception caught: " << excep.GetDescription(); m_ProgressCommand->SetProgress(progress_steps); CurrentlyBusy.Send(false); std::string msg = excep.GetDescription(); ErrorMessage.Send(msg); return; } m_ProgressCommand->SetProgress(progress_steps); CurrentlyBusy.Send(false); //make output visible mitk::Image::Pointer result = mitk::Image::New(); CastToMitkImage( m_ThresholdFilter->GetOutput(), result); result->GetGeometry()->SetOrigin(m_ReferenceImage->GetGeometry()->GetOrigin() ); result->GetGeometry()->SetIndexToWorldTransform(m_ReferenceImage->GetGeometry()->GetIndexToWorldTransform() ); m_ResultImageNode->SetData(result); m_ResultImageNode->SetVisibility(true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); //add interaction with poinset again mitk::GlobalInteraction::GetInstance()->AddInteractor(m_SeedPointInteractor); } } void mitk::FastMarchingTool3D::ClearSeeds() { // clear seeds for FastMarching as well as the PointSet for visualization if(this->m_SeedContainer.IsNotNull()) this->m_SeedContainer->Initialize(); if(this->m_SeedsAsPointSet.IsNotNull()) { //remove observers from current pointset m_SeedsAsPointSet->RemoveObserver(m_PointSetAddObserverTag); m_SeedsAsPointSet->RemoveObserver(m_PointSetRemoveObserverTag); //renew pointset this->m_SeedsAsPointSet = mitk::PointSet::New(); this->m_SeedsAsPointSetNode->SetData(this->m_SeedsAsPointSet); m_SeedsAsPointSetNode->SetName("Seeds_Preview"); m_SeedsAsPointSetNode->SetBoolProperty("helper object", true); m_SeedsAsPointSetNode->SetColor(0.0, 1.0, 0.0); m_SeedsAsPointSetNode->SetVisibility(true); //add callback function for adding and removing points itk::SimpleMemberCommand::Pointer pointAddedCommand = itk::SimpleMemberCommand::New(); pointAddedCommand->SetCallbackFunction(this, &mitk::FastMarchingTool3D::OnAddPoint); m_PointSetAddObserverTag = m_SeedsAsPointSet->AddObserver( mitk::PointSetAddEvent(), pointAddedCommand); itk::SimpleMemberCommand::Pointer pointRemovedCommand = itk::SimpleMemberCommand::New(); pointRemovedCommand->SetCallbackFunction(this, &mitk::FastMarchingTool3D::OnDelete); m_PointSetRemoveObserverTag = m_SeedsAsPointSet->AddObserver( mitk::PointSetRemoveEvent(), pointRemovedCommand); } if(this->m_FastMarchingFilter.IsNotNull()) m_FastMarchingFilter->Modified(); this->m_NeedUpdate = true; } void mitk::FastMarchingTool3D::Reset() { //clear all seeds and preview empty result this->ClearSeeds(); m_ResultImageNode->SetVisibility(false); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::FastMarchingTool3D::SetCurrentTimeStep(int t) { if( m_CurrentTimeStep != t ) { m_CurrentTimeStep = t; this->Initialize(); } } diff --git a/Modules/Segmentation/Interactions/mitkFastMarchingTool3D.h b/Modules/Segmentation/Interactions/mitkFastMarchingTool3D.h index 471ca36565..a3b12c9126 100644 --- a/Modules/Segmentation/Interactions/mitkFastMarchingTool3D.h +++ b/Modules/Segmentation/Interactions/mitkFastMarchingTool3D.h @@ -1,169 +1,171 @@ /*=================================================================== 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 mitkFastMarchingTool3D_h_Included #define mitkFastMarchingTool3D_h_Included #include "mitkAutoSegmentationTool.h" #include "mitkLegacyAdaptors.h" #include #include "mitkDataNode.h" #include "mitkPointSet.h" #include "mitkPointSetInteractor.h" #include "mitkToolCommand.h" #include "mitkMessage.h" #include "itkImage.h" //itk filter #include "itkFastMarchingImageFilter.h" #include "itkBinaryThresholdImageFilter.h" #include "itkGradientMagnitudeRecursiveGaussianImageFilter.h" #include "itkSigmoidImageFilter.h" #include "itkCurvatureAnisotropicDiffusionImageFilter.h" namespace us { class ModuleResource; } namespace mitk { /** \brief FastMarching semgentation tool. The segmentation is done by setting one or more seed points on the image and adapting the time range and threshold. The pipeline is: Smoothing->GradientMagnitude->SigmoidFunction->FastMarching->Threshold The resulting binary image is seen as a segmentation of an object. For detailed documentation see ITK Software Guide section 9.3.1 Fast Marching Segmentation. */ class MitkSegmentation_EXPORT FastMarchingTool3D : public AutoSegmentationTool { mitkNewMessageMacro(Ready); public: mitkClassMacro(FastMarchingTool3D, AutoSegmentationTool) itkFactorylessNewMacro(Self) itkCloneMacro(Self) /* typedefs for itk pipeline */ typedef float InternalPixelType; typedef itk::Image< InternalPixelType, 3 > InternalImageType; typedef unsigned char OutputPixelType; typedef itk::Image< OutputPixelType, 3 > OutputImageType; typedef itk::BinaryThresholdImageFilter< InternalImageType, OutputImageType > ThresholdingFilterType; typedef itk::CurvatureAnisotropicDiffusionImageFilter< InternalImageType, InternalImageType > SmoothingFilterType; typedef itk::GradientMagnitudeRecursiveGaussianImageFilter< InternalImageType, InternalImageType > GradientFilterType; typedef itk::SigmoidImageFilter< InternalImageType, InternalImageType > SigmoidFilterType; typedef itk::FastMarchingImageFilter< InternalImageType, InternalImageType > FastMarchingFilterType; typedef FastMarchingFilterType::NodeContainer NodeContainer; typedef FastMarchingFilterType::NodeType NodeType; + bool CanHandle(BaseData* referenceData) const; + /* icon stuff */ virtual const char** GetXPM() const; virtual const char* GetName() const; us::ModuleResource GetIconResource() const; /// \brief Set parameter used in Threshold filter. void SetUpperThreshold(double); /// \brief Set parameter used in Threshold filter. void SetLowerThreshold(double); /// \brief Set parameter used in Fast Marching filter. void SetStoppingValue(double); /// \brief Set parameter used in Gradient Magnitude filter. void SetSigma(double); /// \brief Set parameter used in Fast Marching filter. void SetAlpha(double); /// \brief Set parameter used in Fast Marching filter. void SetBeta(double); /// \brief Adds the feedback image to the current working image. virtual void ConfirmSegmentation(); /// \brief Set the working time step. virtual void SetCurrentTimeStep(int t); /// \brief Clear all seed points. void ClearSeeds(); /// \brief Updates the itk pipeline and shows the result of FastMarching. void Update(); protected: FastMarchingTool3D(); virtual ~FastMarchingTool3D(); virtual void Activated(); virtual void Deactivated(); virtual void Initialize(); /// \brief Add point action of StateMachine pattern virtual void OnAddPoint (); /// \brief Delete action of StateMachine pattern virtual void OnDelete (); /// \brief Reset all relevant inputs of the itk pipeline. void Reset(); mitk::ToolCommand::Pointer m_ProgressCommand; Image::Pointer m_ReferenceImage; bool m_NeedUpdate; int m_CurrentTimeStep; float m_LowerThreshold; //used in Threshold filter float m_UpperThreshold; //used in Threshold filter float m_StoppingValue; //used in Fast Marching filter float m_Sigma; //used in GradientMagnitude filter float m_Alpha; //used in Sigmoid filter float m_Beta; //used in Sigmoid filter NodeContainer::Pointer m_SeedContainer; //seed points for FastMarching InternalImageType::Pointer m_ReferenceImageAsITK; //the reference image as itk::Image mitk::DataNode::Pointer m_ResultImageNode;//holds the result as a preview image mitk::DataNode::Pointer m_SeedsAsPointSetNode;//used to visualize the seed points mitk::PointSet::Pointer m_SeedsAsPointSet; mitk::PointSetInteractor::Pointer m_SeedPointInteractor; unsigned int m_PointSetAddObserverTag; unsigned int m_PointSetRemoveObserverTag; ThresholdingFilterType::Pointer m_ThresholdFilter; SmoothingFilterType::Pointer m_SmoothFilter; GradientFilterType::Pointer m_GradientMagnitudeFilter; SigmoidFilterType::Pointer m_SigmoidFilter; FastMarchingFilterType::Pointer m_FastMarchingFilter; }; } // namespace #endif diff --git a/Modules/Segmentation/Interactions/mitkTool.cpp b/Modules/Segmentation/Interactions/mitkTool.cpp index 844d538134..5ddee30199 100644 --- a/Modules/Segmentation/Interactions/mitkTool.cpp +++ b/Modules/Segmentation/Interactions/mitkTool.cpp @@ -1,251 +1,256 @@ /*=================================================================== 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 "mitkTool.h" #include "mitkDataNodeFactory.h" #include "mitkProperties.h" #include "mitkImageWriteAccessor.h" #include "mitkLevelWindowProperty.h" #include "mitkVtkResliceInterpolationProperty.h" #include "mitkImageReadAccessor.h" // us #include #include #include mitk::Tool::Tool(const char* type) : m_PredicateImages(NodePredicateDataType::New("Image")) // for reference images , m_PredicateDim3(NodePredicateDimension::New(3, 1)) , m_PredicateDim4(NodePredicateDimension::New(4, 1)) , m_PredicateDimension( mitk::NodePredicateOr::New(m_PredicateDim3, m_PredicateDim4) ) , m_PredicateImage3D( NodePredicateAnd::New(m_PredicateImages, m_PredicateDimension) ) , m_PredicateBinary(NodePredicateProperty::New("binary", BoolProperty::New(true))) , m_PredicateNotBinary( NodePredicateNot::New(m_PredicateBinary) ) , m_PredicateSegmentation(NodePredicateProperty::New("segmentation", BoolProperty::New(true))) , m_PredicateNotSegmentation( NodePredicateNot::New(m_PredicateSegmentation) ) , m_PredicateHelper(NodePredicateProperty::New("helper object", BoolProperty::New(true))) , m_PredicateNotHelper( NodePredicateNot::New(m_PredicateHelper) ) , m_PredicateImageColorful( NodePredicateAnd::New(m_PredicateNotBinary, m_PredicateNotSegmentation) ) , m_PredicateImageColorfulNotHelper( NodePredicateAnd::New(m_PredicateImageColorful, m_PredicateNotHelper) ) , m_PredicateReference( NodePredicateAnd::New(m_PredicateImage3D, m_PredicateImageColorfulNotHelper) ) , m_IsSegmentationPredicate(NodePredicateAnd::New(NodePredicateOr::New(m_PredicateBinary, m_PredicateSegmentation), m_PredicateNotHelper)) , m_InteractorType( type ) { } mitk::Tool::~Tool() { } +bool mitk::Tool::CanHandle(BaseData* referenceData) const +{ + return true; +} + void mitk::Tool::InitializeStateMachine() { if (m_InteractorType.empty()) return; m_InteractorType += ".xml"; try { LoadStateMachine( m_InteractorType, us::GetModuleContext()->GetModule() ); SetEventConfig( "SegmentationToolsConfig.xml", us::GetModuleContext()->GetModule() ); } catch( const std::exception& e ) { MITK_ERROR << "Could not load statemachine pattern " << m_InteractorType << " with exception: " << e.what(); } } void mitk::Tool::Notify( InteractionEvent* interactionEvent, bool isHandled ) { // to use the state machine pattern, // the event is passed to the state machine interface to be handled if ( !isHandled ) { this->HandleEvent(interactionEvent, NULL); } } void mitk::Tool::ConnectActionsAndFunctions() { } bool mitk::Tool::FilterEvents(InteractionEvent* , DataNode* ) { return true; } const char* mitk::Tool::GetGroup() const { return "default"; } void mitk::Tool::SetToolManager(ToolManager* manager) { m_ToolManager = manager; } void mitk::Tool::Activated() { } void mitk::Tool::Deactivated() { // ToDo: reactivate this feature! //StateMachine::ResetStatemachineToStartState(); // forget about the past } itk::Object::Pointer mitk::Tool::GetGUI(const std::string& toolkitPrefix, const std::string& toolkitPostfix) { itk::Object::Pointer object; std::string classname = this->GetNameOfClass(); std::string guiClassname = toolkitPrefix + classname + toolkitPostfix; std::list allGUIs = itk::ObjectFactoryBase::CreateAllInstance(guiClassname.c_str()); for( std::list::iterator iter = allGUIs.begin(); iter != allGUIs.end(); ++iter ) { if (object.IsNull()) { object = dynamic_cast( iter->GetPointer() ); } else { MITK_ERROR << "There is more than one GUI for " << classname << " (several factories claim ability to produce a " << guiClassname << " ) " << std::endl; return NULL; // people should see and fix this error } } return object; } mitk::NodePredicateBase::ConstPointer mitk::Tool::GetReferenceDataPreference() const { return m_PredicateReference.GetPointer(); } mitk::NodePredicateBase::ConstPointer mitk::Tool::GetWorkingDataPreference() const { return m_IsSegmentationPredicate.GetPointer(); } mitk::DataNode::Pointer mitk::Tool::CreateEmptySegmentationNode( Image* original, const std::string& organName, const mitk::Color& color ) { // we NEED a reference image for size etc. if (!original) return NULL; // actually create a new empty segmentation PixelType pixelType(mitk::MakeScalarPixelType() ); Image::Pointer segmentation = Image::New(); if (original->GetDimension() == 2) { const unsigned int dimensions[] = { original->GetDimension(0), original->GetDimension(1), 1 }; segmentation->Initialize(pixelType, 3, dimensions); } else { segmentation->Initialize(pixelType, original->GetDimension(), original->GetDimensions()); } unsigned int byteSize = sizeof(DefaultSegmentationDataType); if(segmentation->GetDimension() < 4) { for (unsigned int dim = 0; dim < segmentation->GetDimension(); ++dim) { byteSize *= segmentation->GetDimension(dim); } mitk::ImageWriteAccessor writeAccess(segmentation, segmentation->GetVolumeData(0)); memset( writeAccess.GetData(), 0, byteSize ); } else {//if we have a time-resolved image we need to set memory to 0 for each time step for (unsigned int dim = 0; dim < 3; ++dim) { byteSize *= segmentation->GetDimension(dim); } for( unsigned int volumeNumber = 0; volumeNumber < segmentation->GetDimension(3); volumeNumber++) { mitk::ImageWriteAccessor writeAccess(segmentation, segmentation->GetVolumeData(volumeNumber)); memset( writeAccess.GetData(), 0, byteSize ); } } if (original->GetTimeGeometry() ) { TimeGeometry::Pointer originalGeometry = original->GetTimeGeometry()->Clone(); segmentation->SetTimeGeometry( originalGeometry ); } else { Tool::ErrorMessage("Original image does not have a 'Time sliced geometry'! Cannot create a segmentation."); return NULL; } return CreateSegmentationNode( segmentation, organName, color ); } mitk::DataNode::Pointer mitk::Tool::CreateSegmentationNode( Image* image, const std::string& organName, const mitk::Color& color ) { if (!image) return NULL; // decorate the datatreenode with some properties DataNode::Pointer segmentationNode = DataNode::New(); segmentationNode->SetData( image ); // name segmentationNode->SetProperty( "name", StringProperty::New( organName ) ); // visualization properties segmentationNode->SetProperty( "binary", BoolProperty::New(true) ); segmentationNode->SetProperty( "color", ColorProperty::New(color) ); segmentationNode->SetProperty( "texture interpolation", BoolProperty::New(false) ); segmentationNode->SetProperty( "layer", IntProperty::New(10) ); segmentationNode->SetProperty( "levelwindow", LevelWindowProperty::New( LevelWindow(0.5, 1) ) ); segmentationNode->SetProperty( "opacity", FloatProperty::New(0.3) ); segmentationNode->SetProperty( "segmentation", BoolProperty::New(true) ); segmentationNode->SetProperty( "reslice interpolation", VtkResliceInterpolationProperty::New() ); // otherwise -> segmentation appears in 2 slices sometimes (only visual effect, not different data) // For MITK-3M3 release, the volume of all segmentations should be shown segmentationNode->SetProperty( "showVolume", BoolProperty::New( true ) ); return segmentationNode; } us::ModuleResource mitk::Tool::GetIconResource() const { // Each specific tool should load its own resource. This one will be invalid return us::ModuleResource(); } us::ModuleResource mitk::Tool::GetCursorIconResource() const { // Each specific tool should load its own resource. This one will be invalid return us::ModuleResource(); } diff --git a/Modules/Segmentation/Interactions/mitkTool.h b/Modules/Segmentation/Interactions/mitkTool.h index d7abb8998f..75e4f67cc1 100644 --- a/Modules/Segmentation/Interactions/mitkTool.h +++ b/Modules/Segmentation/Interactions/mitkTool.h @@ -1,252 +1,254 @@ /*=================================================================== 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 mitkTool_h_Included #define mitkTool_h_Included #include "mitkCommon.h" #include #include "mitkStateMachine.h" #include "mitkToolEvents.h" #include "itkObjectFactoryBase.h" #include "itkVersion.h" #include "mitkToolFactoryMacro.h" #include "mitkMessage.h" #include "mitkDataNode.h" #include "mitkNodePredicateProperty.h" #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateDimension.h" #include "mitkNodePredicateAnd.h" #include "mitkNodePredicateOr.h" #include "mitkNodePredicateNot.h" #include #include #include #include "mitkInteractionEventObserver.h" #include "mitkEventStateMachine.h" namespace us { class ModuleResource; } namespace mitk { class ToolManager; /** \brief Base class of all tools used by mitk::ToolManager. \sa ToolManager \sa SegTool2D \ingroup Interaction \ingroup ToolManagerEtAl There is a separate page describing the \ref QmitkInteractiveSegmentationTechnicalPage. Every tool is a mitk::StateMachine, which can follow any transition pattern that it likes. One important thing to know is, that every derived tool should always call SuperClass::Deactivated() in its own implementation of Deactivated, because mitk::Tool resets the StateMachine in this method. Only if you are very sure that you covered all possible things that might happen to your own tool, you should consider not to reset the StateMachine from time to time. To learn about the MITK implementation of state machines in general, have a look at \ref InteractionPage. To derive a non-abstract tool, you inherit from mitk::Tool (or some other base class further down the inheritance tree), and in your own parameterless constructor (that is called from the itkFactorylessNewMacro that you use) you pass a StateMachine pattern name to the superclass. Names for valid patterns can be found in StateMachine.xml (which might be enhanced by you). You have to implement at least GetXPM() and GetName() to provide some identification. Each Tool knows its ToolManager, which can provide the data that the tool should work on. \warning Only to be instantiated by mitk::ToolManager (because SetToolManager has to be called). All other uses are unsupported. $Author$ */ class MitkSegmentation_EXPORT Tool : public EventStateMachine , public InteractionEventObserver { public: typedef unsigned char DefaultSegmentationDataType; /** * \brief To let GUI process new events (e.g. qApp->processEvents() ) */ Message<> GUIProcessEventsMessage; /** * \brief To send error messages (to be shown by some GUI) */ Message1 ErrorMessage; /** * \brief To send whether the tool is busy (to be shown by some GUI) */ Message1 CurrentlyBusy; /** * \brief To send general messages (to be shown by some GUI) */ Message1 GeneralMessage; mitkClassMacro(Tool, EventStateMachine); // no New(), there should only be subclasses /** \brief Returns an icon in the XPM format. This icon has to fit into some kind of button in most applications, so make it smaller than 25x25 pixels. XPM is e.g. supported by The Gimp. But if you open any XPM file in your text editor, you will see that you could also "draw" it with an editor. */ virtual const char** GetXPM() const = 0; /** * \brief Returns the path of an icon. * * This icon is preferred to the XPM icon. */ virtual std::string GetIconPath() const { return ""; } /** * \brief Returns the path of a cursor icon. * */ virtual us::ModuleResource GetCursorIconResource() const; /** * @brief Returns the tool button icon of the tool wrapped by a usModuleResource * @return a valid ModuleResource or an invalid if this function * is not reimplemented */ virtual us::ModuleResource GetIconResource() const; /** \brief Returns the name of this tool. Make it short! This name has to fit into some kind of button in most applications, so take some time to think of a good name! */ virtual const char* GetName() const = 0; /** \brief Name of a group. You can group several tools by assigning a group name. Graphical tool selectors might use this information to group tools. (What other reason could there be?) */ virtual const char* GetGroup() const; virtual void InitializeStateMachine(); /** * \brief Interface for GUI creation. * * This is the basic interface for creation of a GUI object belonging to one tool. * * Tools that support a GUI (e.g. for display/editing of parameters) should follow some rules: * * - A Tool and its GUI are two separate classes * - There may be several instances of a GUI at the same time. * - mitk::Tool is toolkit (Qt, wxWidgets, etc.) independent, the GUI part is of course dependent * - The GUI part inherits both from itk::Object and some GUI toolkit class * - The GUI class name HAS to be constructed like "toolkitPrefix" tool->GetClassName() + "toolkitPostfix", e.g. MyTool -> wxMyToolGUI * - For each supported toolkit there is a base class for tool GUIs, which contains some convenience methods * - Tools notify the GUI about changes using ITK events. The GUI must observe interesting events. * - The GUI base class may convert all ITK events to the GUI toolkit's favoured messaging system (Qt -> signals) * - Calling methods of a tool by its GUI is done directly. * In some cases GUIs don't want to be notified by the tool when they cause a change in a tool. * There is a macro CALL_WITHOUT_NOTICE(method()), which will temporarily disable all notifications during a method call. */ virtual itk::Object::Pointer GetGUI(const std::string& toolkitPrefix, const std::string& toolkitPostfix); virtual NodePredicateBase::ConstPointer GetReferenceDataPreference() const; virtual NodePredicateBase::ConstPointer GetWorkingDataPreference() const; DataNode::Pointer CreateEmptySegmentationNode( Image* original, const std::string& organName, const mitk::Color& color ); DataNode::Pointer CreateSegmentationNode( Image* image, const std::string& organName, const mitk::Color& color ); + virtual bool CanHandle(BaseData* referenceData) const; + protected: friend class ToolManager; virtual void SetToolManager(ToolManager*); void ConnectActionsAndFunctions(); /** \brief Called when the tool gets activated (registered to mitk::GlobalInteraction). Derived tools should call their parents implementation. */ virtual void Activated(); /** \brief Called when the tool gets deactivated (unregistered from mitk::GlobalInteraction). Derived tools should call their parents implementation. */ virtual void Deactivated(); Tool(); // purposely hidden Tool( const char*); // purposely hidden virtual ~Tool(); virtual void Notify( InteractionEvent* interactionEvent,bool isHandled ); bool FilterEvents(InteractionEvent* , DataNode* ); ToolManager* m_ToolManager; private: // for reference data NodePredicateDataType::Pointer m_PredicateImages; NodePredicateDimension::Pointer m_PredicateDim3; NodePredicateDimension::Pointer m_PredicateDim4; NodePredicateOr::Pointer m_PredicateDimension; NodePredicateAnd::Pointer m_PredicateImage3D; NodePredicateProperty::Pointer m_PredicateBinary; NodePredicateNot::Pointer m_PredicateNotBinary; NodePredicateProperty::Pointer m_PredicateSegmentation; NodePredicateNot::Pointer m_PredicateNotSegmentation; NodePredicateProperty::Pointer m_PredicateHelper; NodePredicateNot::Pointer m_PredicateNotHelper; NodePredicateAnd::Pointer m_PredicateImageColorful; NodePredicateAnd::Pointer m_PredicateImageColorfulNotHelper; NodePredicateAnd::Pointer m_PredicateReference; // for working data NodePredicateAnd::Pointer m_IsSegmentationPredicate; std::string m_InteractorType; }; } // namespace #endif diff --git a/Modules/SegmentationUI/Qmitk/QmitkToolSelectionBox.cpp b/Modules/SegmentationUI/Qmitk/QmitkToolSelectionBox.cpp index 05bf9cc63f..2354e4c12d 100755 --- a/Modules/SegmentationUI/Qmitk/QmitkToolSelectionBox.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitkToolSelectionBox.cpp @@ -1,673 +1,678 @@ /*=================================================================== 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. ===================================================================*/ //#define MBILOG_ENABLE_DEBUG 1 #include "QmitkToolSelectionBox.h" #include "QmitkToolGUI.h" #include "mitkBaseRenderer.h" #include #include #include #include #include #include #include #include "usModuleResource.h" #include "usModuleResourceStream.h" #include "mitkToolManagerProvider.h" QmitkToolSelectionBox::QmitkToolSelectionBox(QWidget* parent, mitk::DataStorage* storage) :QWidget(parent), m_SelfCall(false), m_DisplayedGroups("default"), m_LayoutColumns(2), m_ShowNames(true), m_GenerateAccelerators(false), m_ToolGUIWidget(NULL), m_LastToolGUI(NULL), m_ToolButtonGroup(NULL), m_ButtonLayout(NULL), m_EnabledMode(EnabledWithReferenceAndWorkingDataVisible) { QFont currentFont = QWidget::font(); currentFont.setBold(true); QWidget::setFont( currentFont ); m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); // muellerm // QButtonGroup m_ToolButtonGroup = new QButtonGroup(this); // some features of QButtonGroup m_ToolButtonGroup->setExclusive( false ); // mutually exclusive toggle buttons RecreateButtons(); QWidget::setContentsMargins(0, 0, 0, 0); if ( layout() != NULL ) { layout()->setContentsMargins(0, 0, 0, 0); } // reactions to signals connect( m_ToolButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(toolButtonClicked(int)) ); // reactions to ToolManager events m_ToolManager->ActiveToolChanged += mitk::MessageDelegate( this, &QmitkToolSelectionBox::OnToolManagerToolModified ); m_ToolManager->ReferenceDataChanged += mitk::MessageDelegate( this, &QmitkToolSelectionBox::OnToolManagerReferenceDataModified ); m_ToolManager->WorkingDataChanged += mitk::MessageDelegate( this, &QmitkToolSelectionBox::OnToolManagerWorkingDataModified ); // show active tool SetOrUnsetButtonForActiveTool(); QWidget::setEnabled( false ); } QmitkToolSelectionBox::~QmitkToolSelectionBox() { m_ToolManager->ActiveToolChanged -= mitk::MessageDelegate( this, &QmitkToolSelectionBox::OnToolManagerToolModified ); m_ToolManager->ReferenceDataChanged -= mitk::MessageDelegate( this, &QmitkToolSelectionBox::OnToolManagerReferenceDataModified ); m_ToolManager->WorkingDataChanged -= mitk::MessageDelegate( this, &QmitkToolSelectionBox::OnToolManagerWorkingDataModified ); } void QmitkToolSelectionBox::SetEnabledMode(EnabledMode mode) { m_EnabledMode = mode; SetGUIEnabledAccordingToToolManagerState(); } mitk::ToolManager* QmitkToolSelectionBox::GetToolManager() { return m_ToolManager; } void QmitkToolSelectionBox::SetToolManager(mitk::ToolManager& newManager) // no NULL pointer allowed here, a manager is required { // say bye to the old manager m_ToolManager->ActiveToolChanged -= mitk::MessageDelegate( this, &QmitkToolSelectionBox::OnToolManagerToolModified ); m_ToolManager->ReferenceDataChanged -= mitk::MessageDelegate( this, &QmitkToolSelectionBox::OnToolManagerReferenceDataModified ); m_ToolManager->WorkingDataChanged -= mitk::MessageDelegate( this, &QmitkToolSelectionBox::OnToolManagerWorkingDataModified ); if ( QWidget::isEnabled() ) { m_ToolManager->UnregisterClient(); } m_ToolManager = &newManager; RecreateButtons(); // greet the new one m_ToolManager->ActiveToolChanged += mitk::MessageDelegate( this, &QmitkToolSelectionBox::OnToolManagerToolModified ); m_ToolManager->ReferenceDataChanged += mitk::MessageDelegate( this, &QmitkToolSelectionBox::OnToolManagerReferenceDataModified ); m_ToolManager->WorkingDataChanged += mitk::MessageDelegate( this, &QmitkToolSelectionBox::OnToolManagerWorkingDataModified ); if ( QWidget::isEnabled() ) { m_ToolManager->RegisterClient(); } // ask the new one what the situation is like SetOrUnsetButtonForActiveTool(); } void QmitkToolSelectionBox::toolButtonClicked(int id) { if ( !QWidget::isEnabled() ) return; // this method could be triggered from the constructor, when we are still disabled MITK_DEBUG << "toolButtonClicked(" << id << "): id translates to tool ID " << m_ToolIDForButtonID[id]; //QToolButton* toolButton = dynamic_cast( Q3ButtonGroup::find(id) ); QToolButton* toolButton = dynamic_cast( m_ToolButtonGroup->buttons().at(id) ); if (toolButton) { if ( (m_ButtonIDForToolID.find( m_ToolManager->GetActiveToolID() ) != m_ButtonIDForToolID.end()) // if we have this tool in our box && (m_ButtonIDForToolID[ m_ToolManager->GetActiveToolID() ] == id) ) // the tool corresponding to this button is already active { // disable this button, disable all tools // mmueller toolButton->setChecked(false); m_ToolManager->ActivateTool(-1); // disable everything } else { // enable the corresponding tool m_SelfCall = true; m_ToolManager->ActivateTool( m_ToolIDForButtonID[id] ); m_SelfCall = false; } } } void QmitkToolSelectionBox::OnToolManagerToolModified() { SetOrUnsetButtonForActiveTool(); } void QmitkToolSelectionBox::SetOrUnsetButtonForActiveTool() { // we want to emit a signal in any case, whether we selected ourselves or somebody else changes "our" tool manager. --> emit before check on m_SelfCall int id = m_ToolManager->GetActiveToolID(); // don't emit signal for shape model tools bool emitSignal = true; mitk::Tool* tool = m_ToolManager->GetActiveTool(); if(tool && std::string(tool->GetGroup()) == "organ_segmentation") emitSignal = false; if(emitSignal) emit ToolSelected(id); // delete old GUI (if any) if ( m_LastToolGUI && m_ToolGUIWidget ) { if (m_ToolGUIWidget->layout()) { m_ToolGUIWidget->layout()->removeWidget(m_LastToolGUI); } //m_LastToolGUI->reparent(NULL, QPoint(0,0)); // TODO: reparent <-> setParent, Daniel fragen m_LastToolGUI->setParent(0); delete m_LastToolGUI; // will hopefully notify parent and layouts m_LastToolGUI = NULL; QLayout* layout = m_ToolGUIWidget->layout(); if (layout) { layout->activate(); } } QToolButton* toolButton(NULL); //mitk::Tool* tool = m_ToolManager->GetActiveTool(); if (m_ButtonIDForToolID.find(id) != m_ButtonIDForToolID.end()) // if this tool is in our box { //toolButton = dynamic_cast( Q3ButtonGroup::find( m_ButtonIDForToolID[id] ) ); toolButton = dynamic_cast( m_ToolButtonGroup->buttons().at( m_ButtonIDForToolID[id] ) ); } if ( toolButton ) { // mmueller // uncheck all other buttons QAbstractButton* tmpBtn = 0; QList::iterator it; for(int i=0; i < m_ToolButtonGroup->buttons().size(); ++i) { tmpBtn = m_ToolButtonGroup->buttons().at(i); if(tmpBtn != toolButton) dynamic_cast( tmpBtn )->setChecked(false); } toolButton->setChecked(true); if (m_ToolGUIWidget && tool) { // create and reparent new GUI (if any) itk::Object::Pointer possibleGUI = tool->GetGUI("Qmitk", "GUI").GetPointer(); // prefix and postfix QmitkToolGUI* gui = dynamic_cast( possibleGUI.GetPointer() ); //! m_LastToolGUI = gui; if (gui) { gui->SetTool( tool ); // mmueller //gui->reparent(m_ToolGUIWidget, gui->geometry().topLeft(), true ); gui->setParent(m_ToolGUIWidget); gui->move(gui->geometry().topLeft()); gui->show(); QLayout* layout = m_ToolGUIWidget->layout(); if (!layout) { layout = new QVBoxLayout( m_ToolGUIWidget ); } if (layout) { // mmueller layout->addWidget( gui ); //layout->add( gui ); layout->activate(); } } } } else { // disable all buttons QToolButton* selectedToolButton = dynamic_cast( m_ToolButtonGroup->checkedButton() ); //QToolButton* selectedToolButton = dynamic_cast( Q3ButtonGroup::find( Q3ButtonGroup::selectedId() ) ); if (selectedToolButton) { // mmueller selectedToolButton->setChecked(false); //selectedToolButton->setOn(false); } } } void QmitkToolSelectionBox::OnToolManagerReferenceDataModified() { if (m_SelfCall) return; MITK_DEBUG << "OnToolManagerReferenceDataModified()"; SetGUIEnabledAccordingToToolManagerState(); } void QmitkToolSelectionBox::OnToolManagerWorkingDataModified() { if (m_SelfCall) return; MITK_DEBUG << "OnToolManagerWorkingDataModified()"; SetGUIEnabledAccordingToToolManagerState(); } /** Implementes the logic, which decides, when tools are activated/deactivated. */ void QmitkToolSelectionBox::SetGUIEnabledAccordingToToolManagerState() { mitk::DataNode* referenceNode = m_ToolManager->GetReferenceData(0); mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); //MITK_DEBUG << this->name() << ": SetGUIEnabledAccordingToToolManagerState: referenceNode " << (void*)referenceNode << " workingNode " << (void*)workingNode << " isVisible() " << isVisible(); bool enabled = true; switch ( m_EnabledMode ) { default: case EnabledWithReferenceAndWorkingDataVisible: enabled = referenceNode && workingNode && referenceNode->IsVisible(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1"))) && workingNode->IsVisible(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1"))) && isVisible(); break; case EnabledWithReferenceData: enabled = referenceNode && isVisible(); break; case EnabledWithWorkingData: enabled = workingNode && isVisible(); break; case AlwaysEnabled: enabled = isVisible(); break; } if ( QWidget::isEnabled() == enabled ) return; // nothing to change QWidget::setEnabled( enabled ); if (enabled) { m_ToolManager->RegisterClient(); int id = m_ToolManager->GetActiveToolID(); emit ToolSelected(id); } else { m_ToolManager->ActivateTool(-1); m_ToolManager->UnregisterClient(); emit ToolSelected(-1); } } /** External enableization... */ void QmitkToolSelectionBox::setEnabled( bool /*enable*/ ) { SetGUIEnabledAccordingToToolManagerState(); } void QmitkToolSelectionBox::RecreateButtons() { if (m_ToolManager.IsNull()) return; /* // remove all buttons that are there QObjectList *l = Q3ButtonGroup::queryList( "QButton" ); QObjectListIt it( *l ); // iterate over all buttons QObject *obj; while ( (obj = it.current()) != 0 ) { ++it; QButton* button = dynamic_cast(obj); if (button) { Q3ButtonGroup::remove(button); delete button; } } delete l; // delete the list, not the objects */ // mmueller Qt4 impl QList l = m_ToolButtonGroup->buttons(); // remove all buttons that are there QList::iterator it; QAbstractButton * btn; for(it=l.begin(); it!=l.end();++it) { btn = *it; m_ToolButtonGroup->removeButton(btn); //this->removeChild(btn); delete btn; } // end mmueller Qt4 impl mitk::ToolManager::ToolVectorTypeConst allPossibleTools = m_ToolManager->GetTools(); mitk::ToolManager::ToolVectorTypeConst allTools; typedef std::pair< std::string::size_type, const mitk::Tool* > SortPairType; typedef std::priority_queue< SortPairType > SortedToolQueueType; SortedToolQueueType toolPositions; // clear and sort all tools // step one: find name/group of all tools in m_DisplayedGroups string. remember these positions for all tools. for ( mitk::ToolManager::ToolVectorTypeConst::const_iterator iter = allPossibleTools.begin(); iter != allPossibleTools.end(); ++iter) { const mitk::Tool* tool = *iter; std::string::size_type namePos = m_DisplayedGroups.find( std::string("'") + tool->GetName() + "'" ); std::string::size_type groupPos = m_DisplayedGroups.find( std::string("'") + tool->GetGroup() + "'" ); if ( !m_DisplayedGroups.empty() && namePos == std::string::npos && groupPos == std::string::npos ) continue; // skip if ( m_DisplayedGroups.empty() && std::string(tool->GetName()).length() > 0 ) { namePos = static_cast (tool->GetName()[0]); } SortPairType thisPair = std::make_pair( namePos < groupPos ? namePos : groupPos, *iter ); toolPositions.push( thisPair ); } // step two: sort tools according to previously found positions in m_DisplayedGroups MITK_DEBUG << "Sorting order of tools (lower number --> earlier in button group)"; while ( !toolPositions.empty() ) { SortPairType thisPair = toolPositions.top(); MITK_DEBUG << "Position " << thisPair.first << " : " << thisPair.second->GetName(); allTools.push_back( thisPair.second ); toolPositions.pop(); } std::reverse( allTools.begin(), allTools.end() ); MITK_DEBUG << "Sorted tools:"; for ( mitk::ToolManager::ToolVectorTypeConst::const_iterator iter = allTools.begin(); iter != allTools.end(); ++iter) { MITK_DEBUG << (*iter)->GetName(); } // try to change layout... bad? //Q3GroupBox::setColumnLayout ( m_LayoutColumns, Qt::Horizontal ); // mmueller using gridlayout instead of Q3GroupBox //this->setLayout(0); if(m_ButtonLayout == NULL) m_ButtonLayout = new QGridLayout; /*else delete m_ButtonLayout;*/ int row(0); int column(-1); int currentButtonID(0); m_ButtonIDForToolID.clear(); m_ToolIDForButtonID.clear(); QToolButton* button = 0; MITK_DEBUG << "Creating buttons for tools"; // fill group box with buttons for ( mitk::ToolManager::ToolVectorTypeConst::const_iterator iter = allTools.begin(); iter != allTools.end(); ++iter) { const mitk::Tool* tool = *iter; int currentToolID( m_ToolManager->GetToolID( tool ) ); ++column; // new line if we are at the maximum columns if(column == m_LayoutColumns) { ++row; column = 0; } button = new QToolButton; button->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum)); // add new button to the group MITK_DEBUG << "Adding button with ID " << currentToolID; m_ToolButtonGroup->addButton(button, currentButtonID); // ... and to the layout MITK_DEBUG << "Adding button in row/column " << row << "/" << column; m_ButtonLayout->addWidget(button, row, column); if (m_LayoutColumns == 1) { //button->setTextPosition( QToolButton::BesideIcon ); // mmueller button->setToolButtonStyle( Qt::ToolButtonTextBesideIcon ); } else { //button->setTextPosition( QToolButton::BelowIcon ); // mmueller button->setToolButtonStyle( Qt::ToolButtonTextUnderIcon ); } //button->setToggleButton( true ); // mmueller button->setCheckable ( true ); if(currentToolID == m_ToolManager->GetActiveToolID()) button->setChecked(true); QString label; if (m_GenerateAccelerators) { label += "&"; } label += tool->GetName(); QString tooltip = tool->GetName(); MITK_DEBUG << tool->GetName() << ", " << label.toLocal8Bit().constData() << ", '" << tooltip.toLocal8Bit().constData(); if ( m_ShowNames ) { /* button->setUsesTextLabel(true); button->setTextLabel( label ); // a label QToolTip::add( button, tooltip ); */ // mmueller Qt4 button->setText( label ); // a label button->setToolTip( tooltip ); // mmueller QFont currentFont = button->font(); currentFont.setBold(false); button->setFont( currentFont ); } us::ModuleResource iconResource = tool->GetIconResource(); if (!iconResource.IsValid()) { button->setIcon(QIcon(QPixmap(tool->GetXPM()))); } else { us::ModuleResourceStream resourceStream(iconResource, std::ios::binary); resourceStream.seekg(0, std::ios::end); std::ios::pos_type length = resourceStream.tellg(); resourceStream.seekg(0, std::ios::beg); char* data = new char[length]; resourceStream.read(data, length); QPixmap pixmap; pixmap.loadFromData(QByteArray::fromRawData(data, length)); QIcon* icon = new QIcon(pixmap); delete[] data; button->setIcon(*icon); if (m_ShowNames) { if (m_LayoutColumns == 1) button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); else button->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); button->setIconSize(QSize(24, 24)); } else { button->setToolButtonStyle(Qt::ToolButtonIconOnly); button->setIconSize(QSize(32,32)); button->setToolTip(tooltip); } } if (m_GenerateAccelerators) { QString firstLetter = QString( tool->GetName() ); firstLetter.truncate( 1 ); button->setShortcut( firstLetter ); // a keyboard shortcut (just the first letter of the given name w/o any CTRL or something) } + mitk::DataNode* dataNode = m_ToolManager->GetReferenceData(0); + + if (dataNode != NULL && !tool->CanHandle(dataNode->GetData())) + button->setEnabled(false); + m_ButtonIDForToolID[currentToolID] = currentButtonID; m_ToolIDForButtonID[currentButtonID] = currentToolID; MITK_DEBUG << "m_ButtonIDForToolID[" << currentToolID << "] == " << currentButtonID; MITK_DEBUG << "m_ToolIDForButtonID[" << currentButtonID << "] == " << currentToolID; tool->GUIProcessEventsMessage += mitk::MessageDelegate( this, &QmitkToolSelectionBox::OnToolGUIProcessEventsMessage ); // will never add a listener twice, so we don't have to check here tool->ErrorMessage += mitk::MessageDelegate1( this, &QmitkToolSelectionBox::OnToolErrorMessage ); // will never add a listener twice, so we don't have to check here tool->GeneralMessage += mitk::MessageDelegate1( this, &QmitkToolSelectionBox::OnGeneralToolMessage ); ++currentButtonID; } // setting grid layout for this groupbox this->setLayout(m_ButtonLayout); //this->update(); } void QmitkToolSelectionBox::OnToolGUIProcessEventsMessage() { qApp->processEvents(); } void QmitkToolSelectionBox::OnToolErrorMessage(std::string s) { QMessageBox::critical(this, "MITK", QString( s.c_str() ), QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); } void QmitkToolSelectionBox::OnGeneralToolMessage(std::string s) { QMessageBox::information(this, "MITK", QString( s.c_str() ), QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); } void QmitkToolSelectionBox::SetDisplayedToolGroups(const std::string& toolGroups) { if (m_DisplayedGroups != toolGroups) { QString q_DisplayedGroups = toolGroups.c_str(); // quote all unquoted single words q_DisplayedGroups = q_DisplayedGroups.replace( QRegExp("\\b(\\w+)\\b|'([^']+)'"), "'\\1\\2'" ); MITK_DEBUG << "m_DisplayedGroups was \"" << toolGroups << "\""; m_DisplayedGroups = q_DisplayedGroups.toLocal8Bit().constData(); MITK_DEBUG << "m_DisplayedGroups is \"" << m_DisplayedGroups << "\""; RecreateButtons(); SetOrUnsetButtonForActiveTool(); } } void QmitkToolSelectionBox::SetLayoutColumns(int columns) { if (columns > 0 && columns != m_LayoutColumns) { m_LayoutColumns = columns; RecreateButtons(); } } void QmitkToolSelectionBox::SetShowNames(bool show) { if (show != m_ShowNames) { m_ShowNames = show; RecreateButtons(); } } void QmitkToolSelectionBox::SetGenerateAccelerators(bool accel) { if (accel != m_GenerateAccelerators) { m_GenerateAccelerators = accel; RecreateButtons(); } } void QmitkToolSelectionBox::SetToolGUIArea( QWidget* parentWidget ) { m_ToolGUIWidget = parentWidget; } void QmitkToolSelectionBox::setTitle( const QString& /*title*/ ) { } void QmitkToolSelectionBox::showEvent( QShowEvent* e ) { QWidget::showEvent(e); SetGUIEnabledAccordingToToolManagerState(); } void QmitkToolSelectionBox::hideEvent( QHideEvent* e ) { QWidget::hideEvent(e); SetGUIEnabledAccordingToToolManagerState(); } diff --git a/Modules/SegmentationUI/Qmitk/QmitkToolSelectionBox.h b/Modules/SegmentationUI/Qmitk/QmitkToolSelectionBox.h index 7bb0523dfd..94c7feb153 100755 --- a/Modules/SegmentationUI/Qmitk/QmitkToolSelectionBox.h +++ b/Modules/SegmentationUI/Qmitk/QmitkToolSelectionBox.h @@ -1,145 +1,146 @@ /*=================================================================== 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 QmitkToolSelectionBox_h_Included #define QmitkToolSelectionBox_h_Included #include "QmitkToolGUIArea.h" #include #include "mitkToolManager.h" #include #include #include #include class QmitkToolGUI; /** \brief Display the tool selection state of a mitk::ToolManager \sa mitk::ToolManager \ingroup org_mitk_gui_qt_interactivesegmentation \ingroup ToolManagerEtAl There is a separate page describing the general design of QmitkInteractiveSegmentation: \ref QmitkInteractiveSegmentationTechnicalPage This widget graphically displays the active tool of a mitk::ToolManager as a set of toggle buttons. Each button show the identification of a Tool (icon and name). When a button's toggle state is "down", the tool is activated. When a different button is clicked, the active tool is switched. When you click an already active button, the associated tool is deactivated with no replacement, which means that no tool is active then. When this widget is enabled/disabled it (normally) also enables/disables the tools. There could be cases where two QmitkToolSelectionBox widgets are associated to the same ToolManager, but if this happens, please look deeply into the code. Last contributor: $Author: maleike $ */ class MitkSegmentationUI_EXPORT QmitkToolSelectionBox : public QWidget //! { Q_OBJECT public: enum EnabledMode { EnabledWithReferenceAndWorkingDataVisible, EnabledWithReferenceData, EnabledWithWorkingData, AlwaysEnabled }; QmitkToolSelectionBox(QWidget* parent = 0, mitk::DataStorage* storage = 0); virtual ~QmitkToolSelectionBox(); mitk::ToolManager* GetToolManager(); void SetToolManager(mitk::ToolManager&); // no NULL pointer allowed here, a manager is required void setTitle( const QString& title ); /** You may specify a list of tool "groups" that should be displayed in this widget. Every Tool can report its group as a string. This method will try to find the tool's group inside the supplied string \param toolGroups. If there is a match, the tool is displayed. Effectively, you can provide a human readable list like "default, lymphnodevolumetry, oldERISstuff". */ void SetDisplayedToolGroups(const std::string& toolGroups = 0); void OnToolManagerToolModified(); void OnToolManagerReferenceDataModified(); void OnToolManagerWorkingDataModified(); void OnToolGUIProcessEventsMessage(); void OnToolErrorMessage(std::string s); void OnGeneralToolMessage(std::string s); + void RecreateButtons(); + signals: /// Whenever a tool is activated. id is the index of the active tool. Counting starts at 0, -1 indicates "no tool selected" /// This signal is also emitted, when the whole QmitkToolSelectionBox get disabled. Then it will claim ToolSelected(-1) /// When it is enabled again, there will be another ToolSelected event with the tool that is currently selected void ToolSelected(int id); public slots: virtual void setEnabled( bool ); virtual void SetEnabledMode(EnabledMode mode); virtual void SetLayoutColumns(int); virtual void SetShowNames(bool); virtual void SetGenerateAccelerators(bool); virtual void SetToolGUIArea( QWidget* parentWidget ); protected slots: void toolButtonClicked(int id); void SetGUIEnabledAccordingToToolManagerState(); protected: void showEvent( QShowEvent* ); void hideEvent( QHideEvent* ); - void RecreateButtons(); void SetOrUnsetButtonForActiveTool(); mitk::ToolManager::Pointer m_ToolManager; bool m_SelfCall; std::string m_DisplayedGroups; /// stores relationship between button IDs of the Qt widget and tool IDs of ToolManager std::map m_ButtonIDForToolID; /// stores relationship between button IDs of the Qt widget and tool IDs of ToolManager std::map m_ToolIDForButtonID; int m_LayoutColumns; bool m_ShowNames; bool m_GenerateAccelerators; QWidget* m_ToolGUIWidget; QmitkToolGUI* m_LastToolGUI; // store buttons in this group QButtonGroup* m_ToolButtonGroup; QGridLayout* m_ButtonLayout; EnabledMode m_EnabledMode; }; #endif diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp index dba802a07f..3f8a5f78ff 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp @@ -1,1234 +1,1240 @@ /*=================================================================== 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 #include "mitkProperties.h" #include "mitkSegTool2D.h" #include "mitkStatusBar.h" #include "QmitkStdMultiWidget.h" #include "QmitkNewSegmentationDialog.h" #include #include #include "QmitkSegmentationView.h" #include "QmitkSegmentationOrganNamesHandling.cpp" #include #include "mitkVtkResliceInterpolationProperty.h" #include "mitkApplicationCursor.h" #include "mitkSegmentationObjectFactory.h" #include "mitkPluginActivator.h" #include "usModuleResource.h" #include "usModuleResourceStream.h" //micro service to get the ToolManager instance #include "mitkToolManagerProvider.h" const std::string QmitkSegmentationView::VIEW_ID = "org.mitk.views.segmentation"; // public methods QmitkSegmentationView::QmitkSegmentationView() :m_Parent(NULL) ,m_Controls(NULL) ,m_MultiWidget(NULL) ,m_DataSelectionChanged(false) ,m_MouseCursorSet(false) { mitk::NodePredicateDataType::Pointer isDwi = mitk::NodePredicateDataType::New("DiffusionImage"); mitk::NodePredicateDataType::Pointer isDti = mitk::NodePredicateDataType::New("TensorImage"); mitk::NodePredicateDataType::Pointer isQbi = mitk::NodePredicateDataType::New("QBallImage"); mitk::NodePredicateOr::Pointer isDiffusionImage = mitk::NodePredicateOr::New(isDwi, isDti); isDiffusionImage = mitk::NodePredicateOr::New(isDiffusionImage, isQbi); m_IsOfTypeImagePredicate = mitk::NodePredicateOr::New(isDiffusionImage, mitk::TNodePredicateDataType::New()); m_IsBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); m_IsNotBinaryPredicate = mitk::NodePredicateNot::New( m_IsBinaryPredicate ); m_IsNotABinaryImagePredicate = mitk::NodePredicateAnd::New( m_IsOfTypeImagePredicate, m_IsNotBinaryPredicate ); m_IsABinaryImagePredicate = mitk::NodePredicateAnd::New( m_IsOfTypeImagePredicate, m_IsBinaryPredicate); } QmitkSegmentationView::~QmitkSegmentationView() { delete m_Controls; } void QmitkSegmentationView::NewNodesGenerated() { MITK_WARN<<"Use of deprecated function: NewNodesGenerated!! This function is empty and will be removed in the next time!"; } void QmitkSegmentationView::NewNodeObjectsGenerated(mitk::ToolManager::DataVectorType* nodes) { if (!nodes) return; mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); if (!toolManager) return; for (mitk::ToolManager::DataVectorType::iterator iter = nodes->begin(); iter != nodes->end(); ++iter) { this->FireNodeSelected( *iter ); // only last iteration meaningful, multiple generated objects are not taken into account here } } void QmitkSegmentationView::Visible() { if (m_DataSelectionChanged) { this->OnSelectionChanged(this->GetDataManagerSelection()); } } void QmitkSegmentationView::Activated() { // should be moved to ::BecomesVisible() or similar if( m_Controls ) { m_Controls->m_ManualToolSelectionBox2D->setEnabled( true ); m_Controls->m_ManualToolSelectionBox3D->setEnabled( true ); // m_Controls->m_OrganToolSelectionBox->setEnabled( true ); // m_Controls->m_LesionToolSelectionBox->setEnabled( true ); // m_Controls->m_SlicesInterpolator->Enable3DInterpolation( m_Controls->widgetStack->currentWidget() == m_Controls->pageManual ); mitk::DataStorage::SetOfObjects::ConstPointer segmentations = this->GetDefaultDataStorage()->GetSubset( m_IsABinaryImagePredicate ); mitk::DataStorage::SetOfObjects::ConstPointer image = this->GetDefaultDataStorage()->GetSubset( m_IsNotABinaryImagePredicate ); if (!image->empty()) { OnSelectionChanged(*image->begin()); } for ( mitk::DataStorage::SetOfObjects::const_iterator iter = segmentations->begin(); iter != segmentations->end(); ++iter) { mitk::DataNode* node = *iter; itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::OnWorkingNodeVisibilityChanged); m_WorkingDataObserverTags.insert( std::pair( node, node->GetProperty("visible")->AddObserver( itk::ModifiedEvent(), command ) ) ); itk::SimpleMemberCommand::Pointer command2 = itk::SimpleMemberCommand::New(); command2->SetCallbackFunction(this, &QmitkSegmentationView::OnBinaryPropertyChanged); m_BinaryPropertyObserverTags.insert( std::pair( node, node->GetProperty("binary")->AddObserver( itk::ModifiedEvent(), command2 ) ) ); } } itk::SimpleMemberCommand::Pointer command3 = itk::SimpleMemberCommand::New(); command3->SetCallbackFunction( this, &QmitkSegmentationView::RenderingManagerReinitialized ); m_RenderingManagerObserverTag = mitk::RenderingManager::GetInstance()->AddObserver( mitk::RenderingManagerViewsInitializedEvent(), command3 ); this->SetToolManagerSelection(m_Controls->patImageSelector->GetSelectedNode(), m_Controls->segImageSelector->GetSelectedNode()); } void QmitkSegmentationView::Deactivated() { if( m_Controls ) { this->SetToolSelectionBoxesEnabled( false ); //deactivate all tools mitk::ToolManagerProvider::GetInstance()->GetToolManager()->ActivateTool(-1); //Removing all observers for ( NodeTagMapType::iterator dataIter = m_WorkingDataObserverTags.begin(); dataIter != m_WorkingDataObserverTags.end(); ++dataIter ) { (*dataIter).first->GetProperty("visible")->RemoveObserver( (*dataIter).second ); } m_WorkingDataObserverTags.clear(); for ( NodeTagMapType::iterator dataIter = m_BinaryPropertyObserverTags.begin(); dataIter != m_BinaryPropertyObserverTags.end(); ++dataIter ) { (*dataIter).first->GetProperty("binary")->RemoveObserver( (*dataIter).second ); } m_BinaryPropertyObserverTags.clear(); mitk::RenderingManager::GetInstance()->RemoveObserver(m_RenderingManagerObserverTag); ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); service->RemoveAllPlanePositions(); context->ungetService(ppmRef); this->SetToolManagerSelection(0,0); } } void QmitkSegmentationView::StdMultiWidgetAvailable( QmitkStdMultiWidget& stdMultiWidget ) { SetMultiWidget(&stdMultiWidget); } void QmitkSegmentationView::StdMultiWidgetNotAvailable() { SetMultiWidget(NULL); } void QmitkSegmentationView::StdMultiWidgetClosed( QmitkStdMultiWidget& /*stdMultiWidget*/ ) { SetMultiWidget(NULL); } void QmitkSegmentationView::SetMultiWidget(QmitkStdMultiWidget* multiWidget) { // save the current multiwidget as the working widget m_MultiWidget = multiWidget; if (m_Parent) { m_Parent->setEnabled(m_MultiWidget); } // tell the interpolation about toolmanager and multiwidget (and data storage) if (m_Controls && m_MultiWidget) { mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); m_Controls->m_SlicesInterpolator->SetDataStorage( this->GetDefaultDataStorage()); QList controllers; controllers.push_back(m_MultiWidget->GetRenderWindow1()->GetSliceNavigationController()); controllers.push_back(m_MultiWidget->GetRenderWindow2()->GetSliceNavigationController()); controllers.push_back(m_MultiWidget->GetRenderWindow3()->GetSliceNavigationController()); m_Controls->m_SlicesInterpolator->Initialize( toolManager, controllers ); } } void QmitkSegmentationView::OnPreferencesChanged(const berry::IBerryPreferences* prefs) { if (m_Controls != NULL) { bool slimView = prefs->GetBool("slim view", false); m_Controls->m_ManualToolSelectionBox2D->SetShowNames(!slimView); m_Controls->m_ManualToolSelectionBox3D->SetShowNames(!slimView); } m_AutoSelectionEnabled = prefs->GetBool("auto selection", false); this->ForceDisplayPreferencesUponAllImages(); } void QmitkSegmentationView::CreateNewSegmentation() { mitk::DataNode::Pointer node = mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetReferenceData(0); if (node.IsNotNull()) { mitk::Image::Pointer image = dynamic_cast( node->GetData() ); if (image.IsNotNull()) { if (image->GetDimension()>1) { // ask about the name and organ type of the new segmentation QmitkNewSegmentationDialog* dialog = new QmitkNewSegmentationDialog( m_Parent ); // needs a QWidget as parent, "this" is not QWidget QString storedList = QString::fromStdString( this->GetPreferences()->GetByteArray("Organ-Color-List","") ); QStringList organColors; if (storedList.isEmpty()) { organColors = GetDefaultOrganColorString(); } else { /* a couple of examples of how organ names are stored: a simple item is built up like 'name#AABBCC' where #AABBCC is the hexadecimal notation of a color as known from HTML items are stored separated by ';' this makes it necessary to escape occurrences of ';' in name. otherwise the string "hugo;ypsilon#AABBCC;eugen#AABBCC" could not be parsed as two organs but we would get "hugo" and "ypsilon#AABBCC" and "eugen#AABBCC" so the organ name "hugo;ypsilon" is stored as "hugo\;ypsilon" and must be unescaped after loading the following lines could be one split with Perl's negative lookbehind */ // recover string list from BlueBerry view's preferences QString storedString = QString::fromStdString( this->GetPreferences()->GetByteArray("Organ-Color-List","") ); MITK_DEBUG << "storedString: " << storedString.toStdString(); // match a string consisting of any number of repetitions of either "anything but ;" or "\;". This matches everything until the next unescaped ';' QRegExp onePart("(?:[^;]|\\\\;)*"); MITK_DEBUG << "matching " << onePart.pattern().toStdString(); int count = 0; int pos = 0; while( (pos = onePart.indexIn( storedString, pos )) != -1 ) { ++count; int length = onePart.matchedLength(); if (length == 0) break; QString matchedString = storedString.mid(pos, length); MITK_DEBUG << " Captured length " << length << ": " << matchedString.toStdString(); pos += length + 1; // skip separating ';' // unescape possible occurrences of '\;' in the string matchedString.replace("\\;", ";"); // add matched string part to output list organColors << matchedString; } MITK_DEBUG << "Captured " << count << " organ name/colors"; } dialog->SetSuggestionList( organColors ); int dialogReturnValue = dialog->exec(); if ( dialogReturnValue == QDialog::Rejected ) return; // user clicked cancel or pressed Esc or something similar // ask the user about an organ type and name, add this information to the image's (!) propertylist // create a new image of the same dimensions and smallest possible pixel type mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); mitk::Tool* firstTool = toolManager->GetToolById(0); if (firstTool) { try { std::string newNodeName = dialog->GetSegmentationName().toStdString(); if(newNodeName.empty()) newNodeName = "no_name"; mitk::DataNode::Pointer emptySegmentation = firstTool->CreateEmptySegmentationNode( image, newNodeName, dialog->GetColor() ); // initialize showVolume to false to prevent recalculating the volume while working on the segmentation emptySegmentation->SetProperty( "showVolume", mitk::BoolProperty::New( false ) ); if (!emptySegmentation) return; // could be aborted by user UpdateOrganList( organColors, dialog->GetSegmentationName(), dialog->GetColor() ); /* escape ';' here (replace by '\;'), see longer comment above */ std::string stringForStorage = organColors.replaceInStrings(";","\\;").join(";").toStdString(); MITK_DEBUG << "Will store: " << stringForStorage; this->GetPreferences()->PutByteArray("Organ-Color-List", stringForStorage ); this->GetPreferences()->Flush(); if(mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetWorkingData(0)) { mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetWorkingData(0)->SetSelected(false); } emptySegmentation->SetSelected(true); this->GetDefaultDataStorage()->Add( emptySegmentation, node ); // add as a child, because the segmentation "derives" from the original this->ApplyDisplayOptions( emptySegmentation ); this->FireNodeSelected( emptySegmentation ); this->OnSelectionChanged( emptySegmentation ); m_Controls->segImageSelector->SetSelectedNode(emptySegmentation); } catch (std::bad_alloc) { QMessageBox::warning(NULL,"Create new segmentation","Could not allocate memory for new segmentation"); } } } else { QMessageBox::information(NULL,"Segmentation","Segmentation is currently not supported for 2D images"); } } } else { MITK_ERROR << "'Create new segmentation' button should never be clickable unless a patient image is selected..."; } } void QmitkSegmentationView::OnWorkingNodeVisibilityChanged() { mitk::DataNode* selectedNode = m_Controls->segImageSelector->GetSelectedNode(); bool selectedNodeIsVisible = selectedNode->IsVisible(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1"))); if (!selectedNodeIsVisible) { this->SetToolSelectionBoxesEnabled(false); this->UpdateWarningLabel("The selected segmentation is currently not visible!"); } else { this->SetToolSelectionBoxesEnabled(true); this->UpdateWarningLabel(""); } } void QmitkSegmentationView::OnBinaryPropertyChanged() { mitk::DataStorage::SetOfObjects::ConstPointer patImages = m_Controls->patImageSelector->GetNodes(); bool isBinary(false); for (mitk::DataStorage::SetOfObjects::ConstIterator it = patImages->Begin(); it != patImages->End(); ++it) { const mitk::DataNode* node = it->Value(); node->GetBoolProperty("binary", isBinary); if(isBinary) { m_Controls->patImageSelector->RemoveNode(node); m_Controls->segImageSelector->AddNode(node); this->SetToolManagerSelection(NULL,NULL); return; } } mitk::DataStorage::SetOfObjects::ConstPointer segImages = m_Controls->segImageSelector->GetNodes(); isBinary = true; for (mitk::DataStorage::SetOfObjects::ConstIterator it = segImages->Begin(); it != segImages->End(); ++it) { const mitk::DataNode* node = it->Value(); node->GetBoolProperty("binary", isBinary); if(!isBinary) { m_Controls->segImageSelector->RemoveNode(node); m_Controls->patImageSelector->AddNode(node); if (mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetWorkingData(0) == node) mitk::ToolManagerProvider::GetInstance()->GetToolManager()->SetWorkingData(NULL); return; } } } void QmitkSegmentationView::NodeAdded(const mitk::DataNode *node) { bool isBinary (false); bool isHelperObject (false); node->GetBoolProperty("binary", isBinary); node->GetBoolProperty("helper object", isHelperObject); if (m_AutoSelectionEnabled) { if (!isBinary && dynamic_cast(node->GetData())) { FireNodeSelected(const_cast(node)); } } if (isBinary && !isHelperObject) { itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::OnWorkingNodeVisibilityChanged); m_WorkingDataObserverTags.insert( std::pair( const_cast(node), node->GetProperty("visible")->AddObserver( itk::ModifiedEvent(), command ) ) ); itk::SimpleMemberCommand::Pointer command2 = itk::SimpleMemberCommand::New(); command2->SetCallbackFunction(this, &QmitkSegmentationView::OnBinaryPropertyChanged); m_BinaryPropertyObserverTags.insert( std::pair( const_cast(node), node->GetProperty("binary")->AddObserver( itk::ModifiedEvent(), command2 ) ) ); this->ApplyDisplayOptions( const_cast(node) ); m_Controls->segImageSelector->setCurrentIndex( m_Controls->segImageSelector->Find(node) ); } } void QmitkSegmentationView::NodeRemoved(const mitk::DataNode* node) { bool isSeg(false); bool isHelperObject(false); node->GetBoolProperty("helper object", isHelperObject); node->GetBoolProperty("binary", isSeg); mitk::Image* image = dynamic_cast(node->GetData()); if(isSeg && !isHelperObject && image) { //First of all remove all possible contour markers of the segmentation mitk::DataStorage::SetOfObjects::ConstPointer allContourMarkers = this->GetDataStorage()->GetDerivations(node, mitk::NodePredicateProperty::New("isContourMarker" , mitk::BoolProperty::New(true))); ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); for (mitk::DataStorage::SetOfObjects::ConstIterator it = allContourMarkers->Begin(); it != allContourMarkers->End(); ++it) { std::string nodeName = node->GetName(); unsigned int t = nodeName.find_last_of(" "); unsigned int id = atof(nodeName.substr(t+1).c_str())-1; service->RemovePlanePosition(id); this->GetDataStorage()->Remove(it->Value()); } context->ungetService(ppmRef); service = NULL; if ((mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetWorkingData(0) == node) && m_Controls->patImageSelector->GetSelectedNode().IsNotNull()) { this->SetToolManagerSelection(mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetReferenceData(0), NULL); this->UpdateWarningLabel("Select or create a segmentation"); } mitk::SurfaceInterpolationController::GetInstance()->RemoveSegmentationFromContourList(image); } mitk::DataNode* tempNode = const_cast(node); //Since the binary property could be changed during runtime by the user if (image && !isHelperObject) { node->GetProperty("visible")->RemoveObserver( m_WorkingDataObserverTags[tempNode] ); m_WorkingDataObserverTags.erase(tempNode); node->GetProperty("binary")->RemoveObserver( m_BinaryPropertyObserverTags[tempNode] ); m_BinaryPropertyObserverTags.erase(tempNode); } if((mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetReferenceData(0) == node)) { //as we don't know which node was actually removed e.g. our reference node, disable 'New Segmentation' button. //consider the case that there is no more image in the datastorage this->SetToolManagerSelection(NULL, NULL); this->SetToolSelectionBoxesEnabled( false ); } } //void QmitkSegmentationView::CreateSegmentationFromSurface() //{ // mitk::DataNode::Pointer surfaceNode = // m_Controls->MaskSurfaces->GetSelectedNode(); // mitk::Surface::Pointer surface(0); // if(surfaceNode.IsNotNull()) // surface = dynamic_cast ( surfaceNode->GetData() ); // if(surface.IsNull()) // { // this->HandleException( "No surface selected.", m_Parent, true); // return; // } // mitk::DataNode::Pointer imageNode // = mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetReferenceData(0); // mitk::Image::Pointer image(0); // if (imageNode.IsNotNull()) // image = dynamic_cast( imageNode->GetData() ); // if(image.IsNull()) // { // this->HandleException( "No image selected.", m_Parent, true); // return; // } // mitk::SurfaceToImageFilter::Pointer s2iFilter // = mitk::SurfaceToImageFilter::New(); // s2iFilter->MakeOutputBinaryOn(); // s2iFilter->SetInput(surface); // s2iFilter->SetImage(image); // s2iFilter->Update(); // mitk::DataNode::Pointer resultNode = mitk::DataNode::New(); // std::string nameOfResultImage = imageNode->GetName(); // nameOfResultImage.append(surfaceNode->GetName()); // resultNode->SetProperty("name", mitk::StringProperty::New(nameOfResultImage) ); // resultNode->SetProperty("binary", mitk::BoolProperty::New(true) ); // resultNode->SetData( s2iFilter->GetOutput() ); // this->GetDataStorage()->Add(resultNode, imageNode); //} //void QmitkSegmentationView::ToolboxStackPageChanged(int id) //{ // // interpolation only with manual tools visible // m_Controls->m_SlicesInterpolator->EnableInterpolation( id == 0 ); // if( id == 0 ) // { // mitk::DataNode::Pointer workingData = mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetWorkingData(0); // if( workingData.IsNotNull() ) // { // m_Controls->segImageSelector->setCurrentIndex( m_Controls->segImageSelector->Find(workingData) ); // } // } // // this is just a workaround, should be removed when all tools support 3D+t // if (id==2) // lesions // { // mitk::DataNode::Pointer node = mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetReferenceData(0); // if (node.IsNotNull()) // { // mitk::Image::Pointer image = dynamic_cast( node->GetData() ); // if (image.IsNotNull()) // { // if (image->GetDimension()>3) // { // m_Controls->widgetStack->setCurrentIndex(0); // QMessageBox::information(NULL,"Segmentation","Lesion segmentation is currently not supported for 4D images"); // } // } // } // } //} // protected void QmitkSegmentationView::OnPatientComboBoxSelectionChanged( const mitk::DataNode* node ) { //mitk::DataNode* selectedNode = const_cast(node); if( node != NULL ) { this->UpdateWarningLabel(""); mitk::DataNode* segNode = m_Controls->segImageSelector->GetSelectedNode(); if (segNode) { mitk::DataStorage::SetOfObjects::ConstPointer possibleParents = this->GetDefaultDataStorage()->GetSources( segNode, m_IsNotABinaryImagePredicate ); bool isSourceNode(false); for (mitk::DataStorage::SetOfObjects::ConstIterator it = possibleParents->Begin(); it != possibleParents->End(); it++) { if (it.Value() == node) isSourceNode = true; } if ( !isSourceNode && (!this->CheckForSameGeometry(segNode, node) || possibleParents->Size() > 0 )) { this->SetToolManagerSelection(node, NULL); this->SetToolSelectionBoxesEnabled( false ); this->UpdateWarningLabel("The selected patient image does not match with the selected segmentation!"); } else if ((!isSourceNode && this->CheckForSameGeometry(segNode, node)) || isSourceNode ) { this->SetToolManagerSelection(node, segNode); //Doing this we can assure that the segmenation is always visible if the segmentation and the patient image are //loaded separately int layer(10); node->GetIntProperty("layer", layer); layer++; segNode->SetProperty("layer", mitk::IntProperty::New(layer)); //this->UpdateWarningLabel(""); RenderingManagerReinitialized(); } } else { this->SetToolManagerSelection(node, NULL); this->SetToolSelectionBoxesEnabled( false ); this->UpdateWarningLabel("Select or create a segmentation"); } } else { this->UpdateWarningLabel("Please load an image!"); this->SetToolSelectionBoxesEnabled( false ); } } void QmitkSegmentationView::OnSegmentationComboBoxSelectionChanged(const mitk::DataNode *node) { if (node == NULL) { this->UpdateWarningLabel("Select or create a segmentation"); this->SetToolSelectionBoxesEnabled( false ); return; } mitk::DataNode* refNode = m_Controls->patImageSelector->GetSelectedNode(); RenderingManagerReinitialized(); if ( m_Controls->lblSegmentationWarnings->isVisible()) // "RenderingManagerReinitialized()" caused a warning. we do not need to go any further return; if (m_AutoSelectionEnabled) { this->OnSelectionChanged(const_cast(node)); } else { mitk::DataStorage::SetOfObjects::ConstPointer possibleParents = this->GetDefaultDataStorage()->GetSources( node, m_IsNotABinaryImagePredicate ); if ( possibleParents->Size() == 1 ) { mitk::DataNode* parentNode = possibleParents->ElementAt(0); if (parentNode != refNode) { this->UpdateWarningLabel("The selected segmentation does not match with the selected patient image!"); this->SetToolSelectionBoxesEnabled( false ); this->SetToolManagerSelection(NULL, node); } else { this->UpdateWarningLabel(""); this->SetToolManagerSelection(refNode, node); } } else if (refNode && this->CheckForSameGeometry(node, refNode)) { this->UpdateWarningLabel(""); this->SetToolManagerSelection(refNode, node); } else if (!refNode || !this->CheckForSameGeometry(node, refNode)) { this->UpdateWarningLabel("Please select or load the according patient image!"); } } if (!node->IsVisible(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1")))) { this->UpdateWarningLabel("The selected segmentation is currently not visible!"); this->SetToolSelectionBoxesEnabled( false ); } } void QmitkSegmentationView::OnShowMarkerNodes (bool state) { mitk::SegTool2D::Pointer manualSegmentationTool; unsigned int numberOfExistingTools = mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetTools().size(); for(unsigned int i = 0; i < numberOfExistingTools; i++) { manualSegmentationTool = dynamic_cast(mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetToolById(i)); if (manualSegmentationTool) { if(state == true) { manualSegmentationTool->SetShowMarkerNodes( true ); } else { manualSegmentationTool->SetShowMarkerNodes( false ); } } } } void QmitkSegmentationView::OnSelectionChanged(mitk::DataNode* node) { std::vector nodes; nodes.push_back( node ); this->OnSelectionChanged( nodes ); } void QmitkSegmentationView::OnSelectionChanged(std::vector nodes) { if (nodes.size() != 0) { std::string markerName = "Position"; unsigned int numberOfNodes = nodes.size(); std::string nodeName = nodes.at( 0 )->GetName(); if ( ( numberOfNodes == 1 ) && ( nodeName.find( markerName ) == 0) ) { this->OnContourMarkerSelected( nodes.at( 0 ) ); return; } } if (m_AutoSelectionEnabled && this->IsActivated()) { if (nodes.size() == 0 && m_Controls->patImageSelector->GetSelectedNode().IsNull()) { SetToolManagerSelection(NULL,NULL); } else if (nodes.size() == 1) { mitk::DataNode::Pointer selectedNode = nodes.at(0); if(selectedNode.IsNull()) { return; } mitk::Image::Pointer selectedImage = dynamic_cast(selectedNode->GetData()); if (selectedImage.IsNull()) { SetToolManagerSelection(NULL,NULL); return; } else { bool isASegmentation(false); selectedNode->GetBoolProperty("binary", isASegmentation); if (isASegmentation) { //If a segmentation is selected find a possible reference image: mitk::DataStorage::SetOfObjects::ConstPointer sources = this->GetDataStorage()->GetSources(selectedNode, m_IsNotABinaryImagePredicate); mitk::DataNode::Pointer refNode; if (sources->Size() != 0) { refNode = sources->ElementAt(0); refNode->SetVisibility(true); selectedNode->SetVisibility(true); SetToolManagerSelection(refNode,selectedNode); mitk::DataStorage::SetOfObjects::ConstPointer otherSegmentations = this->GetDataStorage()->GetSubset(m_IsABinaryImagePredicate); for(mitk::DataStorage::SetOfObjects::const_iterator iter = otherSegmentations->begin(); iter != otherSegmentations->end(); ++iter) { mitk::DataNode* node = *iter; if (dynamic_cast(node->GetData()) != selectedImage.GetPointer()) node->SetVisibility(false); } mitk::DataStorage::SetOfObjects::ConstPointer otherPatientImages = this->GetDataStorage()->GetSubset(m_IsNotABinaryImagePredicate); for(mitk::DataStorage::SetOfObjects::const_iterator iter = otherPatientImages->begin(); iter != otherPatientImages->end(); ++iter) { mitk::DataNode* node = *iter; if (dynamic_cast(node->GetData()) != dynamic_cast(refNode->GetData())) node->SetVisibility(false); } } else { mitk::DataStorage::SetOfObjects::ConstPointer possiblePatientImages = this->GetDataStorage()->GetSubset(m_IsNotABinaryImagePredicate); for (mitk::DataStorage::SetOfObjects::ConstIterator it = possiblePatientImages->Begin(); it != possiblePatientImages->End(); it++) { refNode = it->Value(); if (this->CheckForSameGeometry(selectedNode, it->Value())) { refNode->SetVisibility(true); selectedNode->SetVisibility(true); mitk::DataStorage::SetOfObjects::ConstPointer otherSegmentations = this->GetDataStorage()->GetSubset(m_IsABinaryImagePredicate); for(mitk::DataStorage::SetOfObjects::const_iterator iter = otherSegmentations->begin(); iter != otherSegmentations->end(); ++iter) { mitk::DataNode* node = *iter; if (dynamic_cast(node->GetData()) != selectedImage.GetPointer()) node->SetVisibility(false); } mitk::DataStorage::SetOfObjects::ConstPointer otherPatientImages = this->GetDataStorage()->GetSubset(m_IsNotABinaryImagePredicate); for(mitk::DataStorage::SetOfObjects::const_iterator iter = otherPatientImages->begin(); iter != otherPatientImages->end(); ++iter) { mitk::DataNode* node = *iter; if (dynamic_cast(node->GetData()) != dynamic_cast(refNode->GetData())) node->SetVisibility(false); } this->SetToolManagerSelection(refNode, selectedNode); //Doing this we can assure that the segmenation is always visible if the segmentation and the patient image are at the //same level in the datamanager int layer(10); refNode->GetIntProperty("layer", layer); layer++; selectedNode->SetProperty("layer", mitk::IntProperty::New(layer)); return; } } this->SetToolManagerSelection(NULL, selectedNode); } } else { if (mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetReferenceData(0) != selectedNode) { SetToolManagerSelection(selectedNode, NULL); //May be a bug in the selection services. A node which is deselected will be passed as selected node to the OnSelectionChanged function if (!selectedNode->IsVisible(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1")))) selectedNode->SetVisibility(true); this->UpdateWarningLabel("The selected patient image does not\nmatchwith the selected segmentation!"); this->SetToolSelectionBoxesEnabled( false ); } } } } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); if ( m_Controls->lblSegmentationWarnings->isVisible()) // "RenderingManagerReinitialized()" caused a warning. we do not need to go any further return; RenderingManagerReinitialized(); } } void QmitkSegmentationView::OnContourMarkerSelected(const mitk::DataNode *node) { QmitkRenderWindow* selectedRenderWindow = 0; QmitkRenderWindow* RenderWindow1 = this->GetActiveStdMultiWidget()->GetRenderWindow1(); QmitkRenderWindow* RenderWindow2 = this->GetActiveStdMultiWidget()->GetRenderWindow2(); QmitkRenderWindow* RenderWindow3 = this->GetActiveStdMultiWidget()->GetRenderWindow3(); QmitkRenderWindow* RenderWindow4 = this->GetActiveStdMultiWidget()->GetRenderWindow4(); bool PlanarFigureInitializedWindow = false; // find initialized renderwindow if (node->GetBoolProperty("PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, RenderWindow1->GetRenderer())) { selectedRenderWindow = RenderWindow1; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, RenderWindow2->GetRenderer())) { selectedRenderWindow = RenderWindow2; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, RenderWindow3->GetRenderer())) { selectedRenderWindow = RenderWindow3; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, RenderWindow4->GetRenderer())) { selectedRenderWindow = RenderWindow4; } // make node visible if (selectedRenderWindow) { std::string nodeName = node->GetName(); unsigned int t = nodeName.find_last_of(" "); unsigned int id = atof(nodeName.substr(t+1).c_str())-1; { ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); selectedRenderWindow->GetSliceNavigationController()->ExecuteOperation(service->GetPlanePosition(id)); context->ungetService(ppmRef); } selectedRenderWindow->GetRenderer()->GetDisplayGeometry()->Fit(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkSegmentationView::OnTabWidgetChanged(int id) { //always disable tools on tab changed mitk::ToolManagerProvider::GetInstance()->GetToolManager()->ActivateTool(-1); //2D Tab ID = 0 //3D Tab ID = 1 if (id == 0) { //Hide 3D selection box, show 2D selection box m_Controls->m_ManualToolSelectionBox3D->hide(); m_Controls->m_ManualToolSelectionBox2D->show(); //Deactivate possible active tool //TODO Remove possible visible interpolations -> Maybe changes in SlicesInterpolator } else { //Hide 3D selection box, show 2D selection box m_Controls->m_ManualToolSelectionBox2D->hide(); m_Controls->m_ManualToolSelectionBox3D->show(); //Deactivate possible active tool } } void QmitkSegmentationView::SetToolManagerSelection(const mitk::DataNode* referenceData, const mitk::DataNode* workingData) { // called as a result of new BlueBerry selections // tells the ToolManager for manual segmentation about new selections // updates GUI information about what the user should select mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); toolManager->SetReferenceData(const_cast(referenceData)); toolManager->SetWorkingData( const_cast(workingData)); // check original image m_Controls->btnNewSegmentation->setEnabled(referenceData != NULL); if (referenceData) { this->UpdateWarningLabel(""); disconnect( m_Controls->patImageSelector, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnPatientComboBoxSelectionChanged( const mitk::DataNode* ) ) ); m_Controls->patImageSelector->setCurrentIndex( m_Controls->patImageSelector->Find(referenceData) ); connect( m_Controls->patImageSelector, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnPatientComboBoxSelectionChanged( const mitk::DataNode* ) ) ); } // check segmentation if (referenceData) { if (workingData) { this->FireNodeSelected(const_cast(workingData)); // if( m_Controls->widgetStack->currentIndex() == 0 ) // { disconnect( m_Controls->segImageSelector, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnSegmentationComboBoxSelectionChanged( const mitk::DataNode* ) ) ); m_Controls->segImageSelector->setCurrentIndex(m_Controls->segImageSelector->Find(workingData)); connect( m_Controls->segImageSelector, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnSegmentationComboBoxSelectionChanged(const mitk::DataNode*)) ); // } } } } void QmitkSegmentationView::ForceDisplayPreferencesUponAllImages() { if (!m_Parent || !m_Parent->isVisible()) return; // check all images and segmentations in DataStorage: // (items in brackets are implicitly done by previous steps) // 1. // if a reference image is selected, // show the reference image // and hide all other images (orignal and segmentation), // (and hide all segmentations of the other original images) // and show all the reference's segmentations // if no reference image is selected, do do nothing // // 2. // if a segmentation is selected, // show it // (and hide all all its siblings (childs of the same parent, incl, NULL parent)) // if no segmentation is selected, do nothing if (!m_Controls) return; // might happen on initialization (preferences loaded) mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); mitk::DataNode::Pointer referenceData = toolManager->GetReferenceData(0); mitk::DataNode::Pointer workingData = toolManager->GetWorkingData(0); // 1. if (referenceData.IsNotNull()) { // iterate all images mitk::DataStorage::SetOfObjects::ConstPointer allImages = this->GetDefaultDataStorage()->GetSubset( m_IsABinaryImagePredicate ); for ( mitk::DataStorage::SetOfObjects::const_iterator iter = allImages->begin(); iter != allImages->end(); ++iter) { mitk::DataNode* node = *iter; // apply display preferences ApplyDisplayOptions(node); // set visibility node->SetVisibility(node == referenceData); } } // 2. if (workingData.IsNotNull()) workingData->SetVisibility(true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSegmentationView::ApplyDisplayOptions(mitk::DataNode* node) { if (!node) return; bool isBinary(false); node->GetPropertyValue("binary", isBinary); if (isBinary) { node->SetProperty( "outline binary", mitk::BoolProperty::New( this->GetPreferences()->GetBool("draw outline", true)) ); node->SetProperty( "outline width", mitk::FloatProperty::New( 2.0 ) ); node->SetProperty( "opacity", mitk::FloatProperty::New( this->GetPreferences()->GetBool("draw outline", true) ? 1.0 : 0.3 ) ); node->SetProperty( "volumerendering", mitk::BoolProperty::New( this->GetPreferences()->GetBool("volume rendering", false) ) ); } } void QmitkSegmentationView::RenderingManagerReinitialized() { if ( ! m_MultiWidget ) { return; } /* * Here we check whether the geometry of the selected segmentation image if aligned with the worldgeometry * At the moment it is not supported to use a geometry different from the selected image for reslicing. * For further information see Bug 16063 */ mitk::DataNode* workingNode = m_Controls->segImageSelector->GetSelectedNode(); const mitk::BaseGeometry* worldGeo = m_MultiWidget->GetRenderWindow4()->GetSliceNavigationController()->GetCurrentGeometry3D(); if (workingNode && worldGeo) { const mitk::BaseGeometry* workingNodeGeo = workingNode->GetData()->GetGeometry(); const mitk::BaseGeometry* worldGeo = m_MultiWidget->GetRenderWindow4()->GetSliceNavigationController()->GetCurrentGeometry3D(); //if (mitk::Equal(workingNodeGeo->GetBoundingBox(), worldGeo->GetBoundingBox(), mitk::eps, true)) if (mitk::Equal(workingNodeGeo->GetCornerPoint(false,false,false), worldGeo->GetCornerPoint(false,false,false), mitk::eps) && mitk::Equal(workingNodeGeo->GetCornerPoint(true,true,true), worldGeo->GetCornerPoint(true,true,true), mitk::eps)) { this->SetToolManagerSelection(m_Controls->patImageSelector->GetSelectedNode(), workingNode); this->SetToolSelectionBoxesEnabled(true); this->UpdateWarningLabel(""); } else { this->SetToolManagerSelection(m_Controls->patImageSelector->GetSelectedNode(), NULL); this->SetToolSelectionBoxesEnabled(false); this->UpdateWarningLabel("Please perform a reinit on the segmentation image!"); } } } bool QmitkSegmentationView::CheckForSameGeometry(const mitk::DataNode *node1, const mitk::DataNode *node2) const { bool isSameGeometry(true); mitk::Image* image1 = dynamic_cast(node1->GetData()); mitk::Image* image2 = dynamic_cast(node2->GetData()); if (image1 && image2) { mitk::BaseGeometry* geo1 = image1->GetGeometry(); mitk::BaseGeometry* geo2 = image2->GetGeometry(); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetOrigin(), geo2->GetOrigin()); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetExtent(0), geo2->GetExtent(0)); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetExtent(1), geo2->GetExtent(1)); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetExtent(2), geo2->GetExtent(2)); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetSpacing(), geo2->GetSpacing()); isSameGeometry = isSameGeometry && mitk::MatrixEqualElementWise(geo1->GetIndexToWorldTransform()->GetMatrix(), geo2->GetIndexToWorldTransform()->GetMatrix()); return isSameGeometry; } else { return false; } } void QmitkSegmentationView::UpdateWarningLabel(QString text) { if (text.size() == 0) m_Controls->lblSegmentationWarnings->hide(); else m_Controls->lblSegmentationWarnings->show(); m_Controls->lblSegmentationWarnings->setText(text); } void QmitkSegmentationView::CreateQtPartControl(QWidget* parent) { // setup the basic GUI of this view m_Parent = parent; m_Controls = new Ui::QmitkSegmentationControls; m_Controls->setupUi(parent); m_Controls->patImageSelector->SetDataStorage(this->GetDefaultDataStorage()); m_Controls->patImageSelector->SetPredicate(m_IsNotABinaryImagePredicate); this->UpdateWarningLabel("Please load an image"); if( m_Controls->patImageSelector->GetSelectedNode().IsNotNull() ) this->UpdateWarningLabel("Select or create a new segmentation"); m_Controls->segImageSelector->SetDataStorage(this->GetDefaultDataStorage()); m_Controls->segImageSelector->SetPredicate(m_IsABinaryImagePredicate); if( m_Controls->segImageSelector->GetSelectedNode().IsNotNull() ) this->UpdateWarningLabel(""); mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); assert ( toolManager ); toolManager->SetDataStorage( *(this->GetDefaultDataStorage()) ); toolManager->InitializeTools(); // all part of open source MITK m_Controls->m_ManualToolSelectionBox2D->SetGenerateAccelerators(true); m_Controls->m_ManualToolSelectionBox2D->SetToolGUIArea( m_Controls->m_ManualToolGUIContainer2D ); m_Controls->m_ManualToolSelectionBox2D->SetDisplayedToolGroups("Add Subtract Correction Paint Wipe 'Region Growing' Fill Erase 'Live Wire' '2D Fast Marching'"); m_Controls->m_ManualToolSelectionBox2D->SetLayoutColumns(3); m_Controls->m_ManualToolSelectionBox2D->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible ); connect( m_Controls->m_ManualToolSelectionBox2D, SIGNAL(ToolSelected(int)), this, SLOT(OnManualTool2DSelected(int)) ); //setup 3D Tools m_Controls->m_ManualToolSelectionBox3D->SetGenerateAccelerators(true); m_Controls->m_ManualToolSelectionBox3D->SetToolGUIArea( m_Controls->m_ManualToolGUIContainer3D ); //specify tools to be added to 3D Tool area m_Controls->m_ManualToolSelectionBox3D->SetDisplayedToolGroups("Threshold 'UL Threshold' Otsu 'Fast Marching 3D' 'Region Growing 3D' Watershed Picking"); m_Controls->m_ManualToolSelectionBox3D->SetLayoutColumns(3); m_Controls->m_ManualToolSelectionBox3D->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible ); //Hide 3D selection box, show 2D selection box m_Controls->m_ManualToolSelectionBox3D->hide(); m_Controls->m_ManualToolSelectionBox2D->show(); toolManager->NewNodesGenerated += mitk::MessageDelegate( this, &QmitkSegmentationView::NewNodesGenerated ); // update the list of segmentations toolManager->NewNodeObjectsGenerated += mitk::MessageDelegate1( this, &QmitkSegmentationView::NewNodeObjectsGenerated ); // update the list of segmentations // create signal/slot connections connect( m_Controls->patImageSelector, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnPatientComboBoxSelectionChanged( const mitk::DataNode* ) ) ); connect( m_Controls->segImageSelector, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnSegmentationComboBoxSelectionChanged( const mitk::DataNode* ) ) ); connect( m_Controls->btnNewSegmentation, SIGNAL(clicked()), this, SLOT(CreateNewSegmentation()) ); // connect( m_Controls->CreateSegmentationFromSurface, SIGNAL(clicked()), this, SLOT(CreateSegmentationFromSurface()) ); // connect( m_Controls->widgetStack, SIGNAL(currentChanged(int)), this, SLOT(ToolboxStackPageChanged(int)) ); connect( m_Controls->tabWidgetSegmentationTools, SIGNAL(currentChanged(int)), this, SLOT(OnTabWidgetChanged(int))); // connect(m_Controls->MaskSurfaces, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), // this, SLOT( OnSurfaceSelectionChanged( ) ) ); connect(m_Controls->m_SlicesInterpolator, SIGNAL(SignalShowMarkerNodes(bool)), this, SLOT(OnShowMarkerNodes(bool))); // m_Controls->MaskSurfaces->SetDataStorage(this->GetDefaultDataStorage()); // m_Controls->MaskSurfaces->SetPredicate(mitk::NodePredicateDataType::New("Surface")); } void QmitkSegmentationView::OnManualTool2DSelected(int id) { if (id >= 0) { std::string text = "Active Tool: \""; mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); text += toolManager->GetToolById(id)->GetName(); text += "\""; mitk::StatusBar::GetInstance()->DisplayText(text.c_str()); us::ModuleResource resource = toolManager->GetToolById(id)->GetCursorIconResource(); this->SetMouseCursor(resource, 0, 0); } else { this->ResetMouseCursor(); mitk::StatusBar::GetInstance()->DisplayText(""); } } void QmitkSegmentationView::ResetMouseCursor() { if ( m_MouseCursorSet ) { mitk::ApplicationCursor::GetInstance()->PopCursor(); m_MouseCursorSet = false; } } void QmitkSegmentationView::SetMouseCursor( const us::ModuleResource& resource, int hotspotX, int hotspotY ) { if (!resource) return; // Remove previously set mouse cursor if ( m_MouseCursorSet ) { mitk::ApplicationCursor::GetInstance()->PopCursor(); } us::ModuleResourceStream cursor(resource, std::ios::binary); mitk::ApplicationCursor::GetInstance()->PushCursor( cursor, hotspotX, hotspotY ); m_MouseCursorSet = true; } void QmitkSegmentationView::SetToolSelectionBoxesEnabled(bool status) { - m_Controls->m_ManualToolSelectionBox2D->setEnabled(status); - m_Controls->m_ManualToolSelectionBox3D->setEnabled(status); - m_Controls->m_SlicesInterpolator->setEnabled(status); + if (status) + { + m_Controls->m_ManualToolSelectionBox2D->RecreateButtons(); + m_Controls->m_ManualToolSelectionBox3D->RecreateButtons(); + } + + m_Controls->m_ManualToolSelectionBox2D->setEnabled(status); + m_Controls->m_ManualToolSelectionBox3D->setEnabled(status); + m_Controls->m_SlicesInterpolator->setEnabled(status); } // ATTENTION some methods for handling the known list of (organ names, colors) are defined in QmitkSegmentationOrganNamesHandling.cpp