diff --git a/CMakeExternals/DCMQI.cmake b/CMakeExternals/DCMQI.cmake index dc0e078434..933a8a4f69 100644 --- a/CMakeExternals/DCMQI.cmake +++ b/CMakeExternals/DCMQI.cmake @@ -1,65 +1,65 @@ #----------------------------------------------------------------------------- # DCMQI #----------------------------------------------------------------------------- if(MITK_USE_DCMQI) # Sanity checks if(DEFINED DCMQI_DIR AND NOT EXISTS ${DCMQI_DIR}) message(FATAL_ERROR "DCMQI_DIR variable is defined but corresponds to non-existing directory") endif() set(proj DCMQI) set(proj_DEPENDENCIES DCMTK ITK) set(DCMQI_DEPENDS ${proj}) if(NOT DEFINED DCMQI_DIR) set(additional_cmake_args) if(CTEST_USE_LAUNCHERS) list(APPEND additional_cmake_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() mitk_query_custom_ep_vars() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} GIT_REPOSITORY https://github.com/QIICR/dcmqi.git - GIT_TAG 83f498e9 + GIT_TAG v1.2.4 UPDATE_COMMAND "" INSTALL_COMMAND "" CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} ${additional_cmake_args} #-DCMAKE_INSTALL_PREFIX:PATH= -DBUILD_SHARED_LIBS:BOOL=ON -DDCMQI_BUILD_APPS:BOOL=OFF -DDCMTK_DIR:PATH=${DCMTK_DIR} -DITK_DIR:PATH=${ITK_DIR} -DITK_NO_IO_FACTORY_REGISTER_MANAGER:BOOL=ON -DDCMQI_SUPERBUILD:BOOL=OFF -DDCMQI_CMAKE_CXX_STANDARD:STRING=14 ${${proj}_CUSTOM_CMAKE_ARGS} CMAKE_CACHE_ARGS ${ep_common_cache_args} ${${proj}_CUSTOM_CMAKE_CACHE_ARGS} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} ${${proj}_CUSTOM_CMAKE_CACHE_DEFAULT_ARGS} DEPENDS ${proj_DEPENDENCIES} ) ExternalProject_Get_Property(${proj} binary_dir) set(DCMQI_DIR ${binary_dir}) #set(${proj}_DIR ${ep_prefix}) #message(${proj}_DIR: ${${proj}_DIR}) #mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/DCMTK.cmake b/CMakeExternals/DCMTK.cmake index 4429abba21..2f00eea2ef 100644 --- a/CMakeExternals/DCMTK.cmake +++ b/CMakeExternals/DCMTK.cmake @@ -1,70 +1,70 @@ #----------------------------------------------------------------------------- # DCMTK #----------------------------------------------------------------------------- if(MITK_USE_DCMTK) # Sanity checks if(DEFINED DCMTK_DIR AND NOT EXISTS ${DCMTK_DIR}) message(FATAL_ERROR "DCMTK_DIR variable is defined but corresponds to non-existing directory") endif() set(proj DCMTK) set(proj_DEPENDENCIES ) set(DCMTK_DEPENDS ${proj}) if(NOT DEFINED DCMTK_DIR) if(DCMTK_DICOM_ROOT_ID) set(DCMTK_CXX_FLAGS "${DCMTK_CXX_FLAGS} -DSITE_UID_ROOT=\\\"${DCMTK_DICOM_ROOT_ID}\\\"") set(DCMTK_C_FLAGS "${DCMTK_CXX_FLAGS} -DSITE_UID_ROOT=\\\"${DCMTK_DICOM_ROOT_ID}\\\"") endif() set(additional_args ) if(CTEST_USE_LAUNCHERS) list(APPEND additional_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() mitk_query_custom_ep_vars() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/dcmtk-3.6.5.tar.gz - URL_MD5 e19707f64ee5695c496b9c1e48e39d07 + URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/dcmtk-3.6.6.tar.gz + URL_MD5 f815879d315b916366a9da71339c7575 CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} ${additional_args} "-DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} ${DCMTK_CXX_FLAGS}" "-DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS} ${DCMTK_C_FLAGS}" -DDCMTK_ENABLE_BUILTIN_DICTIONARY:BOOL=ON -DDCMTK_ENABLE_CXX11:BOOL=ON -DDCMTK_ENABLE_STL:BOOL=ON -DDCMTK_WITH_DOXYGEN:BOOL=OFF -DDCMTK_WITH_ZLIB:BOOL=OFF # see bug #9894 -DDCMTK_WITH_OPENSSL:BOOL=OFF # see bug #9894 -DDCMTK_WITH_PNG:BOOL=OFF # see bug #9894 -DDCMTK_WITH_TIFF:BOOL=OFF # see bug #9894 -DDCMTK_WITH_XML:BOOL=OFF # see bug #9894 -DDCMTK_WITH_ICONV:BOOL=OFF # see bug #9894 -DDCMTK_WITH_ICU:BOOL=OFF # see T26438 ${${proj}_CUSTOM_CMAKE_ARGS} CMAKE_CACHE_ARGS ${ep_common_cache_args} ${${proj}_CUSTOM_CMAKE_CACHE_ARGS} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} ${${proj}_CUSTOM_CMAKE_CACHE_DEFAULT_ARGS} DEPENDS ${proj_DEPENDENCIES} ) set(DCMTK_DIR ${ep_prefix}) mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/Modules/Core/include/mitkLevelWindowManager.h b/Modules/Core/include/mitkLevelWindowManager.h index b639cbc2b8..92768c692c 100644 --- a/Modules/Core/include/mitkLevelWindowManager.h +++ b/Modules/Core/include/mitkLevelWindowManager.h @@ -1,215 +1,203 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef MITKLEVELWINDOWMANAGER_H #define MITKLEVELWINDOWMANAGER_H // mitk core #include "mitkBaseProperty.h" #include "mitkDataStorage.h" #include "mitkLevelWindowProperty.h" // c++ #include #include namespace mitk { /** @brief Provides access to the LevelWindowProperty object and LevelWindow of the "current" image. - provides a LevelWindowProperty for purposes like GUI editors - this property comes from one of two possible sources - either something (e.g. the application) sets the property because of some user selection - OR the "Auto top-most" logic is used to search a DataStorage for the image with the highest "layer" property value Changes on Level/Window can be set with SetLevelWindow() and will affect either the topmost layer image, if isAutoTopMost() returns true, or an image which is set by SetLevelWindowProperty(LevelWindowProperty::Pointer levelWindowProperty). Changes to Level/Window, when another image gets active or by SetLevelWindow(const LevelWindow& levelWindow), will be sent to all listeners by Modified(). DataStorageChanged() listens to the DataStorage for new or removed images. Depending on how m_AutoTopMost is set, the new image becomes active or not. If an image is removed from the DataStorage and m_AutoTopMost is false, there is a check to proof, if the active image is still available. If not, then m_AutoTopMost becomes true. Note that this class is not thread safe at the moment! */ class MITKCORE_EXPORT LevelWindowManager : public itk::Object { public: mitkClassMacroItkParent(LevelWindowManager, itk::Object); itkFactorylessNewMacro(Self); itkCloneMacro(Self); - void SetDataStorage(DataStorage *ds); + void SetDataStorage(DataStorage* dataStorage); DataStorage *GetDataStorage(); /** * @brief (Re-)Initialize the LevelWindowManager by setting the topmost image. * Use the removedNode parameter if a node was removed. * * @param autoTopMost Set the topmost layer image to be affected by changes, if true. * @param removedNode A node was removed from the data storage if != nullptr. */ void SetAutoTopMostImage(bool autoTopMost, const DataNode *removedNode = nullptr); /** * @brief (Re-)Initialize the LevelWindowManager by setting the selected images. * Use the removedNode parameter if a node was removed. * * @param selectedImagesMode Set the selected images to be affected by changes, if true. * @param removedNode A node was removed from the data storage if != nullptr. */ void SetSelectedImages(bool selectedImagesMode, const DataNode *removedNode = nullptr); void RecalculateLevelWindowForSelectedComponent(const itk::EventObject&); /** * @brief Update the level window. * This function is called if a property of a data node is changed. * Relevant properties are defined in the protected 'ObserverToPropertyValueMap'-members. */ void Update(const itk::EventObject&); /** * @brief Update the level window. * This function is only called if the 'selected' property of a data node is changed. * This is done in order to avoid finding the correct image each time a node is selected but * the 'm_SelectedImages' bool value is set to false (as the normal 'Update'-function would do). * Changes of the 'selected' property happen quite a lot so this should not slow down the application. */ void UpdateSelected(const itk::EventObject&); /** * @brief Set a specific LevelWindowProperty; all changes will affect the image belonging to this property. * @throw mitk::Exception Throw an exception if the there is no image in the data storage which belongs to this * property. */ void SetLevelWindowProperty(LevelWindowProperty::Pointer levelWindowProperty); /** * @brief Set new Level/Window values and inform all listeners about changes. */ void SetLevelWindow(const LevelWindow &levelWindow); /** * @brief Return the current LevelWindowProperty object from the image that is affected by changes. * * @return The current LevelWindowProperty */ LevelWindowProperty::Pointer GetLevelWindowProperty(); /** * @brief Return Level/Window values for the current image * * @return The LevelWindow value for the current image. */ const LevelWindow &GetLevelWindow(); /** * @brief Return true, if the changes on slider or line-edits will affect the topmost layer image. * * @return Return the member value that denotes the auto-topmost mode. */ bool IsAutoTopMost(); /** * @brief Return true, if changes on slider or line-edits will affect the currently selected images. * * @return Return the member value that denotes the selected-images mode. */ bool IsSelectedImages(); - /** @brief This method is called when a node is added to the data storage. - * A listener on the data storage is used to call this method automatically after a node was added. - * @throw mitk::Exception Throws an exception if something is wrong, e.g. if the number of observers differs from - * the number of nodes. + /** + * @brief This method is called when a node is added to the data storage. + * A listener on the data storage is used to call this method automatically after a node was added. + * @throw mitk::Exception Throws an exception if something is wrong, e.g. if the number of observers differs from + * the number of nodes. */ - void DataStorageAddedNode(const DataNode *n = nullptr); - /** @brief This method is called when a node is removed to the data storage. - * A listener on the data storage is used to call this method automatically directly before a node will be - * removed. - * @throw mitk::Exception Throws an exception if something is wrong, e.g. if the number of observers differs from - * the number of nodes. + void DataStorageAddedNode(const DataNode *dataNode = nullptr); + /** + * @brief This method is called when a node is removed from the data storage. + * A listener on the data storage is used to call this method automatically before a node will be removed. + * @throw mitk::Exception Throws an exception if something is wrong, e.g. if the number of observers differs from + * the number of nodes. */ - void DataStorageRemovedNode(const DataNode *removedNode = nullptr); + void DataStorageRemovedNode(const DataNode *dataNode = nullptr); /** * @brief Change notifications from mitkLevelWindowProperty. */ - void OnPropertyModified(const itk::EventObject &e); + void OnPropertyModified(const itk::EventObject&); /** * @brief Return the currently active image. * * @return The member variable holding the currently active image. */ Image *GetCurrentImage(); /** - * @return Returns the current number of observers which are registered in this object. - * @throw mitk::Exception Throws an exception if the number of observers differs from - * the number of relevant objects - * which means that something is wrong. + * @brief Return the number of observers for data node's "visible" property. + * This basically returns the number of relevant nodes to observe. * + * @return The current number of observers which are registered in this object. */ int GetNumberOfObservers(); - /** - * @brief Returns all nodes in the DataStorage that have the following properties: + * @brief Return all nodes in the data storage that have the following properties: * - "binary" == false * - "levelwindow" * - DataType == Image / DiffusionImage / TensorImage / OdfImage / ShImage + * + @ return The filtered list of relevant nodes in the data storage */ DataStorage::SetOfObjects::ConstPointer GetRelevantNodes(); - protected: + private: LevelWindowManager(); ~LevelWindowManager() override; DataStorage::Pointer m_DataStorage; - /// Pointer to the LevelWindowProperty of the current image. LevelWindowProperty::Pointer m_LevelWindowProperty; typedef std::pair PropDataPair; typedef std::map ObserverToPropertyValueMap; - /// Map to hold observer IDs to every "visible" property of DataNode's BaseProperty. + ObserverToPropertyValueMap m_ObserverToVisibleProperty; - /// Map to hold observer IDs to every "layer" property of DataNode's BaseProperty. ObserverToPropertyValueMap m_ObserverToLayerProperty; - /// Map to hold observer IDs to every "Image Rendering.Mode" property of DataNode's BaseProperty. ObserverToPropertyValueMap m_ObserverToRenderingModeProperty; - /// Map to hold observer IDs to every "Image.Displayed Component" property of DataNode's BaseProperty. ObserverToPropertyValueMap m_ObserverToDisplayedComponentProperty; - /// Map to hold observer IDs to every "imageForLevelWindow" property of DataNode's BaseProperty. ObserverToPropertyValueMap m_ObserverToLevelWindowImageProperty; - /// Map to hold observer IDs to every "selected" property of DataNode's BaseProperty. ObserverToPropertyValueMap m_ObserverToSelectedProperty; - /// Updates the internal observer list. - /// Ignores nodes which are marked to be deleted in the variable m_NodeMarkedToDelete. void UpdateObservers(); - /// Internal help method to clear both lists/maps. - void ClearPropObserverLists(); - /// Internal help method to create both lists/maps. - void CreatePropObserverLists(); + void ClearPropertyObserverMaps(); + void CreatePropertyObserverMaps(); - bool IgnoreNode(const DataNode* dataNode); + bool HasLevelWindowRenderingMode(DataNode *dataNode); - /// This variable holds a data node which will be deleted from the datastorage immediately - /// Nullptr, if there is no data node to be deleted. + // This variable holds a data node which will be deleted from the datastorage immediately. const DataNode *m_NodeMarkedToDelete; bool m_AutoTopMost; bool m_SelectedImagesMode; - unsigned long m_ObserverTag; - bool m_IsObserverTagSet; unsigned long m_PropertyModifiedTag; Image *m_CurrentImage; - std::vector m_RelevantDataNodes; + std::vector m_DataNodesForLevelWindow; bool m_IsPropertyModifiedTagSet; bool m_LevelWindowMutex; }; } #endif // MITKLEVELWINDOWMANAGER_H diff --git a/Modules/Core/src/DataManagement/mitkLevelWindowManager.cpp b/Modules/Core/src/DataManagement/mitkLevelWindowManager.cpp index c0b04c6570..109716cbd2 100644 --- a/Modules/Core/src/DataManagement/mitkLevelWindowManager.cpp +++ b/Modules/Core/src/DataManagement/mitkLevelWindowManager.cpp @@ -1,737 +1,724 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkLevelWindowManager.h" #include "mitkDataStorage.h" #include "mitkImage.h" #include "mitkMessage.h" #include "mitkNodePredicateAnd.h" #include "mitkNodePredicateBase.h" #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateNot.h" #include "mitkNodePredicateOr.h" #include "mitkNodePredicateProperty.h" #include "mitkProperties.h" #include "mitkRenderingModeProperty.h" #include mitk::LevelWindowManager::LevelWindowManager() : m_DataStorage(nullptr) , m_LevelWindowProperty(nullptr) , m_AutoTopMost(true) , m_SelectedImagesMode(false) - , m_IsObserverTagSet(false) , m_CurrentImage(nullptr) , m_IsPropertyModifiedTagSet(false) , m_LevelWindowMutex(false) { } mitk::LevelWindowManager::~LevelWindowManager() { if (m_DataStorage.IsNotNull()) { m_DataStorage->AddNodeEvent.RemoveListener( MessageDelegate1(this, &LevelWindowManager::DataStorageAddedNode)); m_DataStorage->RemoveNodeEvent.RemoveListener( MessageDelegate1(this, &LevelWindowManager::DataStorageRemovedNode)); m_DataStorage = nullptr; } if (m_IsPropertyModifiedTagSet && m_LevelWindowProperty.IsNotNull()) { m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag); m_IsPropertyModifiedTagSet = false; } - // clear both observer maps - this->ClearPropObserverLists(); + this->ClearPropertyObserverMaps(); } -void mitk::LevelWindowManager::SetDataStorage(DataStorage *ds) +void mitk::LevelWindowManager::SetDataStorage(DataStorage *dataStorage) { - if (ds == nullptr) + if (nullptr == dataStorage) return; - /* remove listeners of old DataStorage */ + // remove listeners of old DataStorage if (m_DataStorage.IsNotNull()) { m_DataStorage->AddNodeEvent.RemoveListener( MessageDelegate1(this, &LevelWindowManager::DataStorageAddedNode)); m_DataStorage->RemoveNodeEvent.RemoveListener( MessageDelegate1(this, &LevelWindowManager::DataStorageRemovedNode)); } - /* register listener for new DataStorage */ - m_DataStorage = ds; // register + // register listener for new DataStorage + m_DataStorage = dataStorage; m_DataStorage->AddNodeEvent.AddListener( MessageDelegate1(this, &LevelWindowManager::DataStorageAddedNode)); m_DataStorage->RemoveNodeEvent.AddListener( MessageDelegate1(this, &LevelWindowManager::DataStorageRemovedNode)); - this->DataStorageAddedNode(); // update us with new DataStorage + this->DataStorageAddedNode(); } mitk::DataStorage *mitk::LevelWindowManager::GetDataStorage() { return m_DataStorage.GetPointer(); } void mitk::LevelWindowManager::SetAutoTopMostImage(bool autoTopMost, const DataNode *removedNode/* = nullptr*/) { m_AutoTopMost = autoTopMost; if (false == m_AutoTopMost) { return; } // deactivate other mode m_SelectedImagesMode = false; if (m_IsPropertyModifiedTagSet && m_LevelWindowProperty.IsNotNull()) { m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag); m_IsPropertyModifiedTagSet = false; } // find topmost image in the data storage if (m_DataStorage.IsNull()) { mitkThrow() << "DataStorage not set"; } DataNode::Pointer topLevelNode; int maxVisibleLayer = itk::NumericTraits::min(); m_LevelWindowProperty = nullptr; m_CurrentImage = nullptr; DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes(); for (DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) { DataNode::Pointer node = it->Value(); if (node.IsNull() || node == removedNode) { continue; } + // reset the "imageForLevelWindow" of each node m_LevelWindowMutex = true; node->SetBoolProperty("imageForLevelWindow", false); m_LevelWindowMutex = false; if (false == node->IsVisible(nullptr)) { continue; } - int layer = -1; - node->GetIntProperty("layer", layer); - if (layer < maxVisibleLayer) + bool validRenderingMode = HasLevelWindowRenderingMode(node); + if (false == validRenderingMode) { continue; } - bool ignore = this->IgnoreNode(node); - if (ignore) + int layer = -1; + node->GetIntProperty("layer", layer); + if (layer < maxVisibleLayer) { continue; } m_LevelWindowProperty = dynamic_cast(node->GetProperty("levelwindow")); topLevelNode = node; maxVisibleLayer = layer; } // this will set the "imageForLevelWindow" property and the 'm_CurrentImage' and call 'Modified()' this->SetLevelWindowProperty(m_LevelWindowProperty); if (m_LevelWindowProperty.IsNull()) { this->Modified(); } } void mitk::LevelWindowManager::SetSelectedImages(bool selectedImagesMode, const DataNode *removedNode/* = nullptr*/) { m_SelectedImagesMode = selectedImagesMode; if (false == m_SelectedImagesMode) { return; } // deactivate other mode m_AutoTopMost = false; if (m_IsPropertyModifiedTagSet && m_LevelWindowProperty.IsNotNull()) { m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag); m_IsPropertyModifiedTagSet = false; } // find selected images in the data storage if (m_DataStorage.IsNull()) { mitkThrow() << "DataStorage not set"; } DataNode::Pointer lastSelectedNode; m_LevelWindowProperty = nullptr; m_CurrentImage = nullptr; DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes(); for (DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) { DataNode::Pointer node = it->Value(); if (node.IsNull() || node == removedNode) { continue; } + // reset the "imageForLevelWindow" of each node m_LevelWindowMutex = true; node->SetBoolProperty("imageForLevelWindow", false); m_LevelWindowMutex = false; if (false == node->IsSelected()) { continue; } - bool ignore = this->IgnoreNode(node); - if (ignore) + + bool validRenderingMode = HasLevelWindowRenderingMode(node); + if (false == validRenderingMode) { continue; } m_LevelWindowProperty = dynamic_cast(node->GetProperty("levelwindow")); - m_RelevantDataNodes.push_back(node); + m_DataNodesForLevelWindow.push_back(node); lastSelectedNode = node; } // this will set the "imageForLevelWindow" property and the 'm_CurrentImage' and call 'Modified()' this->SetLevelWindowProperty(m_LevelWindowProperty); if (m_LevelWindowProperty.IsNull()) { this->Modified(); } } void mitk::LevelWindowManager::RecalculateLevelWindowForSelectedComponent(const itk::EventObject &event) { DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes(); for (DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) { DataNode::Pointer node = it->Value(); if (node.IsNull()) continue; bool isSelected = false; node->GetBoolProperty("selected", isSelected); if (isSelected) { LevelWindow selectedLevelWindow; node->GetLevelWindow(selectedLevelWindow); // node is an image node because of predicates auto *image = dynamic_cast(node->GetData()); int displayedComponent = 0; if (image && (node->GetIntProperty("Image.Displayed Component", displayedComponent))) { // we found a selected image with a displayed component // let's recalculate the levelwindow for this. selectedLevelWindow.SetAuto(image, true, true, static_cast(displayedComponent)); node->SetLevelWindow(selectedLevelWindow); } } LevelWindow levelWindow; node->GetLevelWindow(levelWindow); } this->Update(event); } void mitk::LevelWindowManager::Update(const itk::EventObject &) { if (m_LevelWindowMutex) // no mutex, should still help { return; } - m_RelevantDataNodes.clear(); + m_DataNodesForLevelWindow.clear(); if (m_AutoTopMost) { this->SetAutoTopMostImage(true); return; } if (m_SelectedImagesMode) { this->SetSelectedImages(true); return; } int maxVisibleLayer = itk::NumericTraits::min(); DataNode::Pointer topLevelNode = nullptr; std::vector nodesForLevelWindow; DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes(); for (DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) { DataNode::Pointer node = it->Value(); - if (node.IsNull()) { continue; } - if (node->IsVisible(nullptr) == false) + if (false == node->IsVisible(nullptr)) + { + continue; + } + + bool validRenderingMode = HasLevelWindowRenderingMode(node); + if (false == validRenderingMode) { continue; } bool prop = false; node->GetBoolProperty("imageForLevelWindow", prop); if (prop) { nodesForLevelWindow.push_back(node); continue; } int layer = -1; node->GetIntProperty("layer", layer); if (layer > maxVisibleLayer) { // top level node is backup node, if no node with // "imageForLevelWindow" property with value "true" is found topLevelNode = node; maxVisibleLayer = layer; } } int nodesForLevelWindowSize = nodesForLevelWindow.size(); if (nodesForLevelWindowSize > 2) { MITK_ERROR << "Error: not more than two visible nodes are expected to have the imageForLevelWindow property set at " "any point."; } if (nodesForLevelWindowSize > 0) { // 1 or 2 nodes for level window found for (const auto& node : nodesForLevelWindow) { LevelWindowProperty::Pointer newProp = dynamic_cast(node->GetProperty("levelwindow")); if (newProp != m_LevelWindowProperty) { this->SetLevelWindowProperty(newProp); return; } } } else if (topLevelNode) { // no nodes for level window found LevelWindowProperty::Pointer lvlProp = dynamic_cast(topLevelNode->GetProperty("levelwindow")); this->SetLevelWindowProperty(lvlProp); } else { // no nodes for level window found and no visible top level node found this->Modified(); } } void mitk::LevelWindowManager::UpdateSelected(const itk::EventObject &) { if (m_LevelWindowMutex) // no mutex, should still help { return; } - m_RelevantDataNodes.clear(); + m_DataNodesForLevelWindow.clear(); if (m_SelectedImagesMode) { this->SetSelectedImages(true); } } void mitk::LevelWindowManager::SetLevelWindowProperty(LevelWindowProperty::Pointer levelWindowProperty) { if (levelWindowProperty.IsNull()) { return; } // find data node that belongs to the property DataStorage::SetOfObjects::ConstPointer all = m_DataStorage->GetAll(); mitk::DataNode::Pointer propNode = nullptr; for (DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) { DataNode::Pointer node = it.Value(); LevelWindowProperty::Pointer property = dynamic_cast(node->GetProperty("levelwindow")); if (property == levelWindowProperty) { propNode = node; } else { m_LevelWindowMutex = true; node->SetBoolProperty("imageForLevelWindow", false); m_LevelWindowMutex = false; } } if (propNode.IsNull()) { mitkThrow() << "No Image in the data storage that belongs to level-window property " << m_LevelWindowProperty; } if (m_IsPropertyModifiedTagSet) // remove listener for old property { m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag); m_IsPropertyModifiedTagSet = false; } m_LevelWindowProperty = levelWindowProperty; - itk::ReceptorMemberCommand::Pointer command = - itk::ReceptorMemberCommand::New(); // register listener for new property + auto command = itk::ReceptorMemberCommand::New(); // register listener for new property command->SetCallbackFunction(this, &LevelWindowManager::OnPropertyModified); m_PropertyModifiedTag = m_LevelWindowProperty->AddObserver(itk::ModifiedEvent(), command); m_IsPropertyModifiedTagSet = true; m_CurrentImage = dynamic_cast(propNode->GetData()); m_LevelWindowMutex = true; propNode->SetBoolProperty("imageForLevelWindow", true); m_LevelWindowMutex = false; this->Modified(); } void mitk::LevelWindowManager::SetLevelWindow(const LevelWindow &levelWindow) { - if (m_LevelWindowProperty.IsNotNull()) + if (m_LevelWindowProperty.IsNull()) { - m_LevelWindowProperty->SetLevelWindow(levelWindow); - for (const auto &dataNode : m_RelevantDataNodes) - { - auto levelWindowProperty = dynamic_cast(dataNode->GetProperty("levelwindow")); - if (nullptr == levelWindowProperty) - { - continue; - } + return; + } - levelWindowProperty->SetLevelWindow(levelWindow); + m_LevelWindowProperty->SetLevelWindow(levelWindow); + for (const auto &dataNode : m_DataNodesForLevelWindow) + { + auto levelWindowProperty = dynamic_cast(dataNode->GetProperty("levelwindow")); + if (nullptr == levelWindowProperty) + { + continue; } + + levelWindowProperty->SetLevelWindow(levelWindow); } + this->Modified(); } mitk::LevelWindowProperty::Pointer mitk::LevelWindowManager::GetLevelWindowProperty() { return m_LevelWindowProperty; } const mitk::LevelWindow &mitk::LevelWindowManager::GetLevelWindow() { if (m_LevelWindowProperty.IsNotNull()) { return m_LevelWindowProperty->GetLevelWindow(); } else { mitkThrow() << "No LevelWindow available!"; } } bool mitk::LevelWindowManager::IsAutoTopMost() { return m_AutoTopMost; } bool mitk::LevelWindowManager::IsSelectedImages() { return m_SelectedImagesMode; } void mitk::LevelWindowManager::DataStorageAddedNode(const DataNode *) { // update observers with new data storage this->UpdateObservers(); - // Initialize LevelWindowsManager to new image + // initialize LevelWindowManager to new image this->SetAutoTopMostImage(true); // check if everything is still ok if ((m_ObserverToVisibleProperty.size() != m_ObserverToLayerProperty.size()) || (m_ObserverToLayerProperty.size() != this->GetRelevantNodes()->size())) { mitkThrow() << "Wrong number of observers in Level Window Manager!"; } } void mitk::LevelWindowManager::DataStorageRemovedNode(const DataNode *removedNode) { // First: check if deleted node is part of relevant nodes. // If not, abort method because there is no need change anything. bool removedNodeIsRelevant = false; DataStorage::SetOfObjects::ConstPointer relevantNodes = GetRelevantNodes(); for (DataStorage::SetOfObjects::ConstIterator it = relevantNodes->Begin(); it != relevantNodes->End(); ++it) { if (it->Value() == removedNode) { removedNodeIsRelevant = true; } } if (false == removedNodeIsRelevant) { return; } // remember node which will be removed m_NodeMarkedToDelete = removedNode; // update observers this->UpdateObservers(); // search image that belongs to the property if (m_LevelWindowProperty.IsNull()) { this->SetAutoTopMostImage(true, removedNode); } else { - NodePredicateProperty::Pointer property = NodePredicateProperty::New("levelwindow", m_LevelWindowProperty); + auto property = NodePredicateProperty::New("levelwindow", m_LevelWindowProperty); DataNode *n = m_DataStorage->GetNode(property); if (n == nullptr || m_AutoTopMost) // if node was deleted, change our behavior to AutoTopMost, if AutoTopMost is // true change level window to topmost node { this->SetAutoTopMostImage(true, removedNode); } } // reset variable m_NodeMarkedToDelete = nullptr; // check if everything is still ok if ((m_ObserverToVisibleProperty.size() != m_ObserverToLayerProperty.size()) || (m_ObserverToLayerProperty.size() != (relevantNodes->size() - 1))) { mitkThrow() << "Wrong number of observers in Level Window Manager!"; } } void mitk::LevelWindowManager::OnPropertyModified(const itk::EventObject &) { this->Modified(); } mitk::Image *mitk::LevelWindowManager::GetCurrentImage() { return m_CurrentImage; } int mitk::LevelWindowManager::GetNumberOfObservers() { return m_ObserverToVisibleProperty.size(); } mitk::DataStorage::SetOfObjects::ConstPointer mitk::LevelWindowManager::GetRelevantNodes() { if (m_DataStorage.IsNull()) { return DataStorage::SetOfObjects::ConstPointer(DataStorage::SetOfObjects::New()); } - NodePredicateProperty::Pointer notBinary = NodePredicateProperty::New("binary", BoolProperty::New(false)); - NodePredicateProperty::Pointer hasLevelWindow = NodePredicateProperty::New("levelwindow", nullptr); + auto notBinary = NodePredicateProperty::New("binary", BoolProperty::New(false)); + auto hasLevelWindow = NodePredicateProperty::New("levelwindow", nullptr); - NodePredicateDataType::Pointer isImage = NodePredicateDataType::New("Image"); - NodePredicateDataType::Pointer isDImage = NodePredicateDataType::New("DiffusionImage"); - NodePredicateDataType::Pointer isTImage = NodePredicateDataType::New("TensorImage"); - NodePredicateDataType::Pointer isOdfImage = NodePredicateDataType::New("OdfImage"); - NodePredicateDataType::Pointer isShImage = NodePredicateDataType::New("ShImage"); - NodePredicateOr::Pointer predicateTypes = NodePredicateOr::New(); + auto isImage = NodePredicateDataType::New("Image"); + auto isDImage = NodePredicateDataType::New("DiffusionImage"); + auto isTImage = NodePredicateDataType::New("TensorImage"); + auto isOdfImage = NodePredicateDataType::New("OdfImage"); + auto isShImage = NodePredicateDataType::New("ShImage"); + auto predicateTypes = NodePredicateOr::New(); predicateTypes->AddPredicate(isImage); predicateTypes->AddPredicate(isDImage); predicateTypes->AddPredicate(isTImage); predicateTypes->AddPredicate(isOdfImage); predicateTypes->AddPredicate(isShImage); NodePredicateAnd::Pointer predicate = NodePredicateAnd::New(); predicate->AddPredicate(notBinary); predicate->AddPredicate(hasLevelWindow); predicate->AddPredicate(predicateTypes); DataStorage::SetOfObjects::ConstPointer relevantNodes = m_DataStorage->GetSubset(predicate); return relevantNodes; } void mitk::LevelWindowManager::UpdateObservers() { - this->ClearPropObserverLists(); // remove old observers - this->CreatePropObserverLists(); // create new observer lists + this->ClearPropertyObserverMaps(); + this->CreatePropertyObserverMaps(); } -void mitk::LevelWindowManager::ClearPropObserverLists() +void mitk::LevelWindowManager::ClearPropertyObserverMaps() { for (auto iter = m_ObserverToVisibleProperty.begin(); iter != m_ObserverToVisibleProperty.end(); ++iter) { (*iter).second->RemoveObserver((*iter).first.first); (*iter).second = nullptr; } m_ObserverToVisibleProperty.clear(); for (auto iter = m_ObserverToLayerProperty.begin(); iter != m_ObserverToLayerProperty.end(); ++iter) { (*iter).second->RemoveObserver((*iter).first.first); (*iter).second = nullptr; } m_ObserverToLayerProperty.clear(); for (auto iter = m_ObserverToRenderingModeProperty.begin(); iter != m_ObserverToRenderingModeProperty.end(); ++iter) { (*iter).second->RemoveObserver((*iter).first.first); (*iter).second = nullptr; } m_ObserverToRenderingModeProperty.clear(); for (auto iter = m_ObserverToDisplayedComponentProperty.begin(); iter != m_ObserverToDisplayedComponentProperty.end(); ++iter) { (*iter).second->RemoveObserver((*iter).first.first); (*iter).second = nullptr; } m_ObserverToDisplayedComponentProperty.clear(); for (auto iter = m_ObserverToLevelWindowImageProperty.begin(); iter != m_ObserverToLevelWindowImageProperty.end(); ++iter) { (*iter).second->RemoveObserver((*iter).first.first); (*iter).second = nullptr; } m_ObserverToLevelWindowImageProperty.clear(); for (auto iter = m_ObserverToSelectedProperty.begin(); iter != m_ObserverToSelectedProperty.end(); ++iter) { (*iter).second->RemoveObserver((*iter).first.first); (*iter).second = nullptr; } m_ObserverToSelectedProperty.clear(); } -void mitk::LevelWindowManager::CreatePropObserverLists() +void mitk::LevelWindowManager::CreatePropertyObserverMaps() { - if (m_DataStorage.IsNull()) // check if data storage is set + if (m_DataStorage.IsNull()) { mitkThrow() << "DataStorage not set"; } - /* add observers for all relevant nodes */ + // add observers for all relevant nodes DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes(); for (DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) { - if ((it->Value().IsNull()) || (it->Value() == m_NodeMarkedToDelete)) + DataNode::Pointer node = it->Value(); + if (node.IsNull() || node == m_NodeMarkedToDelete) { continue; } - /* register listener for changes in visible property */ - itk::ReceptorMemberCommand::Pointer command = - itk::ReceptorMemberCommand::New(); + auto command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction(this, &LevelWindowManager::Update); - unsigned long visIdx = it->Value()->GetProperty("visible")->AddObserver(itk::ModifiedEvent(), command); - m_ObserverToVisibleProperty[PropDataPair(visIdx, it->Value())] = it->Value()->GetProperty("visible"); + unsigned long visIdx = node->GetProperty("visible")->AddObserver(itk::ModifiedEvent(), command); + m_ObserverToVisibleProperty[PropDataPair(visIdx, node)] = node->GetProperty("visible"); - /* register listener for changes in layer property */ - itk::ReceptorMemberCommand::Pointer command2 = - itk::ReceptorMemberCommand::New(); + auto command2 = itk::ReceptorMemberCommand::New(); command2->SetCallbackFunction(this, &LevelWindowManager::Update); - unsigned long layerIdx = it->Value()->GetProperty("layer")->AddObserver(itk::ModifiedEvent(), command2); - m_ObserverToLayerProperty[PropDataPair(layerIdx, it->Value())] = it->Value()->GetProperty("layer"); + unsigned long layerIdx = node->GetProperty("layer")->AddObserver(itk::ModifiedEvent(), command2); + m_ObserverToLayerProperty[PropDataPair(layerIdx, node)] = node->GetProperty("layer"); - /* register listener for changes in layer property */ - itk::ReceptorMemberCommand::Pointer command3 = - itk::ReceptorMemberCommand::New(); + auto command3 = itk::ReceptorMemberCommand::New(); command3->SetCallbackFunction(this, &LevelWindowManager::Update); - BaseProperty::Pointer imageRenderingMode = it->Value()->GetProperty("Image Rendering.Mode"); + BaseProperty::Pointer imageRenderingMode = node->GetProperty("Image Rendering.Mode"); if (imageRenderingMode.IsNotNull()) { unsigned long rendIdx = imageRenderingMode->AddObserver(itk::ModifiedEvent(), command3); - m_ObserverToRenderingModeProperty[PropDataPair(rendIdx, it->Value())] = imageRenderingMode.GetPointer(); + m_ObserverToRenderingModeProperty[PropDataPair(rendIdx, node)] = imageRenderingMode.GetPointer(); } - itk::ReceptorMemberCommand::Pointer command4 = - itk::ReceptorMemberCommand::New(); + auto command4 = itk::ReceptorMemberCommand::New(); command4->SetCallbackFunction(this, &LevelWindowManager::RecalculateLevelWindowForSelectedComponent); - BaseProperty::Pointer displayedImageComponent = it->Value()->GetProperty("Image.Displayed Component"); + BaseProperty::Pointer displayedImageComponent = node->GetProperty("Image.Displayed Component"); if (displayedImageComponent.IsNotNull()) { unsigned long dispIdx = displayedImageComponent->AddObserver(itk::ModifiedEvent(), command4); - m_ObserverToDisplayedComponentProperty[PropDataPair(dispIdx, it->Value())] = displayedImageComponent.GetPointer(); + m_ObserverToDisplayedComponentProperty[PropDataPair(dispIdx, node)] = displayedImageComponent.GetPointer(); } - itk::ReceptorMemberCommand::Pointer command5 = - itk::ReceptorMemberCommand::New(); + auto command5 = itk::ReceptorMemberCommand::New(); command5->SetCallbackFunction(this, &LevelWindowManager::Update); - BaseProperty::Pointer imgForLvlWin = it->Value()->GetProperty("imageForLevelWindow"); + BaseProperty::Pointer imgForLvlWin = node->GetProperty("imageForLevelWindow"); if (imgForLvlWin.IsNull()) { - it->Value()->SetBoolProperty("imageForLevelWindow", false); - imgForLvlWin = it->Value()->GetProperty("imageForLevelWindow"); + node->SetBoolProperty("imageForLevelWindow", false); + imgForLvlWin = node->GetProperty("imageForLevelWindow"); } unsigned long lvlWinIdx = imgForLvlWin->AddObserver(itk::ModifiedEvent(), command5); - m_ObserverToLevelWindowImageProperty[PropDataPair(lvlWinIdx, it->Value())] = it->Value()->GetProperty("imageForLevelWindow"); + m_ObserverToLevelWindowImageProperty[PropDataPair(lvlWinIdx, node)] = node->GetProperty("imageForLevelWindow"); - itk::ReceptorMemberCommand::Pointer command6 = - itk::ReceptorMemberCommand::New(); + auto command6 = itk::ReceptorMemberCommand::New(); command6->SetCallbackFunction(this, &LevelWindowManager::UpdateSelected); - BaseProperty::Pointer selectedDataNode = it->Value()->GetProperty("selected"); + BaseProperty::Pointer selectedDataNode = node->GetProperty("selected"); if (selectedDataNode.IsNull()) { - it->Value()->SetBoolProperty("selected", false); - selectedDataNode = it->Value()->GetProperty("selected"); + node->SetBoolProperty("selected", false); + selectedDataNode = node->GetProperty("selected"); } unsigned long selectedIdx = selectedDataNode->AddObserver(itk::ModifiedEvent(), command5); - m_ObserverToSelectedProperty[PropDataPair(selectedIdx, it->Value())] = it->Value()->GetProperty("selected"); + m_ObserverToSelectedProperty[PropDataPair(selectedIdx, node)] = node->GetProperty("selected"); } } -bool mitk::LevelWindowManager::IgnoreNode(const DataNode* dataNode) +bool mitk::LevelWindowManager::HasLevelWindowRenderingMode(DataNode *dataNode) { - LevelWindowProperty::Pointer levelWindowProperty = - dynamic_cast(dataNode->GetProperty("levelwindow")); - if (levelWindowProperty.IsNull()) - { - return true; - } - - int nonLvlWinMode1 = RenderingModeProperty::LOOKUPTABLE_COLOR; - int nonLvlWinMode2 = RenderingModeProperty::COLORTRANSFERFUNCTION_COLOR; - RenderingModeProperty::Pointer mode = dynamic_cast(dataNode->GetProperty("Image Rendering.Mode")); if (mode.IsNotNull()) { int currMode = mode->GetRenderingMode(); - if (currMode == nonLvlWinMode1 || currMode == nonLvlWinMode2) + if (currMode == RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR || + currMode == RenderingModeProperty::COLORTRANSFERFUNCTION_LEVELWINDOW_COLOR) { return true; } } - else - { - return true; - } return false; }